29 Commits
Author SHA1 Message Date
pali 7bee6aa9c4 Prevent unbreakable blocks from being moved by ProjectRed motors (#14) 2026-11-07 21:34:18 +00:00
Dream Master 21da7aae0e update+gradle+bs+deps 2026-08-04 11:28:29 +07:00
boubou19andAlgent eacf6f7dd7 Remove render allocations (#13)
Co-authored-by: Algent <algent@gmail.com>
2026-08-03 21:18:20 +02:00
Alexdoru cd90218a37 [Memory-opti:fix leak] fix light matrix world leak (#12) 2026-04-28 17:54:22 -04:00
Martin Robertz 93b3283d8b Merge remote-tracking branch 'origin/master' 2026-04-27 13:42:10 +02:00
Martin Robertz 51cc5d1cd1 update+gradle+deps+bs 2026-04-27 13:41:41 +02:00
UltraProdigy 614b2d4e3e Optimize Images & Workflow (#11) 2026-04-26 08:38:56 +02:00
Dream Master aebd3ebf8c fix 2025-08-16 19:38:01 +07:00
Dream Master ccb66ee3b1 update 2025-08-13 15:29:39 +07:00
Alexdoru d37209b9e1 Delete legacy dep file + properly register IFMLLoadingPlugin (#10) 2025-08-11 17:05:15 +02:00
Maya 972ccacc69 update 2025-06-03 13:00:41 -06:00
AlexdoruandMaya e58530f587 Fix WorldClient memory leak (#9)
Co-authored-by: Maya <10861407+serenibyss@users.noreply.github.com>
2025-06-03 19:00:30 +00:00
Martin Robertz c75c509fda update 2025-06-03 18:20:45 +02:00
Alexdoru b2c051b597 use one local variable for the Tesselator, so it can be transformed properly (#8) 2025-06-03 13:19:41 +02:00
Martin Robertz 5b34a69e2b update 2025-01-03 23:29:50 +01:00
Martin Robertz 582ed32314 update cc Render State 2025-01-03 23:29:30 +01:00
Martin Robertz f1324c86be update 2024-12-31 14:23:07 +01:00
glowredman 77d2debe5d Add Localizations (#7) 2024-12-30 18:18:59 -06:00
Martin Robertz cca754773a update 2024-06-28 21:59:47 +02:00
Jason Mitchell ebc1762cb6 Try a thread safe client map, and guard against a null world (#6) 2024-02-19 20:36:33 -08:00
glowredman 6820516d89 Update Version Replacement (#5)
* Update version replacement

* Use CCRenderState instance

* Comment out MCFrames|API again
2024-02-13 22:06:41 +01:00
Raven Szewczyk 3529de5863 [ci skip] upgraded build system 2024-02-04 19:58:37 +00:00
bombcar 58973e61f7 [bs] spotless apply for jenkins
[bs] spotless apply for jenkins
2024-01-09 15:48:52 -06:00
bombcar 35ca8210c0 spotless apply for jenkins 2024-01-09 05:49:18 -06:00
Raven Szewczyk b13c6544b6 [ci skip] upgraded build system 2024-01-08 21:25:52 +00:00
Raven Szewczyk 9be7a99f25 [ci skip] upgraded build system 2023-01-31 09:52:55 +00:00
Jason Mitchell cffa422164 [ci skip] Add git-blame-ignore-revs for spotlessApply 2023-01-29 11:53:43 -08:00
Jason Mitchell 79ea033e26 [ci skip] spotlessApply with the new settings 2023-01-29 11:53:43 -08:00
Jason Mitchell da006885b4 [ci skip] Update buildscript to RetroFuturaGradle 2023-01-29 11:52:53 -08:00
57 changed files with 2770 additions and 3362 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
# Ignore spotlessApply reformat
79ea033e261260e200647154a04f97c5e638b07a
+17
View File
@@ -0,0 +1,17 @@
name: Optimize images
on:
pull_request:
branches: [ master, main, release/** ]
paths:
- "**/*.png"
push:
branches: [ master, main, release/** ]
paths:
- "**/*.png"
jobs:
optimize-images:
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/optimize-images.yml@master
secrets: inherit
+1
View File
@@ -30,3 +30,4 @@ src/main/resources/mixins.*.json
*.bat
*.DS_Store
!gradlew.bat
layout.json
-6
View File
@@ -1,6 +0,0 @@
jar {
manifest {
attributes 'FMLCorePlugin': 'mrtjp.relocation.asm.RelocationPlugin'
attributes 'FMLCorePluginContainsFMLMod': true
}
}
Executable → Regular
+2 -1113
View File
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -1,3 +1,4 @@
dependencies {
compile 'com.github.GTNewHorizons:MrTJPCore:1.1.1:dev'
api('com.github.GTNewHorizons:CodeChickenCore:1.4.17:dev')
api 'com.github.GTNewHorizons:MrTJPCore:1.3.7:dev'
}
+162 -40
View File
@@ -1,65 +1,135 @@
# ExampleMod tag to use as Blowdryer (Spotless, etc.) settings version, leave empty to disable.
# LOCAL to test local config updates.
gtnh.settings.blowdryerTag = 0.2.0
# Human-readable mod name, available for mcmod.info population.
modName = ForgeRelocation
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
# Case-sensitive identifier string, available for mcmod.info population and used for automatic mixin JSON generation.
# Conventionally lowercase.
modId = ForgeRelocation
# Root package of the mod, used to find various classes in other properties,
# mcmod.info substitution, enabling assertions in run tasks, etc.
modGroup = mrtjp.relocation
# WHY is there no version field?
# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the
# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/
# Whether to use modGroup as the maven publishing group.
# When false, com.github.GTNewHorizons is used.
useModGroupForPublishing = false
# Will update your build.gradle automatically whenever an update is available
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
autoUpdateBuildScript = false
# Version of Minecraft to target
minecraftVersion = 1.7.10
# Version of Minecraft Forge to target
forgeVersion = 10.13.4.1614
# Specify a MCP channel and mappings version for dependency deobfuscation and the deobfParams task.
# Specify an MCP channel for dependency deobfuscation and the deobfParams task.
channel = stable
# Specify an MCP mappings version for dependency deobfuscation and the deobfParams task.
mappingsVersion = 12
# Define other MCP mappings for dependency deobfuscation
remoteMappings = https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
# Defines other MCP mappings for dependency deobfuscation.
remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
# restart Minecraft in development. Choose this dependent on your mod:
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
# Select a default username for testing your mod. You can always override this per-run by running
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
developmentEnvironmentUserName = Developer
# Define a source file of your project with:
# Enables modern Java syntax support. Valid values:
# - false: No modern syntax, Java 8 only
# - jabel: Jabel syntax-only support, compiles to J8 bytecode
# - jvmDowngrader: Full modern Java via JVM Downgrader (syntax + stdlib APIs)
# - modern: Native modern Java bytecode, no downgrading
enableModernJavaSyntax = false
# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues,
# and should *not* be used in most situations. -1 disables this.
# forceToolchainVersion = -1
# Target JVM version for JVM Downgrader bytecode downgrading.
# Only used when enableModernJavaSyntax = jvmDowngrader
# downgradeTargetVersion = 8
# Comma-separated list of Java versions for multi-release jar support (JVM Downgrader only).
# Classes will be available in META-INF/versions/N/ for each version N in this list.
# Default: "21,25" (J25+ gets native classes, J21-24 gets partial downgrade, J8-20 gets full downgrade).
# jvmDowngraderMultiReleaseVersions = 21,25
# Specifies how JVM Downgrader API stubs are provided. Options:
# - shade: Shade minimized stubs into the jar
# - gtnhlib: GTNHLib provides stubs at runtime (adds version constraint)
# - external: Another dependency provides stubs (no constraint, no warning)
# - (empty): Warning reminding you to configure stubs
# Note: 'shade' option requires you to verify license compliance, see: https://github.com/unimined/JvmDowngrader/blob/main/LICENSE.md
# jvmDowngraderStubsProvider =
# Enables injecting missing generics into the decompiled source code for a better coding experience.
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
enableGenericInjection = false
# Generate a class with a String field for the mod version named as defined below.
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
# If gradleTokenVersion is empty or missing, the field will not be present in the class.
generateGradleTokenClass = mrtjp.relocation.Tags
# Name of the token containing the project's current version to generate/replace.
gradleTokenVersion = VERSION
# [DEPRECATED] Mod ID replacement token.
gradleTokenModId =
# [DEPRECATED] Mod name replacement token.
gradleTokenModName =
# [DEPRECATED] Mod Group replacement token.
gradleTokenGroupName =
# [DEPRECATED]
# Multiple source files can be defined here by providing a comma-separated list: Class1.java,Class2.java,Class3.java
# public static final String VERSION = "GRADLETOKEN_VERSION";
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
# version in @Mod([...], version = VERSION, [...])
# Leave these properties empty to skip individual token replacements
replaceGradleTokenInFile = mod.scala,package-info.java
gradleTokenModId =
gradleTokenModName =
gradleTokenVersion = GRADLETOKEN_VERSION
gradleTokenGroupName =
# version in @Mod([...], version = VERSION, [...]).
# Leave these properties empty to skip individual token replacements.
replaceGradleTokenInFile =
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
# leave this property empty.
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
# Example value: (apiPackage = api) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.api
apiPackage =
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/
# Example value: mymodid_at.cfg
# There can be multiple files in a space-separated list.
# Example value: mymodid_at.cfg nei_at.cfg
accessTransformersFile =
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
usesMixins = false
# Adds some debug arguments like verbose output and export
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
# Mixin classes will have access to "main" classes, but not the other way around.
separateMixinSourceSet =
# Adds some debug arguments like verbose output and class export.
usesMixinDebug = false
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
mixinPlugin =
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
# Specify the package that contains all of your Mixins. The package must exist or
# the build will fail. If you have a package property defined in your mixins.<modid>.json,
# it must match with this or the build will fail.
mixinsPackage =
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
# This parameter is for legacy compatibility only
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
coreModClass =
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
coreModClass = asm.RelocationPlugin
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
containsMixinsAndOrCoreModOnly = false
@@ -67,15 +137,38 @@ containsMixinsAndOrCoreModOnly = false
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
forceEnableMixins = false
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your
# responsibility check the licence and request permission for distribution, if required.
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated into your jar. It is your
# responsibility to check the license and request permission for distribution if required.
usesShadowedDependencies = false
# If disabled, won't remove unused classes from shadowed dependencies. Some libraries use reflection to access
# their own classes, making the minimization unreliable.
minimizeShadowedDependencies = true
# Publishing to modrinth requires you to set the MODRINTH_TOKEN environment variable to your current modrinth API token.
# If disabled, won't rename the shadowed classes.
relocateShadowedDependencies = true
# Adds CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
includeWellKnownRepositories = true
# A list of repositories to exclude from the includeWellKnownRepositories setting. Should be a space separated
# list of strings, with the acceptable keys being(case does not matter):
# cursemaven
# modrinth
excludeWellKnownRepositories =
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
# Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables.
# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle.
usesMavenPublishing = true
# Maven repository to publish the mod to.
# mavenPublishUrl = https\://nexus.gtnewhorizons.com/repository/releases/
# Publishing to Modrinth requires you to set the MODRINTH_TOKEN environment variable to your current Modrinth API token.
#
# The project's ID on Modrinth. Can be either the slug or the ID.
# Leave this empty if you don't want to publish on Modrinth.
# Leave this empty if you don't want to publish to Modrinth.
modrinthProjectId =
# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth.
@@ -84,12 +177,11 @@ modrinthProjectId =
# type can be one of [project, version],
# and the name is the Modrinth project or version slug/id of the other mod.
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
modrinthRelations =
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
#
# The project's numeric ID on CurseForge. You can find this in the About Project box.
# Leave this empty if you don't want to publish on CurseForge.
curseForgeProjectId =
@@ -99,18 +191,48 @@ curseForgeProjectId =
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
# and the name is the CurseForge project slug of the other mod.
# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
curseForgeRelations =
# Optional parameter to customize the produced artifacts. Use this to preserver artifact naming when migrating older
# Optional parameter to customize the produced artifacts. Use this to preserve artifact naming when migrating older
# projects. New projects should not use this parameter.
# customArchiveBaseName =
# Optional parameter to prevent the source code from being published
# noPublishedSources =
# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory.
# runClientWorkingDirectory = run/client
# Uncomment this to disable spotless checks
# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory.
# runServerWorkingDirectory = run/server
# Optional parameter to have the build automatically fail if an illegal version is used.
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
# The check is ONLY performed if the version is a git tag.
# Note: the specified string must be escaped, so e.g. 1\\.1\\.\\d+ instead of 1\.1\.\d+
# versionPattern =
# Uncomment to prevent the source code from being published.
# noPublishedSources = true
# Uncomment this to disable Spotless checks.
# This should only be uncommented to keep it easier to sync with upstream/other forks.
# That is, if there is no other active fork/upstream, NEVER change this.
# disableSpotless = true
# disableSpotless = true
# Uncomment this to disable Checkstyle checks (currently wildcard import check).
# disableCheckstyle = true
# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
# (force use delegated build).
# This is meant to be set in $HOME/.gradle/gradle.properties.
# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be native build.
# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want!
# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you.
# ideaOverrideBuildType = idea
# Whether IDEA should run spotless checks when pressing the Build button.
# This is meant to be set in $HOME/.gradle/gradle.properties.
# ideaCheckSpotlessOnBuild = true
# Non-GTNH properties
org.gradle.configuration-cache = true
org.gradle.parallel = true
+12
View File
@@ -0,0 +1,12 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1df82b76031285ef2e6a4f59ffe9299d/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/c7d5be6a02945ac2e045048ee54a7d32/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/643f404f769811f5f265fd66f7af5d89/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/38256085a73e137cb4937ea9c4807fec/redirect
toolchainVersion=25
Vendored Executable → Regular
BIN
View File
Binary file not shown.
Vendored Executable → Regular
+3 -1
View File
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+178 -118
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,80 +15,114 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -97,92 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored Executable → Regular
+27 -34
View File
@@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,10 +27,14 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -37,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -51,48 +57,35 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
-4
View File
@@ -1,6 +1,2 @@
repositories {
maven {
name 'GTNH Maven'
url 'http://jenkins.usrv.eu:8081/nexus/content/repositories/public/'
}
}
+19 -6
View File
@@ -1,10 +1,23 @@
pluginManagement {
repositories {
maven {
// RetroFuturaGradle
name "GTNH Maven"
url "https://nexus.gtnewhorizons.com/repository/public/"
mavenContent {
includeGroup("com.gtnewhorizons")
includeGroupByRegex("com\\.gtnewhorizons\\..+")
}
}
gradlePluginPortal()
mavenCentral()
mavenLocal()
}
}
plugins {
id 'com.diffplug.blowdryerSetup' version '1.6.0'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.27'
}
apply plugin: 'com.diffplug.blowdryerSetup'
blowdryerSetup {
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.1.5')
//devLocal '.' // Use this when testing config updates locally
}
@@ -1,2 +1,5 @@
tile.relocation.blockmovingrow.name=Moving Block
tile.mcframes.frame.name=Frame
tile.mcframes.motor|0.name=Debug Frame Motor
tile.mcframes.motor.name=Debug Frame Motor
tile.mcframes.motor|0.name=Debug Frame Motor
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

-6
View File
@@ -1,6 +0,0 @@
[{
"repo": "https://github.com/GTNewHorizons/MrTJPCore/releases/download/1.1.1/",
"file": "MrTJPCore-1.7.10-1.1.1.jar",
"dev": "MrTJPCore-1.7.10-1.1.1-dev.jar",
"class": "mrtjp.core.handler.MrTJPCoreMod"
}]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

After

Width:  |  Height:  |  Size: 205 KiB

+2 -10
View File
@@ -12,11 +12,7 @@
"credits": "",
"logoFile": "",
"screenshots": [],
"parent": "",
"requiredMods": ["MrTJPCoreMod"],
"dependencies": [],
"dependants": [],
"useDependencyInformation": true
"parent": ""
},
{
"modid": "MCFrames",
@@ -30,10 +26,6 @@
"credits": "",
"logoFile": "fr_logo.png",
"screenshots": [],
"parent": "",
"requiredMods": ["${modId}"],
"dependencies": [],
"dependants": [],
"useDependencyInformation": true
"parent": ""
}]
}
+18 -23
View File
@@ -1,47 +1,42 @@
/*
* Copyright (c) 2014.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2014. Created by MrTJP. All rights reserved.
*/
package mrtjp.mcframes.api;
import mrtjp.relocation.api.Relocator;
import net.minecraft.world.World;
import mrtjp.relocation.api.Relocator;
/**
* Interface that can be implemented on Tile Entities or Blocks that wish to
* act as frames, which are the blocks that stick together and form a
* moving structure when moved through the {@link Relocator}. No other action besides
* Interface that can be implemented on Tile Entities or Blocks that wish to act as frames, which are the blocks that
* stick together and form a moving structure when moved through the {@link Relocator}. No other action besides
* implementation of this interface is needed for the block to function.
*/
public interface IFrame {
/**
* Used to check if this frame block is allowed to grab
* a block on the given side.
* Used to check if this frame block is allowed to grab a block on the given side.
*
* Convention requires that this method yields the same result
* on both client and server.
* Convention requires that this method yields the same result on both client and server.
*
* @param w The world.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param w The world.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param side The side of this block, as a ForgeDirection
* @return True if the side can grab another block.
*/
boolean stickOut(World w, int x, int y, int z, int side);
/**
* Used to check if this frame block can be grabbed on the
* given side by another frame.
* Used to check if this frame block can be grabbed on the given side by another frame.
*
* Convention requires that this method yields the same result
* on both client and server.
* Convention requires that this method yields the same result on both client and server.
*
* @param w The world.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param w The world.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param side The side of this block, as a ForgeDirection
* @return True if the side can be grabbed by a frame block.
*/
@@ -1,30 +1,26 @@
/*
* Copyright (c) 2014.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2014. Created by MrTJP. All rights reserved.
*/
package mrtjp.mcframes.api;
import mrtjp.relocation.api.RelocationAPI;
import net.minecraft.world.World;
import mrtjp.relocation.api.RelocationAPI;
/**
* Class used instead of {@link IFrame} to add frame capabilities
* to a block without having the block or tile in that location
* implement the IFrame interface. This class must be registered in
* the {@link RelocationAPI}.
* Class used instead of {@link IFrame} to add frame capabilities to a block without having the block or tile in that
* location implement the IFrame interface. This class must be registered in the {@link RelocationAPI}.
*/
public interface IFrameInteraction extends IFrame {
/**
* Check to see if this interaction can be executed at the given
* coordinates.
* Check to see if this interaction can be executed at the given coordinates.
*
* @param w The world.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @return True if this interaction is valid for the given
* location.
* @return True if this interaction is valid for the given location.
*/
boolean canInteract(World w, int x, int y, int z);
}
@@ -1,36 +1,35 @@
/*
* Copyright (c) 2014.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2014. Created by MrTJP. All rights reserved.
*/
package mrtjp.mcframes.api;
import codechicken.lib.vec.Vector3;
import mrtjp.relocation.api.RelocationAPI;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import codechicken.lib.vec.Vector3;
import mrtjp.relocation.api.RelocationAPI;
/**
* A utility interface used by the frame ItemBlock when placing.
* It can be used to add interactions to the default frame block
* placement. This class can be registered through the
* {@link RelocationAPI}.
* A utility interface used by the frame ItemBlock when placing. It can be used to add interactions to the default frame
* block placement. This class can be registered through the {@link RelocationAPI}.
*/
public interface IFramePlacement {
/**
* Called sequentially on all registered IFrameBlockPlacements on
* the frame item block's onItemUse function, until one returns true.
* @param item The itemstack of the frame block.
* Called sequentially on all registered IFrameBlockPlacements on the frame item block's onItemUse function, until
* one returns true.
*
* @param item The itemstack of the frame block.
* @param player The player who is placing the block.
* @param world The world the block is being placed in.
* @param x The x coordinate that the block is being placed in.
* @param y The y coordinate that the block is being placed in.
* @param z The z coordinate that the block is being placed in.
* @param side The side the player clicked on
* @param hit The exact hit position of the click.
* @param world The world the block is being placed in.
* @param x The x coordinate that the block is being placed in.
* @param y The y coordinate that the block is being placed in.
* @param z The z coordinate that the block is being placed in.
* @param side The side the player clicked on
* @param hit The exact hit position of the click.
* @return True if something happened. This will subsequently block the actual placement of the block.
*/
public boolean onItemUse(
ItemStack item, EntityPlayer player, World world, int x, int y, int z, int side, Vector3 hit);
public boolean onItemUse(ItemStack item, EntityPlayer player, World world, int x, int y, int z, int side,
Vector3 hit);
}
@@ -1,7 +1,5 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2015. Created by MrTJP. All rights reserved.
*/
package mrtjp.mcframes.api;
@@ -10,20 +8,20 @@ import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
/**
* API class for MCFrames.
* <br><br>
* API class for MCFrames. <br>
* <br>
* It is recommended that mods access this class within a soft dependency class.
*/
public abstract class MCFramesAPI {
/**
* This field will contain an implementor of this API if Relocation is installed.
*/
public static MCFramesAPI instance;
/**
* Used to register a custom placment that can define how a frame is placed.
* This is useful for cases such as if the frame is placed on a Multipart from
* the Forge Multipart API, this placement property can perform special actions
* Used to register a custom placment that can define how a frame is placed. This is useful for cases such as if the
* frame is placed on a Multipart from the Forge Multipart API, this placement property can perform special actions
* that would add the frame to the multipart tile.
*
* @param placement The custom frame placement to register.
@@ -31,51 +29,49 @@ public abstract class MCFramesAPI {
public abstract void registerFramePlacement(IFramePlacement placement);
/**
* Used to register a {@link IFrameInteraction}, which is a class that
* can be used to add frame-like properties to any block.
* Used to register a {@link IFrameInteraction}, which is a class that can be used to add frame-like properties to
* any block.
*
* @param interaction The interaction to register.
*/
public abstract void registerFrameInteraction(IFrameInteraction interaction);
/**
* Getter for the optional StickResolver object which can be used to quicky
* resolve a structure based on default Relocation frame blocks and stick
* rules.
* Getter for the optional StickResolver object which can be used to quicky resolve a structure based on default
* Relocation frame blocks and stick rules.
*
* @return The StickResolver object
*/
public abstract StickResolver getStickResolver();
/**
* Getter for the instance variable of the Frame block. Used if external
* implementations need the block. (i.e. registration purposes)
* Getter for the instance variable of the Frame block. Used if external implementations need the block. (i.e.
* registration purposes)
*
* @return The frame block.
*/
public abstract Block getFrameBlock();
/**
* Tessellates the frame model at the given coordinates. Useful for making
* your block look like the default frame block.
* Tessellates the frame model at the given coordinates. Useful for making your block look like the default frame
* block.
*
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param mask The mask of sides not to render.
*/
public abstract void renderFrame(double x, double y, double z, int mask);
/**
* Raytrace a frame block at the given world coords with start and end
* points of a ray.
* Raytrace a frame block at the given world coords with start and end points of a ray.
*
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param mask The side mask for the model.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param mask The side mask for the model.
* @param start The start point of the ray.
* @param end The end point of the ray.
* @param end The end point of the ray.
* @return The object position if anything from the frame model was hit.
*/
public abstract MovingObjectPosition raytraceFrame(double x, double y, double z, int mask, Vec3 start, Vec3 end);
@@ -1,28 +1,29 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2015. Created by MrTJP. All rights reserved.
*/
package mrtjp.mcframes.api;
import java.util.Set;
import mrtjp.relocation.api.BlockPos;
import net.minecraft.world.World;
import mrtjp.relocation.api.BlockPos;
/**
* Helper class used to resolve frame structures.
*/
public abstract class StickResolver {
/**
* Method used to obtain the block coordinates of every block that is part of the same
* framed structure as the one that was given as an argument.
* Method used to obtain the block coordinates of every block that is part of the same framed structure as the one
* that was given as an argument.
*
* @param world The world
* @param x The x coordinate of any block in the structure.
* @param y The y coordinate of any block in the structure.
* @param z The z coordinate of any block in the structure.
* @param exclusions All coordinates to not include in the structure.
* generally, one of these is the motor block that moved the structure.
* @param world The world
* @param x The x coordinate of any block in the structure.
* @param y The y coordinate of any block in the structure.
* @param z The z coordinate of any block in the structure.
* @param exclusions All coordinates to not include in the structure. generally, one of these is the motor block
* that moved the structure.
* @return A set of all block coordinates that are part of the structure that the input block was in.
*/
public abstract Set<BlockPos> getStructure(World world, int x, int y, int z, BlockPos... exclusions);
@@ -1,8 +1,28 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2015. Created by MrTJP. All rights reserved.
*/
// @API(owner = "MCFrames", provides = "MCFrames|API", apiVersion = "GRADLETOKEN_VERSION")
// spotless:off
//
// You may wonder, "why is this commented out?"
// When FML sorts the modcontainers, it includes APIs. The API's dependency is always its owner but if an API is found
// embedded in a mod which isn't the owner, that mod is set as the API's dependant. In this case, the same jar contains
// both ForgeRelocation and MCFrames, each with an API. So when FML determins which APIs are embedded where, it sees
// MCFrames|API embedded in ForgeRelocation and ForgeRelocation|API embedded in MCFrames. This results in the following
// circular load order:
//
// MCFrames --------------> MCFrames|API <----+
// ^ ^ | |
// | | | |
// | +-------------------+ | +- MrTJPCore
// | | | |
// | | v |
// ForgeRelocation|API <--- ForgeRelocation <-+
//
// spotless:on
// @API(owner = "MCFrames", provides = "MCFrames|API", apiVersion = Tags.VERSION)
package mrtjp.mcframes.api;
// import cpw.mods.fml.common.API;
// import mrtjp.relocation.Tags;
+230 -173
View File
@@ -29,210 +29,267 @@ import net.minecraftforge.common.util.ForgeDirection
import scala.collection.JavaConversions._
class BlockFrame extends BlockCore("mcframes.frame", Material.wood) with IFrame
{
setResistance(5.0F)
setHardness(2.0F)
setStepSound(Block.soundTypeWood)
setCreativeTab(CreativeTabs.tabTransport)
class BlockFrame
extends BlockCore("mcframes.frame", Material.wood)
with IFrame {
setResistance(5.0f)
setHardness(2.0f)
setStepSound(Block.soundTypeWood)
setCreativeTab(CreativeTabs.tabTransport)
override def getItemBlockClass = classOf[ItemBlockFrame]
override def getItemBlockClass = classOf[ItemBlockFrame]
override def stickOut(w:World, x:Int, y:Int, z:Int, side:Int) = true
override def stickIn(w:World, x:Int, y:Int, z:Int, side:Int) = true
override def stickOut(w: World, x: Int, y: Int, z: Int, side: Int) = true
override def stickIn(w: World, x: Int, y: Int, z: Int, side: Int) = true
override def isSideSolid(w:IBlockAccess, x:Int, y:Int, z:Int, side:ForgeDirection) = false
override def isSideSolid(
w: IBlockAccess,
x: Int,
y: Int,
z: Int,
side: ForgeDirection
) = false
override def isOpaqueCube = false
override def isOpaqueCube = false
override def renderAsNormalBlock = false
override def renderAsNormalBlock = false
override def collisionRayTrace(world:World, x:Int, y:Int, z:Int, start:Vec3, end:Vec3) =
MCFramesAPI.instance.raytraceFrame(x, y, z, 0, start, end)
override def collisionRayTrace(
world: World,
x: Int,
y: Int,
z: Int,
start: Vec3,
end: Vec3
) =
MCFramesAPI.instance.raytraceFrame(x, y, z, 0, start, end)
@SideOnly(Side.CLIENT)
override def getSelectedBoundingBoxFromPool(w:World, x:Int, y:Int, z:Int) =
Cuboid6.full.copy.add(new Vector3(x, y, z)).toAABB
@SideOnly(Side.CLIENT)
override def getSelectedBoundingBoxFromPool(
w: World,
x: Int,
y: Int,
z: Int
) =
Cuboid6.full.copy.add(new Vector3(x, y, z)).toAABB
override def getRenderType = RenderFrame.renderID
override def getRenderType = RenderFrame.renderID
override def getIcon(side:Int, meta:Int) = RenderFrame.icon
override def getIcon(side: Int, meta: Int) = RenderFrame.icon
@SideOnly(Side.CLIENT)
override def registerBlockIcons(reg:IIconRegister)
{
RenderFrame.registerIcons(reg)
}
@SideOnly(Side.CLIENT)
override def registerBlockIcons(reg: IIconRegister) {
RenderFrame.registerIcons(reg)
}
}
object ItemBlockFrame
{
var placements = Seq[IFramePlacement]()
object ItemBlockFrame {
var placements = Seq[IFramePlacement]()
}
class ItemBlockFrame(b:Block) extends ItemBlock(b)
{
override def getMetadata(meta:Int) = meta
class ItemBlockFrame(b: Block) extends ItemBlock(b) {
override def getMetadata(meta: Int) = meta
override def onItemUse(item:ItemStack, player:EntityPlayer, world:World, x:Int, y:Int, z:Int, side:Int, hitX:Float, hitY:Float, hitZ:Float):Boolean =
{
if (ItemBlockFrame.placements.exists(_.onItemUse(item, player, world, x, y, z,
side, new Vector3(hitX, hitY, hitZ))))
{
SoundLib.playBlockPlacement(world, x, y, z, field_150939_a)
true
}
else super.onItemUse(item, player, world, x, y, z, side, hitX, hitY, hitZ)
}
override def onItemUse(
item: ItemStack,
player: EntityPlayer,
world: World,
x: Int,
y: Int,
z: Int,
side: Int,
hitX: Float,
hitY: Float,
hitZ: Float
): Boolean = {
if (
ItemBlockFrame.placements.exists(
_.onItemUse(
item,
player,
world,
x,
y,
z,
side,
new Vector3(hitX, hitY, hitZ)
)
)
) {
SoundLib.playBlockPlacement(world, x, y, z, field_150939_a)
true
} else super.onItemUse(item, player, world, x, y, z, side, hitX, hitY, hitZ)
}
override def func_150936_a(world:World, x:Int, y:Int, z:Int, side:Int, player:EntityPlayer, stack:ItemStack) = true
override def func_150936_a(
world: World,
x: Int,
y: Int,
z: Int,
side: Int,
player: EntityPlayer,
stack: ItemStack
) = true
}
object RenderFrame extends ISimpleBlockRenderingHandler
{
var renderID = -1
var icon:IIcon = _
object RenderFrame extends ISimpleBlockRenderingHandler {
var renderID = -1
var icon: IIcon = _
private val model = parseModel("frame")
private val models = new Array[CCModel](64)
private val model = parseModel("frame")
private val models = new Array[CCModel](64)
private def parseModel(name:String) =
{
val m = combine(parseObjModels(this.getClass.getResource(
"/assets/mcframes/obj/"+name+".obj").openStream(),
7, InvertX).values())
private def parseModel(name: String) = {
val m = combine(
parseObjModels(
this.getClass
.getResource("/assets/mcframes/obj/" + name + ".obj")
.openStream(),
7,
InvertX
).values()
)
m.apply(new Scale(1.00075, 1.00075, 1.00075))
m.apply(new Translation(Vector3.center))
m
}
override def getRenderId = renderID
override def shouldRender3DInInventory(modelId:Int) = true
override def renderInventoryBlock(b:Block, meta:Int, id:Int, rb:RenderBlocks)
{
renderInvBlock(rb, meta)
}
override def renderWorldBlock(world:IBlockAccess, x:Int, y:Int, z:Int, b:Block, id:Int, rb:RenderBlocks) =
{
renderWorldBlock(rb, world, x, y, z, world.getBlockMetadata(x, y, z))
true
}
def renderWorldBlock(r:RenderBlocks, w:IBlockAccess, x:Int, y:Int, z:Int, meta:Int)
{
TextureUtils.bindAtlas(0)
CCRenderState.reset()
CCRenderState.lightMatrix.locate(w, x, y, z)
CCRenderState.setBrightness(w, x, y, z)
if (r.hasOverrideBlockTexture)
{
getOrGenerateModel(0).render(new Translation(x, y, z), new IconTransformation(r.overrideBlockTexture))
}
else RenderFrame.render(new Vector3(x, y, z), 0)
}
def renderInvBlock(r:RenderBlocks, meta:Int)
{
TextureUtils.bindAtlas(0)
CCRenderState.reset()
CCRenderState.setDynamic()
CCRenderState.pullLightmap()
CCRenderState.startDrawing()
RenderFrame.render(new Vector3(-0.5, -0.5, -0.5), 0)
CCRenderState.render()
CCRenderState.draw()
}
def registerIcons(reg:IIconRegister)
{
icon = reg.registerIcon("mcframes:frame")
}
def render(pos:Vector3, mask:Int)
{
getOrGenerateModel(mask).render(pos.translation, new IconTransformation(icon))
}
def getOrGenerateModel(mask:Int) =
{
var m = models(mask&0x3F)
if (m == null)
{
m = FrameModelGen.generate(model, mask)
models(mask&0x3F) = m
}
m
m.apply(new Scale(1.00075, 1.00075, 1.00075))
m.apply(new Translation(Vector3.center))
m
}
override def getRenderId = renderID
override def shouldRender3DInInventory(modelId: Int) = true
override def renderInventoryBlock(
b: Block,
meta: Int,
id: Int,
rb: RenderBlocks
) {
renderInvBlock(rb, meta)
}
override def renderWorldBlock(
world: IBlockAccess,
x: Int,
y: Int,
z: Int,
b: Block,
id: Int,
rb: RenderBlocks
) = {
TextureUtils.bindAtlas(0)
val state = CCRenderState.instance
state.resetInstance()
state.lightMatrix.locate(world, x, y, z)
state.setBrightnessInstance(world, x, y, z)
if (rb.hasOverrideBlockTexture) {
getOrGenerateModel(0).render(
new Translation(x, y, z),
new IconTransformation(rb.overrideBlockTexture)
)
} else RenderFrame.render(new Vector3(x, y, z), 0)
state.lightMatrix.access = null
true
}
def renderInvBlock(r: RenderBlocks, meta: Int) {
TextureUtils.bindAtlas(0)
val state = CCRenderState.instance
state.resetInstance()
state.setDynamicInstance()
state.pullLightmapInstance()
state.startDrawingInstance()
RenderFrame.render(new Vector3(-0.5, -0.5, -0.5), 0)
state.renderInstance()
state.drawInstance()
}
def registerIcons(reg: IIconRegister) {
icon = reg.registerIcon("mcframes:frame")
}
def render(pos: Vector3, mask: Int) {
getOrGenerateModel(mask).render(
pos.translation,
new IconTransformation(icon)
)
}
def getOrGenerateModel(mask: Int) = {
var m = models(mask & 0x3f)
if (m == null) {
m = FrameModelGen.generate(model, mask)
models(mask & 0x3f) = m
}
m
}
}
object FrameModelGen
{
val w = 2.0/16.0
val l = 16.0/16.0
val i = 1.0/16.0
val u = 0.5
val v = 0.5
object FrameModelGen {
val w = 2.0 / 16.0
val l = 16.0 / 16.0
val i = 1.0 / 16.0
val u = 0.5
val v = 0.5
def generate(box:CCModel, mask:Int) =
{
var m = generateSinglePeg
m = generateQuartRotated(m)
m = generateEightRotated(m)
m = generateBackface(m)
def generate(box: CCModel, mask: Int) = {
var m = generateSinglePeg
m = generateQuartRotated(m)
m = generateEightRotated(m)
m = generateBackface(m)
var b = Seq.newBuilder[CCModel]
b += box
for (s <- 0 until 6) if ((mask&1<<s) == 0)
b += generateSided(m.copy, s)
var b = Seq.newBuilder[CCModel]
b += box
for (s <- 0 until 6)
if ((mask & 1 << s) == 0)
b += generateSided(m.copy, s)
finishModel(combine(b.result()))
}
finishModel(combine(b.result()))
}
def generateSinglePeg =
{
val dw = w/2.0
val dl = l/2.0
def generateSinglePeg = {
val dw = w / 2.0
val dl = l / 2.0
val m = quadModel(4)
m.verts(0) = new Vertex5( dw, i, -dl, u+dw, v-dl)
m.verts(1) = new Vertex5( dw, i, dl, u+dw, v+dl)
m.verts(2) = new Vertex5(-dw, i, dl, u-dw, v+dl)
m.verts(3) = new Vertex5(-dw, i, -dl, u-dw, v-dl)
m.apply(new Translation(u, 0, v))
}
val m = quadModel(4)
m.verts(0) = new Vertex5(dw, i, -dl, u + dw, v - dl)
m.verts(1) = new Vertex5(dw, i, dl, u + dw, v + dl)
m.verts(2) = new Vertex5(-dw, i, dl, u - dw, v + dl)
m.verts(3) = new Vertex5(-dw, i, -dl, u - dw, v - dl)
m.apply(new Translation(u, 0, v))
}
def generateQuartRotated(m:CCModel) =
{
combine(Seq(m, m.copy.apply(Rotation.quarterRotations(1)
.at(Vector3.center) `with` new Translation(0, 0.01, 0))))
}
def generateQuartRotated(m: CCModel) = {
combine(
Seq(
m,
m.copy.apply(
Rotation
.quarterRotations(1)
.at(Vector3.center) `with` new Translation(0, 0.01, 0)
)
)
)
}
def generateEightRotated(m:CCModel) =
{
m.apply(new Rotation(math.Pi/4, 0, 1, 0).at(Vector3.center))
}
def generateEightRotated(m: CCModel) = {
m.apply(new Rotation(math.Pi / 4, 0, 1, 0).at(Vector3.center))
}
def generateBackface(m:CCModel) =
{
combine(Seq(m, m.backfacedCopy()))
}
def generateBackface(m: CCModel) = {
combine(Seq(m, m.backfacedCopy()))
}
def generateSided(m:CCModel, side:Int) =
{
m.apply(Rotation.sideRotations(side).at(Vector3.center.copy))
}
def generateSided(m: CCModel, side: Int) = {
m.apply(Rotation.sideRotations(side).at(Vector3.center.copy))
}
def finishModel(m:CCModel) =
{
m.shrinkUVs(0.0005)
m.computeNormals()
m.computeLighting(LightModel.standardLightModel)
}
}
def finishModel(m: CCModel) = {
m.shrinkUVs(0.0005)
m.computeNormals()
m.computeLighting(LightModel.standardLightModel)
}
}
@@ -10,7 +10,12 @@ import java.util.{Set => JSet}
import codechicken.lib.vec.{BlockCoord, Vector3}
import mrtjp.core.vec.ModelRayTracer
import mrtjp.core.world.WorldLib
import mrtjp.mcframes.api.{IFrameInteraction, IFramePlacement, MCFramesAPI, StickResolver}
import mrtjp.mcframes.api.{
IFrameInteraction,
IFramePlacement,
MCFramesAPI,
StickResolver
}
import mrtjp.mcframes.{ItemBlockFrame, RenderFrame, StickRegistry}
import mrtjp.relocation.api.{BlockPos, RelocationAPI}
import net.minecraft.block.Block
@@ -21,70 +26,87 @@ import scala.annotation.tailrec
import scala.collection.JavaConversions._
import scala.collection.immutable.Queue
object MCFramesAPI_Impl extends MCFramesAPI
{
override def registerFramePlacement(placement:IFramePlacement)
{
ItemBlockFrame.placements :+= placement
}
object MCFramesAPI_Impl extends MCFramesAPI {
override def registerFramePlacement(placement: IFramePlacement) {
ItemBlockFrame.placements :+= placement
}
override def getFrameBlock = MCFramesMod.blockFrame
override def getFrameBlock = MCFramesMod.blockFrame
override def registerFrameInteraction(interaction:IFrameInteraction)
{
StickRegistry.interactionList :+= interaction
}
override def registerFrameInteraction(interaction: IFrameInteraction) {
StickRegistry.interactionList :+= interaction
}
override def getStickResolver = StickResolver_Impl
override def getStickResolver = StickResolver_Impl
override def renderFrame(x:Double, y:Double, z:Double, mask:Int)
{
RenderFrame.render(new Vector3(x, y, z), mask)
}
override def renderFrame(x: Double, y: Double, z: Double, mask: Int) {
RenderFrame.render(new Vector3(x, y, z), mask)
}
override def raytraceFrame(x:Double, y:Double, z:Double, mask:Int, start:Vec3, end:Vec3) =
ModelRayTracer.raytraceModel(x, y, z, start, end, RenderFrame.getOrGenerateModel(mask))
override def raytraceFrame(
x: Double,
y: Double,
z: Double,
mask: Int,
start: Vec3,
end: Vec3
) =
ModelRayTracer.raytraceModel(
x,
y,
z,
start,
end,
RenderFrame.getOrGenerateModel(mask)
)
}
object StickResolver_Impl extends StickResolver
{
private var world:World = null
private var start:BlockCoord = null
private var excl:Set[BlockCoord] = null
object StickResolver_Impl extends StickResolver {
private var world: World = null
private var start: BlockCoord = null
private var excl: Set[BlockCoord] = null
override def getStructure(w:World, x:Int, y:Int, z:Int, ex:BlockPos*):JSet[BlockPos] =
{
world = w
start = new BlockCoord(x, y, z)
excl = ex.map(b => new BlockCoord(b.x, b.y, b.z)).toSet
val result = iterate(Queue(start))
world = null
start = null
excl = null
result.map(b => new BlockPos(b.x, b.y, b.z))
}
override def getStructure(
w: World,
x: Int,
y: Int,
z: Int,
ex: BlockPos*
): JSet[BlockPos] = {
world = w
start = new BlockCoord(x, y, z)
excl = ex.map(b => new BlockCoord(b.x, b.y, b.z)).toSet
val result = iterate(Queue(start))
world = null
start = null
excl = null
result.map(b => new BlockPos(b.x, b.y, b.z))
}
@tailrec
private def iterate(open:Seq[BlockCoord], closed:Set[BlockCoord] = Set.empty):Set[BlockCoord] = open match
{
case Seq() => closed
case Seq(next, rest@_*) => WorldLib.getBlock(world, next) match
{
case block:Block =>
val toCheck = Vector.newBuilder[BlockCoord]
for (s <- 0 until 6)
{
if (StickRegistry.resolveStick(world, next, s))
{
val to = next.copy.offset(s)
if (!excl(to) && !closed(to) && !open.contains(to))
if (!world.isAirBlock(to.x, to.y, to.z) && !RelocationAPI.instance.isMoving(world, to.x, to.y, to.z)
/**&& MovingTileRegistry.canMove(world, to.x, to.y, to.z)**/)//Dont ignore non-movables, have them halt movement.
toCheck += to
}
}
iterate(rest++toCheck.result(), closed+next)
case _ => iterate(rest, closed+next)
}
}
}
@tailrec
private def iterate(
open: Seq[BlockCoord],
closed: Set[BlockCoord] = Set.empty
): Set[BlockCoord] = open match {
case Seq() => closed
case Seq(next, rest @ _*) =>
WorldLib.getBlock(world, next) match {
case block: Block =>
val toCheck = Vector.newBuilder[BlockCoord]
for (s <- 0 until 6) {
if (StickRegistry.resolveStick(world, next, s)) {
val to = next.copy.offset(s)
if (!excl(to) && !closed(to) && !open.contains(to))
if (
!world.isAirBlock(to.x, to.y, to.z) && !RelocationAPI.instance
.isMoving(world, to.x, to.y, to.z)
/** && MovingTileRegistry.canMove(world, to.x, to.y, to.z)* */
) // Dont ignore non-movables, have them halt movement.
toCheck += to
}
}
iterate(rest ++ toCheck.result(), closed + next)
case _ => iterate(rest, closed + next)
}
}
}
+66 -55
View File
@@ -6,75 +6,86 @@
package mrtjp.mcframes.handler
import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.{FMLInitializationEvent, FMLPostInitializationEvent, FMLPreInitializationEvent}
import cpw.mods.fml.common.event.{
FMLInitializationEvent,
FMLPostInitializationEvent,
FMLPreInitializationEvent
}
import mrtjp.core.data.{ModConfig, SpecialConfigGui, TModGuiFactory}
import mrtjp.mcframes.api.MCFramesAPI
import mrtjp.mcframes.{BlockFrame, BlockMotor, StickRegistry}
import mrtjp.relocation.Tags
import net.minecraft.client.gui.GuiScreen
@Mod(modid = MCFramesMod.modID, useMetadata = true, modLanguage = "scala", guiFactory = "mrtjp.mcframes.handler.GuiConfigFactory", acceptedMinecraftVersions = "[1.7.10]", dependencies = "required-after:MrTJPCoreMod", name = MCFramesMod.modName, version = MCFramesMod.version)
object MCFramesMod
{
MCFramesAPI.instance = MCFramesAPI_Impl
@Mod(
modid = MCFramesMod.modID,
useMetadata = true,
modLanguage = "scala",
guiFactory = "mrtjp.mcframes.handler.GuiConfigFactory",
acceptedMinecraftVersions = "[1.7.10]",
dependencies = "required-after:MrTJPCoreMod",
name = MCFramesMod.modName,
version = MCFramesMod.version
)
object MCFramesMod {
MCFramesAPI.instance = MCFramesAPI_Impl
final val modID = "MCFrames"
final val modName = "MCFrames"
final val version = "GRADLETOKEN_VERSION"
final val modID = "MCFrames"
final val modName = "MCFrames"
final val version = Tags.VERSION
var blockFrame:BlockFrame = _
var blockMotor:BlockMotor = _
var blockFrame: BlockFrame = _
var blockMotor: BlockMotor = _
@Mod.EventHandler
def preInit(event:FMLPreInitializationEvent)
{
MCFramesProxy.preinit()
}
@Mod.EventHandler
def preInit(event: FMLPreInitializationEvent) {
MCFramesProxy.preinit()
}
@Mod.EventHandler
def init(event:FMLInitializationEvent)
{
MCFramesConfig.loadConfig()
MCFramesProxy.init()
}
@Mod.EventHandler
def init(event: FMLInitializationEvent) {
MCFramesConfig.loadConfig()
MCFramesProxy.init()
}
@Mod.EventHandler
def postInit(event:FMLPostInitializationEvent)
{
MCFramesProxy.postinit()
}
@Mod.EventHandler
def postInit(event: FMLPostInitializationEvent) {
MCFramesProxy.postinit()
}
}
class MCFramesConfigGui(parent:GuiScreen) extends SpecialConfigGui(parent, "MCFrames", MCFramesConfig.config)
class GuiConfigFactory extends TModGuiFactory
{
override def mainConfigGuiClass() = classOf[MCFramesConfigGui]
class MCFramesConfigGui(parent: GuiScreen)
extends SpecialConfigGui(parent, "MCFrames", MCFramesConfig.config)
class GuiConfigFactory extends TModGuiFactory {
override def mainConfigGuiClass() = classOf[MCFramesConfigGui]
}
object MCFramesConfig extends ModConfig("MCFrames")
{
var setMap = Array(
"minecraft:bed -> minecraft:bed",
"minecraft:wooden_door -> minecraft:wooden_door",
"minecraft:iron_door -> minecraft:iron_door"
object MCFramesConfig extends ModConfig("MCFrames") {
var setMap = Array(
"minecraft:bed -> minecraft:bed",
"minecraft:wooden_door -> minecraft:wooden_door",
"minecraft:iron_door -> minecraft:iron_door"
)
override protected def initValues() {
val sets = new BaseCategory("Latched Sets", buildLatchSetsDesc)
setMap = sets.put("latch registry", setMap)
setMap = sets.put(
"latch registry",
StickRegistry.parseAndAddLatchSets(setMap),
true
)
}
override protected def initValues()
{
val sets = new BaseCategory("Latched Sets", buildLatchSetsDesc)
setMap = sets.put("latch registry", setMap)
setMap = sets.put("latch registry", StickRegistry.parseAndAddLatchSets(setMap), true)
}
def buildLatchSetsDesc:String =
{
var s = "Used to define which pairs of blocks will be stuck together. \n"
s += "Latched sets will always move in pairs, even if only one of them are actually connected to a block. \n"
s += "'block1 -> block2' means that if block1 is moved, any block2 connected to it will also move. \n"
s += "However, moving block2 does not move block1. To do that, you must also register block2 -> block1. \n"
s += "Sets are defined using the syntax of key -> value. \n"
s += "Possible keys and values:\n"
s += " '<modID>:<blockname>' - to assign block from a mod for every meta. \n"
s += " '<modID>:<blockname>m<meta>' - to assign block from mod for specific meta. \n"
s
}
def buildLatchSetsDesc: String = {
var s = "Used to define which pairs of blocks will be stuck together. \n"
s += "Latched sets will always move in pairs, even if only one of them are actually connected to a block. \n"
s += "'block1 -> block2' means that if block1 is moved, any block2 connected to it will also move. \n"
s += "However, moving block2 does not move block1. To do that, you must also register block2 -> block1. \n"
s += "Sets are defined using the syntax of key -> value. \n"
s += "Possible keys and values:\n"
s += " '<modID>:<blockname>' - to assign block from a mod for every meta. \n"
s += " '<modID>:<blockname>m<meta>' - to assign block from mod for specific meta. \n"
s
}
}
@@ -17,47 +17,47 @@ import net.minecraft.init.Items
import net.minecraft.item.ItemStack
import net.minecraftforge.oredict.ShapedOreRecipe
class MCFramesProxy_server
{
def preinit()
{
blockMotor = new BlockMotor
blockFrame = new BlockFrame
}
class MCFramesProxy_server {
def preinit() {
blockMotor = new BlockMotor
blockFrame = new BlockFrame
}
def init()
{
MCFramesRecipes.initRecipes()
}
def init() {
MCFramesRecipes.initRecipes()
}
def postinit(){}
def postinit() {}
}
class MCFramesProxy_client extends MCFramesProxy_server
{
@SideOnly(Side.CLIENT)
override def preinit()
{
super.preinit()
class MCFramesProxy_client extends MCFramesProxy_server {
@SideOnly(Side.CLIENT)
override def preinit() {
super.preinit()
TileRenderRegistry.setRenderer(MCFramesMod.blockMotor, 0, RenderMotor)
TileRenderRegistry.setRenderer(MCFramesMod.blockMotor, 0, RenderMotor)
RenderFrame.renderID = RenderingRegistry.getNextAvailableRenderId
RenderingRegistry.registerBlockHandler(RenderFrame)
}
RenderFrame.renderID = RenderingRegistry.getNextAvailableRenderId
RenderingRegistry.registerBlockHandler(RenderFrame)
}
}
object MCFramesProxy extends MCFramesProxy_client
object MCFramesRecipes
{
def initRecipes()
{
//Frame
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(blockFrame, 8),
"sls","lsl","sls",
's':JC, Items.stick,
'l':JC, "logWood"
))
}
}
object MCFramesRecipes {
def initRecipes() {
// Frame
GameRegistry.addRecipe(
new ShapedOreRecipe(
new ItemStack(blockFrame, 8),
"sls",
"lsl",
"sls",
's': JC,
Items.stick,
'l': JC,
"logWood"
)
)
}
}
+137 -140
View File
@@ -25,155 +25,152 @@ import net.minecraft.util.IIcon
import net.minecraft.world.{IBlockAccess, World}
import net.minecraftforge.common.util.ForgeDirection
class BlockMotor extends InstancedBlock("mcframes.motor", Material.iron)
{
setHardness(5f)
setResistance(10f)
setStepSound(Block.soundTypeMetal)
setCreativeTab(CreativeTabs.tabTransport)
addSingleTile(classOf[TileMotor])
class BlockMotor extends InstancedBlock("mcframes.motor", Material.iron) {
setHardness(5f)
setResistance(10f)
setStepSound(Block.soundTypeMetal)
setCreativeTab(CreativeTabs.tabTransport)
addSingleTile(classOf[TileMotor])
override def isSideSolid(world:IBlockAccess, x:Int, y:Int, z:Int, side:ForgeDirection) = true
override def isSideSolid(
world: IBlockAccess,
x: Int,
y: Int,
z: Int,
side: ForgeDirection
) = true
override def renderAsNormalBlock = true
override def renderAsNormalBlock = true
}
class TileMotor extends InstancedBlockTile with TTileOrient with IFrame
{
override def save(tag:NBTTagCompound)
{
super.save(tag)
tag.setByte("orient", orientation)
}
override def load(tag:NBTTagCompound)
{
super.load(tag)
orientation = tag.getByte("orient")
}
override def readDesc(in:MCDataInput)
{
super.readDesc(in)
orientation = in.readByte()
}
override def writeDesc(out:MCDataOutput)
{
super.writeDesc(out)
out.writeByte(orientation)
}
override def read(in:MCDataInput, key:Int) = key match
{
case 2 =>
orientation = in.readByte()
markRender()
case _ => super.read(in, key)
}
def sendOrientUpdate()
{
if (!world.isRemote)
writeStream(2).writeByte(orientation).sendToChunk()
}
override def onBlockPlaced(side:Int, meta:Int, player:EntityPlayer, stack:ItemStack, hit:Vector3)
{
super.onBlockPlaced(side, meta, player, stack, hit)
setSide(side^1)
setRotation(Rotation.getSidedRotation(player, side^1))
}
override def onBlockActivated(player:EntityPlayer, s:Int):Boolean =
{
if (super.onBlockActivated(player, s)) return true
if (player.isSneaking) setRotation((rotation+1)%4)
else setSide((side+1)%6)
true
}
override def onOrientChanged(oldOrient:Int)
{
super.onOrientChanged(oldOrient)
sendOrientUpdate()
}
override def getBlock = MCFramesMod.blockMotor
def getMoveDir = absoluteDir((rotation+2)%4)
override def stickOut(w:World, x:Int, y:Int, z:Int, side:Int) = side == (this.side^1)
override def stickIn(w:World, x:Int, y:Int, z:Int, side:Int) = side != (this.side^1)
override def update()
{
if (!world.isRemote && world.getBlockPowerInput(x, y, z) > 0)
{
val pos = position.offset(side^1)
if (world.isAirBlock(pos.x, pos.y, pos.z)) return
if (!RelocationAPI.instance.isMoving(world, pos.x, pos.y, pos.z) &&
!RelocationAPI.instance.isMoving(world, x, y, z))
{
val blocks = MCFramesAPI.instance.getStickResolver
.getStructure(world, pos.x, pos.y, pos.z, new BlockPos(x, y, z))
val r = RelocationAPI.instance.getRelocator
r.push()
r.setWorld(world)
r.setDirection(getMoveDir)
r.setSpeed(1/16D)
r.addBlocks(blocks)
r.execute()
r.pop()
}
}
class TileMotor extends InstancedBlockTile with TTileOrient with IFrame {
override def save(tag: NBTTagCompound) {
super.save(tag)
tag.setByte("orient", orientation)
}
override def load(tag: NBTTagCompound) {
super.load(tag)
orientation = tag.getByte("orient")
}
override def readDesc(in: MCDataInput) {
super.readDesc(in)
orientation = in.readByte()
}
override def writeDesc(out: MCDataOutput) {
super.writeDesc(out)
out.writeByte(orientation)
}
override def read(in: MCDataInput, key: Int) = key match {
case 2 =>
orientation = in.readByte()
markRender()
case _ => super.read(in, key)
}
def sendOrientUpdate() {
if (!world.isRemote)
writeStream(2).writeByte(orientation).sendToChunk()
}
override def onBlockPlaced(
side: Int,
meta: Int,
player: EntityPlayer,
stack: ItemStack,
hit: Vector3
) {
super.onBlockPlaced(side, meta, player, stack, hit)
setSide(side ^ 1)
setRotation(Rotation.getSidedRotation(player, side ^ 1))
}
override def onBlockActivated(player: EntityPlayer, s: Int): Boolean = {
if (super.onBlockActivated(player, s)) return true
if (player.isSneaking) setRotation((rotation + 1) % 4)
else setSide((side + 1) % 6)
true
}
override def onOrientChanged(oldOrient: Int) {
super.onOrientChanged(oldOrient)
sendOrientUpdate()
}
override def getBlock = MCFramesMod.blockMotor
def getMoveDir = absoluteDir((rotation + 2) % 4)
override def stickOut(w: World, x: Int, y: Int, z: Int, side: Int) =
side == (this.side ^ 1)
override def stickIn(w: World, x: Int, y: Int, z: Int, side: Int) =
side != (this.side ^ 1)
override def update() {
if (!world.isRemote && world.getBlockPowerInput(x, y, z) > 0) {
val pos = position.offset(side ^ 1)
if (world.isAirBlock(pos.x, pos.y, pos.z)) return
if (
!RelocationAPI.instance.isMoving(world, pos.x, pos.y, pos.z) &&
!RelocationAPI.instance.isMoving(world, x, y, z)
) {
val blocks = MCFramesAPI.instance.getStickResolver
.getStructure(world, pos.x, pos.y, pos.z, new BlockPos(x, y, z))
val r = RelocationAPI.instance.getRelocator
r.push()
r.setWorld(world)
r.setDirection(getMoveDir)
r.setSpeed(1 / 16d)
r.addBlocks(blocks)
r.execute()
r.pop()
}
}
}
}
object RenderMotor extends TCubeMapRender
{
var bottom:IIcon = _
var side:IIcon = _
var sidew:IIcon = _
var sidee:IIcon = _
var top:IIcon = _
object RenderMotor extends TCubeMapRender {
var bottom: IIcon = _
var side: IIcon = _
var sidew: IIcon = _
var sidee: IIcon = _
var top: IIcon = _
override def getData(w:IBlockAccess, x:Int, y:Int, z:Int) =
{
val te = WorldLib.getTileEntity(w, x, y, z, classOf[TileMotor])
var s = 0
var r = 0
if (te != null)
{
s = te.side
r = te.rotation
}
(s, r, new MultiIconTransformation(bottom, top, side, side, sidew, sidee))
override def getData(w: IBlockAccess, x: Int, y: Int, z: Int) = {
val te = WorldLib.getTileEntity(w, x, y, z, classOf[TileMotor])
var s = 0
var r = 0
if (te != null) {
s = te.side
r = te.rotation
}
(s, r, new MultiIconTransformation(bottom, top, side, side, sidew, sidee))
}
override def getInvData =
(0, 0, new MultiIconTransformation(bottom, top, side, side, sidew, sidee))
override def getInvData =
(0, 0, new MultiIconTransformation(bottom, top, side, side, sidew, sidee))
override def getIcon(s:Int, meta:Int) = s match
{
case 0 => bottom
case 1 => top
case 2 => side
case 3 => side
case 4 => sidew
case 5 => sidee
}
override def getIcon(s: Int, meta: Int) = s match {
case 0 => bottom
case 1 => top
case 2 => side
case 3 => side
case 4 => sidew
case 5 => sidee
}
override def registerIcons(reg:IIconRegister)
{
bottom = reg.registerIcon("mcframes:motor/bottom")
top = reg.registerIcon("mcframes:motor/top")
side = reg.registerIcon("mcframes:motor/side")
sidew = reg.registerIcon("mcframes:motor/sidew")
sidee = reg.registerIcon("mcframes:motor/sidee")
}
}
override def registerIcons(reg: IIconRegister) {
bottom = reg.registerIcon("mcframes:motor/bottom")
top = reg.registerIcon("mcframes:motor/top")
side = reg.registerIcon("mcframes:motor/side")
sidew = reg.registerIcon("mcframes:motor/sidew")
sidee = reg.registerIcon("mcframes:motor/sidee")
}
}
+74 -66
View File
@@ -11,79 +11,87 @@ import mrtjp.mcframes.api.{IFrame, IFrameInteraction}
import net.minecraft.block.Block
import net.minecraft.world.World
object StickRegistry
{
val rKeyVal = raw"([\w:]+)\s*->\s*(.+)".r
val rName = raw"(.+)".r
val rNameMetaM = raw"(.+)m(\d+)".r
val rMod = raw"mod:(\w+)".r
object StickRegistry {
val rKeyVal = raw"([\w:]+)\s*->\s*(.+)".r
val rName = raw"(.+)".r
val rNameMetaM = raw"(.+)m(\d+)".r
val rMod = raw"mod:(\w+)".r
var latchMap = Map[(Block, Int), Set[(Block, Int)]]().withDefaultValue(Set())
var interactionList = Seq[IFrameInteraction]()
var latchMap = Map[(Block, Int), Set[(Block, Int)]]().withDefaultValue(Set())
var interactionList = Seq[IFrameInteraction]()
def parseKV(kv:Seq[String]) = kv.map { case rKeyVal(k, v) => (k, v); case s => throw new MatchError(s"Illegal [k -> v] pair: $s") }
def parseBlockMeta(b:String) = b match
{
case rNameMetaM(name, meta) => Block.getBlockFromName(fixName(name)) -> meta.toInt
case rName(name) => Block.getBlockFromName(fixName(name)) -> -1
case _ => throw new MatchError(s"Illegal set part: $b")
}
def fixName(name:String) = name.indexOf(':') match
{
case -1 => "minecraft:"+name
case i => name
}
def parseKV(kv: Seq[String]) = kv.map {
case rKeyVal(k, v) => (k, v);
case s => throw new MatchError(s"Illegal [k -> v] pair: $s")
}
def parseBlockMeta(b: String) = b match {
case rNameMetaM(name, meta) =>
Block.getBlockFromName(fixName(name)) -> meta.toInt
case rName(name) => Block.getBlockFromName(fixName(name)) -> -1
case _ => throw new MatchError(s"Illegal set part: $b")
}
def fixName(name: String) = name.indexOf(':') match {
case -1 => "minecraft:" + name
case i => name
}
def parseAndAddLatchSets(kv:Seq[String]):Array[String] =
{
parseKV(kv).foreach(b => addLatchSet(parseBlockMeta(b._1), parseBlockMeta(b._2)))
latchMap.map{kv =>
val (b, i) = kv._1
val e1 = Block.blockRegistry.getNameForObject(b)+(if (i != -1) s"m$i" else "")
kv._2.map { k =>
val (b2, i2) = k
val e2 = Block.blockRegistry.getNameForObject(b2)+(if (i2 != -1) s"m$i2" else "")
e1+" -> "+e2
}
}.flatten.toArray
}
def addLatchSet(b1:(Block, Int), b2:(Block, Int))
{
latchMap += b1 -> (latchMap(b1)+b2)
}
def resolveStick(w:World, pos:BlockCoord, side:Int):Boolean =
{
def getFrame(pos:BlockCoord):IFrame =
{
val b = getBlock(w, pos)
if (b.isInstanceOf[IFrame]) return b.asInstanceOf[IFrame]
val te = getTileEntity(w, pos, classOf[IFrame])
if (te != null) return te
interactionList.find(_.canInteract(w, pos.x, pos.y, pos.z)).orNull
def parseAndAddLatchSets(kv: Seq[String]): Array[String] = {
parseKV(kv).foreach(b =>
addLatchSet(parseBlockMeta(b._1), parseBlockMeta(b._2))
)
latchMap
.map { kv =>
val (b, i) = kv._1
val e1 = Block.blockRegistry.getNameForObject(b) + (if (i != -1) s"m$i"
else "")
kv._2.map { k =>
val (b2, i2) = k
val e2 =
Block.blockRegistry.getNameForObject(b2) + (if (i2 != -1) s"m$i2"
else "")
e1 + " -> " + e2
}
}
.flatten
.toArray
}
val f1 = getFrame(pos)
if (f1 != null && f1.stickOut(w, pos.x, pos.y, pos.z, side))
{
val p2 = pos.copy.offset(side)
val f2 = getFrame(p2)
return f2 == null || f2.stickIn(w, p2.x, p2.y, p2.z, side^1)
}
def addLatchSet(b1: (Block, Int), b2: (Block, Int)) {
latchMap += b1 -> (latchMap(b1) + b2)
}
if (latchSet(w, pos.x, pos.y, pos.z, side)) return true
def resolveStick(w: World, pos: BlockCoord, side: Int): Boolean = {
val p2 = pos.copy.offset(side)
val target = getBlock(w, p2)
if (
target != null &&
target.getBlockHardness(w, p2.x, p2.y, p2.z) < 0
) return false
false
def getFrame(pos: BlockCoord): IFrame = {
val b = getBlock(w, pos)
if (b.isInstanceOf[IFrame]) return b.asInstanceOf[IFrame]
val te = getTileEntity(w, pos, classOf[IFrame])
if (te != null) return te
interactionList.find(_.canInteract(w, pos.x, pos.y, pos.z)).orNull
}
val f1 = getFrame(pos)
if (f1 != null && f1.stickOut(w, pos.x, pos.y, pos.z, side)) {
val f2 = getFrame(p2)
return f2 == null || f2.stickIn(w, p2.x, p2.y, p2.z, side ^ 1)
}
def latchSet(w:World, x:Int, y:Int, z:Int, side:Int) =
{
val pos = new BlockCoord(x, y, z).offset(side)
val b1 = getBlockMetaPair(w, x, y, z)
val b2 = getBlockMetaPair(w, pos.x, pos.y, pos.z)
if (latchSet(w, pos.x, pos.y, pos.z, side)) return true
val set = latchMap.getOrElse(b1, latchMap((b1._1, -1)))
set.contains(b2) || set.contains((b2._1, -1))
}
}
false
}
def latchSet(w: World, x: Int, y: Int, z: Int, side: Int) = {
val pos = new BlockCoord(x, y, z).offset(side)
val b1 = getBlockMetaPair(w, x, y, z)
val b2 = getBlockMetaPair(w, pos.x, pos.y, pos.z)
val set = latchMap.getOrElse(b1, latchMap((b1._1, -1)))
set.contains(b2) || set.contains((b2._1, -1))
}
}
@@ -1,15 +1,14 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2015. Created by MrTJP. All rights reserved.
*/
package mrtjp.relocation.api;
/**
* Lightweight block position object used to keep dependencies confined
* to the api package, used by some of the API's methods.
* Lightweight block position object used to keep dependencies confined to the api package, used by some of the API's
* methods.
*/
public class BlockPos {
public int x;
public int y;
public int z;
@@ -1,32 +1,26 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2015. Created by MrTJP. All rights reserved.
*/
package mrtjp.relocation.api;
/**
* Interface that can be used by things that wish to receive events for
* a move that they executed. This interface is passed into the {@link Relocator}
* during movement construction.
* Interface that can be used by things that wish to receive events for a move that they executed. This interface is
* passed into the {@link Relocator} during movement construction.
*
* For example, a motor may wish to know when the movement completes. In which case,
* the motor tile itself would implement this interface and pass itself into the
* Relocator.
* For example, a motor may wish to know when the movement completes. In which case, the motor tile itself would
* implement this interface and pass itself into the Relocator.
*
* These methods are only called server-side. Clients will not receive any of
* these events, as this class is registered during the execution of a move, which
* can only happen server-side.
* These methods are only called server-side. Clients will not receive any of these events, as this class is registered
* during the execution of a move, which can only happen server-side.
*
*/
public interface IMovementCallback {
/**
* Called once move starts. The descriptor contains methods that
* describe the state of the current movement that this callback
* was registered to.
* Called once move starts. The descriptor contains methods that describe the state of the current movement that
* this callback was registered to.
*
* This descriptor is properly weak-referenced, keep or discard it
* at your own leasure.
* This descriptor is properly weak-referenced, keep or discard it at your own leasure.
*
* @param desc The movement descriptor for the current move.
*/
@@ -1,18 +1,17 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2015. Created by MrTJP. All rights reserved.
*/
package mrtjp.relocation.api;
/**
* This is the interface of the object that is given to an {@link IMovementCallback} so
* it may access movement information whenever it needs to during the movement.
* This is the interface of the object that is given to an {@link IMovementCallback} so it may access movement
* information whenever it needs to during the movement.
*
* Results of all methods is only valid during movement, undefined otherwise. Use
* isMoving() to check before using any values from this.
* Results of all methods is only valid during movement, undefined otherwise. Use isMoving() to check before using any
* values from this.
*/
public interface IMovementDescriptor {
/**
* @return True if the structure is moving.
*/
@@ -1,23 +1,20 @@
/*
* Copyright (c) 2014.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2014. Created by MrTJP. All rights reserved.
*/
package mrtjp.relocation.api;
import net.minecraft.world.World;
/**
* Interface for an object that manages the movement of blocks and tiles that are
* registered to it. This class should be registered through the {@link RelocationAPI}.
* Interface for an object that manages the movement of blocks and tiles that are registered to it. This class should be
* registered through the {@link RelocationAPI}.
*/
public interface ITileMover {
/**
* Used to check if the block at the given position can move. This
* method is only called if the specified block is tied to this
* handler, so there is no need to check if the block is valid
* for this handler. This is called before actually moving. If
* everything is able to move, an animation will start.
* Used to check if the block at the given position can move. This method is only called if the specified block is
* tied to this handler, so there is no need to check if the block is valid for this handler. This is called before
* actually moving. If everything is able to move, an animation will start.
*
* Called server-side only when determining what to move.
*
@@ -30,25 +27,22 @@ public interface ITileMover {
boolean canMove(World w, int x, int y, int z);
/**
* Method used to actually move the tile. Called after the animation
* has run. This is where you should tell the tile that it is time
* to move, and peform any extra checks or calls. This should also
* move the block and tile as well. This is called
* on every block in the moving structure sequentially.
* Method used to actually move the tile. Called after the animation has run. This is where you should tell the tile
* that it is time to move, and peform any extra checks or calls. This should also move the block and tile as well.
* This is called on every block in the moving structure sequentially.
*
* Called on both server and client.
*
* @param w The world.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param w The world.
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param dir The ForgeDirection the structure is moving in.
*/
void move(World w, int x, int y, int z, int dir);
/**
* Called after all blocks in the group have moved to their
* new locations. This is where you would reload your tile,
* Called after all blocks in the group have moved to their new locations. This is where you would reload your tile,
* tell it to refresh or reacknowledge its new position.
*
* Callod on both server and client.
@@ -1,90 +1,78 @@
/*
* Copyright (c) 2014.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2014. Created by MrTJP. All rights reserved.
*/
package mrtjp.relocation.api;
import net.minecraft.world.World;
/**
* Central API class for Relocation.
* If Relocation is installed, the appropriate field will contain an
* implementor of these methods.
* <br><br>
* Central API class for Relocation. If Relocation is installed, the appropriate field will contain an implementor of
* these methods. <br>
* <br>
* It is recommended that mods access this class within a soft dependency class.
*/
public abstract class RelocationAPI {
/**
* This field will contain an implementor of this API if Relocation is installed.
*/
public static RelocationAPI instance;
/**
* Used to register a {@link ITileMover} class that manages the movement of certain tiles.
* This method must be called during FML pre-initialization.
* Used to register a {@link ITileMover} class that manages the movement of certain tiles. This method must be
* called during FML pre-initialization.
*
* @param name The name of the mover that will be used to assign blocks to it.
* @param desc The description of what this mover is used for or why it is included.
* @param name The name of the mover that will be used to assign blocks to it.
* @param desc The description of what this mover is used for or why it is included.
* @param mover The {@link ITileMover} to register.
*/
public abstract void registerTileMover(String name, String desc, ITileMover mover);
/**
* Used to register an in-game block to a specific {@link ITileMover} which are registered
* with the method above. This method adds the key-value pairs similar to the config,
* but their assignments can be changed from the config file if you would like.
* This method must be called during FML pre-initialization.
* Used to register an in-game block to a specific {@link ITileMover} which are registered with the method above.
* This method adds the key-value pairs similar to the config, but their assignments can be changed from the config
* file if you would like. This method must be called during FML pre-initialization.
*
* @param key The mod or block key regex. This works the same way it does from the
* config file:
* Possible keys:
* default - to assign default mover
* mod:<modID> - to assign every block from a mod
* <modID>:<blockname> - to assign block from a mod for every meta
* <modID>:<blockname>m<meta> - to assign block from mod for specific meta
* @param key The mod or block key regex. This works the same way it does from the config file: Possible keys:
* default - to assign default mover mod:<modID> - to assign every block from a mod <modID>:<blockname>
* - to assign block from a mod for every meta <modID>:<blockname>m<meta> - to assign block from mod
* for specific meta
*
* @param value The name of the mover to assign this block. A list of all available
* movers will show up in the configs.
* @param value The name of the mover to assign this block. A list of all available movers will show up in the
* configs.
*/
public abstract void registerPreferredMover(String key, String value);
/**
* Used to register an in-game block to a specific {@link ITileMover} which are registered
* with the method above. This method adds the key-value pairs similar to the config. These
* assignments are manatory, and blocks that are registered will be locked to the specified
* mover, and it cannot be changed from the config.
* This method must be called during FML pre-initialization.
* Used to register an in-game block to a specific {@link ITileMover} which are registered with the method above.
* This method adds the key-value pairs similar to the config. These assignments are manatory, and blocks that are
* registered will be locked to the specified mover, and it cannot be changed from the config. This method must be
* called during FML pre-initialization.
*
* @param key The mod or block key regex. This works the same way it does from the
* config file:
* Possible keys:
* default - to assign default mover
* mod:<modID> - to assign every block from a mod
* <modID>:<blockname> - to assign block from a mod for every meta
* <modID>:<blockname>m<meta> - to assign block from mod for specific meta
* @param key The mod or block key regex. This works the same way it does from the config file: Possible keys:
* default - to assign default mover mod:<modID> - to assign every block from a mod <modID>:<blockname>
* - to assign block from a mod for every meta <modID>:<blockname>m<meta> - to assign block from mod
* for specific meta
*
* @param value The name of the mover to assign this block. A list of all available
* movers will show up in the configs.
* @param value The name of the mover to assign this block. A list of all available movers will show up in the
* configs.
*/
public abstract void registerMandatoryMover(String key, String value);
/**
* Getter for the global Relocator object which is what is used
* to actually initiate movements.
* Getter for the global Relocator object which is what is used to actually initiate movements.
*
* @return The Relocator object
*/
public abstract Relocator getRelocator();
/**
* Used to check if the given block is currently moving. This method is
* client and server safe.
* Used to check if the given block is currently moving. This method is client and server safe.
*
* @param world The world the block is in.
* @param x The x coordinate of the block.
* @param y The y coordinate of the block.
* @param z The z coordinate of the block.
* @param x The x coordinate of the block.
* @param y The y coordinate of the block.
* @param z The z coordinate of the block.
*
* @return True if the block is currently moving.
*/
@@ -1,27 +1,25 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2015. Created by MrTJP. All rights reserved.
*/
package mrtjp.relocation.api;
import java.util.Set;
import net.minecraft.world.World;
/**
* Helper class used to queue and execute the movement of a set of blocks.
* See {@link mrtjp.mcframes.TileMotor} for usage.
* Helper class used to queue and execute the movement of a set of blocks. See {@link mrtjp.mcframes.TileMotor} for
* usage.
*/
public abstract class Relocator {
/**
* Pushes an instance of the Relocator onto the stack.
* Must be called before using any methods.
* Pushes an instance of the Relocator onto the stack. Must be called before using any methods.
*/
public abstract void push();
/**
* Pops the instance of the Relocator off the stack.
* Must be called after you are done using this.
* Pops the instance of the Relocator off the stack. Must be called after you are done using this.
*
* @throws IllegalStateException If there is no Relocator on the stack.
*/
@@ -36,8 +34,7 @@ public abstract class Relocator {
public abstract void setWorld(World world);
/**
* Sets the direction towards which all the queued blocks will move.
* This is a ForgeDirection index, from 0 to 5
* Sets the direction towards which all the queued blocks will move. This is a ForgeDirection index, from 0 to 5
*
* @param dir The direction to move the blocks.
*
@@ -47,8 +44,7 @@ public abstract class Relocator {
public abstract void setDirection(int dir);
/**
* Sets the speed of the movement. Must be greater than 0 and
* less than 1.
* Sets the speed of the movement. Must be greater than 0 and less than 1.
*
* @param speed The speed of the movement, in meters/tick.
*
@@ -58,8 +54,8 @@ public abstract class Relocator {
public abstract void setSpeed(double speed);
/**
* Sets a callback object that receives events during the actual move.
* This is optional and is not required to be set.
* Sets a callback object that receives events during the actual move. This is optional and is not required to be
* set.
*
* @param callback The callback to register for this move.
*
@@ -80,14 +76,12 @@ public abstract class Relocator {
public abstract void addBlocks(Set<BlockPos> blocks);
/**
* Used to execute the queued movement. Before calling, the world, direction,
* and queue of blocks must be set.
* Used to execute the queued movement. Before calling, the world, direction, and queue of blocks must be set.
*
* @return True if the movement was successfully started.
*
* @throws IllegalStateException If the Relocator is not on the stack.
* @throws IllegalStateException If any of the required parameters are not set
* or are invalid.
* @throws IllegalStateException If any of the required parameters are not set or are invalid.
*/
public abstract boolean execute();
}
@@ -1,10 +1,9 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
* Copyright (c) 2015. Created by MrTJP. All rights reserved.
*/
@API(owner = "ForgeRelocation", provides = "ForgeRelocation|API", apiVersion = "GRADLETOKEN_VERSION")
@API(owner = "ForgeRelocation", provides = "ForgeRelocation|API", apiVersion = Tags.VERSION)
package mrtjp.relocation.api;
import cpw.mods.fml.common.API;
import mrtjp.relocation.Tags;
@@ -0,0 +1,19 @@
package mrtjp.relocation.asm
import java.util.{Map => JMap}
import cpw.mods.fml.relauncher.IFMLLoadingPlugin
@IFMLLoadingPlugin.MCVersion("1.7.10")
@IFMLLoadingPlugin.TransformerExclusions(value =
Array("mrtjp.relocation.asm.*", "scala")
)
class RelocationPlugin extends IFMLLoadingPlugin {
override def getASMTransformerClass = Array(
"mrtjp.relocation.asm.Transformer"
)
override def getSetupClass = null
override def getModContainerClass = null
override def getAccessTransformerClass = null
override def injectData(data: JMap[String, AnyRef]): Unit = {}
}
@@ -5,10 +5,9 @@
*/
package mrtjp.relocation.asm
import java.util.{Map => JMap}
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper.{INSTANCE => mapper}
import cpw.mods.fml.relauncher.{IFMLCallHook, IFMLLoadingPlugin}
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper.{
INSTANCE => mapper
}
import mrtjp.relocation.handler.RelocationMod
import net.minecraft.launchwrapper.{IClassTransformer, Launch}
import org.objectweb.asm.Opcodes._
@@ -17,92 +16,91 @@ import org.objectweb.asm.{ClassReader, ClassWriter}
import scala.collection.JavaConversions._
/**
* Add "Dfml.coreMods.load=mrtjp.relocation.asm.RelocationPlugin" to launch configs
* to enable in a development workspace.
*/
@IFMLLoadingPlugin.MCVersion("1.7.10")
@IFMLLoadingPlugin.TransformerExclusions(value = Array("mrtjp.relocation.asm.*", "scala"))
class RelocationPlugin extends IFMLLoadingPlugin with IFMLCallHook
{
override def getASMTransformerClass = Array("mrtjp.relocation.asm.Transformer")
override def getSetupClass = "mrtjp.relocation.asm.RelocationPlugin"
override def getModContainerClass = null
override def getAccessTransformerClass = null
override def injectData(data:JMap[String, AnyRef]): Unit ={}
override def call():Void = null
}
class Transformer extends IClassTransformer {
type MethodChecker = (String, MethodNode) => Boolean
type InsTransformer = MethodNode => Unit
class Transformer extends IClassTransformer
{
type MethodChecker = (String, MethodNode) => Boolean
type InsTransformer = MethodNode => Unit
lazy val deobfEnv =
(Launch.blackboard get "fml.deobfuscatedEnvironment").asInstanceOf[Boolean]
lazy val blockClass = mapper.unmap("net/minecraft/block/Block")
lazy val teClass = mapper.unmap("net/minecraft/tileentity/TileEntity")
lazy val deobfEnv = (Launch.blackboard get "fml.deobfuscatedEnvironment").asInstanceOf[Boolean]
lazy val blockClass = mapper.unmap("net/minecraft/block/Block")
lazy val teClass = mapper.unmap("net/minecraft/tileentity/TileEntity")
def transformBlockRender(m:MethodNode)
{
val old = m.instructions.toArray.collectFirst{ case i:MethodInsnNode => i }.get
val list = new InsnList
list.add(new VarInsnNode(ILOAD, 2))
list.add(new VarInsnNode(ILOAD, 3))
list.add(new VarInsnNode(ILOAD, 4))
list.add(new MethodInsnNode(INVOKESTATIC, "mrtjp/relocation/ASMHacks",
"getRenderType", "(Lnet/minecraft/block/Block;III)I", false))
m.instructions.insert(old, list)
m.instructions.remove(old)
}
def transformTERender(m:MethodNode)
{
val old = m.instructions.toArray.collect{ case i:MethodInsnNode => i }.last
m.instructions.insert(old, new InsnNode(POP))
m.instructions.insert(old, new MethodInsnNode(INVOKESTATIC,
"mrtjp/relocation/ASMHacks", "renderTileEntityAt", old.desc, false))
m.instructions.remove(old)
}
val classData = Map[String, (MethodChecker, MethodChecker, InsTransformer)](
"net.minecraft.client.renderer.RenderBlocks" -> ((
(_:String, m:MethodNode) => m.name == "renderBlockByRenderType",
(n:String, m:MethodNode) => mapper.mapMethodName(n, m.name, m.desc) == "func_147805_b",
transformBlockRender _
)),
"net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher" -> ((
(_:String, m:MethodNode) => m.name == "renderTileEntity",
(n:String, m:MethodNode) => mapper.mapMethodName(n, m.name, m.desc) == "func_147544_a",
transformTERender _
))
def transformBlockRender(m: MethodNode) {
val old = m.instructions.toArray.collectFirst { case i: MethodInsnNode =>
i
}.get
val list = new InsnList
list.add(new VarInsnNode(ILOAD, 2))
list.add(new VarInsnNode(ILOAD, 3))
list.add(new VarInsnNode(ILOAD, 4))
list.add(
new MethodInsnNode(
INVOKESTATIC,
"mrtjp/relocation/ASMHacks",
"getRenderType",
"(Lnet/minecraft/block/Block;III)I",
false
)
)
m.instructions.insert(old, list)
m.instructions.remove(old)
}
var matched = Set[String]()
def transformTERender(m: MethodNode) {
val old = m.instructions.toArray.collect { case i: MethodInsnNode =>
i
}.last
m.instructions.insert(old, new InsnNode(POP))
m.instructions.insert(
old,
new MethodInsnNode(
INVOKESTATIC,
"mrtjp/relocation/ASMHacks",
"renderTileEntityAt",
old.desc,
false
)
)
m.instructions.remove(old)
}
override def transform(name:String, tName:String, data:Array[Byte]) =
{
if (classData.keys.contains(tName) && !matched.contains(tName))
{
RelocationMod.log.info(s"transforming: $tName")
val (ch1, ch2, tr) = classData(tName)
val classData = Map[String, (MethodChecker, MethodChecker, InsTransformer)](
"net.minecraft.client.renderer.RenderBlocks" -> ((
(_: String, m: MethodNode) => m.name == "renderBlockByRenderType",
(n: String, m: MethodNode) =>
mapper.mapMethodName(n, m.name, m.desc) == "func_147805_b",
transformBlockRender _
)),
"net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher" -> ((
(_: String, m: MethodNode) => m.name == "renderTileEntity",
(n: String, m: MethodNode) =>
mapper.mapMethodName(n, m.name, m.desc) == "func_147544_a",
transformTERender _
))
)
val node = new ClassNode
val reader = new ClassReader(data)
reader.accept(node, 0)
var matched = Set[String]()
for (m@(_m:MethodNode) <- node.methods)
if ((deobfEnv && ch1(name, m)) || (!deobfEnv && ch2(name, m)))
{
RelocationMod.log.info(s"$name $tName ${m.name} ${m.desc}")
tr(m)
}
override def transform(name: String, tName: String, data: Array[Byte]) = {
if (classData.keys.contains(tName) && !matched.contains(tName)) {
RelocationMod.log.info(s"transforming: $tName")
val (ch1, ch2, tr) = classData(tName)
matched += tName
val node = new ClassNode
val reader = new ClassReader(data)
reader.accept(node, 0)
val writer = new ClassWriter(ClassWriter.COMPUTE_MAXS)
node.accept(writer)
writer.toByteArray
for (m @ (_m: MethodNode) <- node.methods)
if ((deobfEnv && ch1(name, m)) || (!deobfEnv && ch2(name, m))) {
RelocationMod.log.info(s"$name $tName ${m.name} ${m.desc}")
tr(m)
}
else data
}
matched += tName
val writer = new ClassWriter(ClassWriter.COMPUTE_MAXS)
node.accept(writer)
writer.toByteArray
} else data
}
}
+58 -64
View File
@@ -18,75 +18,69 @@ import net.minecraft.world.World
import scala.collection.JavaConversions._
class BlockMovingRow extends InstancedBlock("relocation.blockmovingrow", Material.iron)
{
setHardness(-1F)
setStepSound(Block.soundTypeGravel)
setCreativeTab(null)
addSingleTile(classOf[TileMovingRow])
class BlockMovingRow
extends InstancedBlock("relocation.blockmovingrow", Material.iron) {
setHardness(-1f)
setStepSound(Block.soundTypeGravel)
setCreativeTab(null)
addSingleTile(classOf[TileMovingRow])
}
object TileMovingRow
{
def setBlockForRow(w:World, r:BlockRow)
{
w.setBlock(r.pos.x, r.pos.y, r.pos.z, RelocationMod.blockMovingRow, 0, 3)
}
def getBoxFor(w:World, r:BlockRow, progress:Double):Cuboid6 =
{
val p = r.pos.copy.offset(r.moveDir^1)
val bl = w.getBlock(p.x, p.y, p.z)
if (bl == RelocationMod.blockMovingRow) return Cuboid6.full.copy()
bl.getCollisionBoundingBoxFromPool(w, p.x, p.y, p.z) match
{
case aabb:AxisAlignedBB => new Cuboid6(aabb).sub(new Vector3(r.pos))
.add(new Vector3(BlockCoord.sideOffsets(r.moveDir))*progress)
case _ => Cuboid6.full.copy
}
object TileMovingRow {
def setBlockForRow(w: World, r: BlockRow) {
w.setBlock(r.pos.x, r.pos.y, r.pos.z, RelocationMod.blockMovingRow, 0, 3)
}
def getBoxFor(w: World, r: BlockRow, progress: Double): Cuboid6 = {
val p = r.pos.copy.offset(r.moveDir ^ 1)
val bl = w.getBlock(p.x, p.y, p.z)
if (bl == RelocationMod.blockMovingRow) return Cuboid6.full.copy()
bl.getCollisionBoundingBoxFromPool(w, p.x, p.y, p.z) match {
case aabb: AxisAlignedBB =>
new Cuboid6(aabb)
.sub(new Vector3(r.pos))
.add(new Vector3(BlockCoord.sideOffsets(r.moveDir)) * progress)
case _ => Cuboid6.full.copy
}
}
}
class TileMovingRow extends InstancedBlockTile
{
var prevProg = 0.0
class TileMovingRow extends InstancedBlockTile {
var prevProg = 0.0
override def update()
{
if (!MovementManager2.isMoving(world, x, y, z)) world.setBlockToAir(x, y, z)
override def update() {
if (!MovementManager2.isMoving(world, x, y, z)) world.setBlockToAir(x, y, z)
}
override def getBlock = RelocationMod.blockMovingRow
override def getBlockBounds = {
val s = MovementManager2.getEnclosedStructure(world, x, y, z)
if (s != null) {
val r = s.rows.find(_.contains(x, y, z)).get
TileMovingRow.getBoxFor(world, r, s.progress)
} else Cuboid6.full
}
override def getCollisionBounds = getBlockBounds
def pushEntities(r: BlockRow, progress: Double) {
val box = Cuboid6.full.copy
.add(new Vector3(r.preMoveBlocks.head))
.add(new Vector3(BlockCoord.sideOffsets(r.moveDir)).multiply(progress))
.toAABB
val dp = (if (progress >= 1.0) progress + 0.1 else progress) - prevProg
val d = new Vector3(BlockCoord.sideOffsets(r.moveDir)) * dp
world.getEntitiesWithinAABBExcludingEntity(null, box) match {
case list: JList[_] =>
for (e <- list.asInstanceOf[JList[Entity]])
e.moveEntity(d.x, d.y max 0, d.z)
case _ =>
}
override def getBlock = RelocationMod.blockMovingRow
override def getBlockBounds =
{
val s = MovementManager2.getEnclosedStructure(world, x, y, z)
if (s != null)
{
val r = s.rows.find(_.contains(x, y, z)).get
TileMovingRow.getBoxFor(world, r, s.progress)
}
else Cuboid6.full
}
override def getCollisionBounds = getBlockBounds
def pushEntities(r:BlockRow, progress:Double)
{
val box = Cuboid6.full.copy.add(new Vector3(r.preMoveBlocks.head))
.add(new Vector3(BlockCoord.sideOffsets(r.moveDir)).multiply(progress)).toAABB
val dp = (if (progress >= 1.0) progress+0.1 else progress)-prevProg
val d = new Vector3(BlockCoord.sideOffsets(r.moveDir))*dp
world.getEntitiesWithinAABBExcludingEntity(null, box) match
{
case list:JList[_] =>
for (e <- list.asInstanceOf[JList[Entity]]) e.moveEntity(d.x, d.y max 0, d.z)
case _ =>
}
prevProg = progress
}
}
prevProg = progress
}
}
+38 -46
View File
@@ -11,58 +11,50 @@ import mrtjp.relocation.handler.RelocationSPH
import net.minecraftforge.client.event.RenderWorldLastEvent
import net.minecraftforge.event.world.{ChunkWatchEvent, WorldEvent}
object RelocationEventHandler
{
@SubscribeEvent
def worldUnload(event:WorldEvent.Unload)
{
RelocationSPH.onWorldUnload(event.world)
MovementManager2.onWorldUnload(event.world)
}
object RelocationEventHandler {
@SubscribeEvent
def worldUnload(event: WorldEvent.Unload) {
RelocationSPH.onWorldUnload(event.world)
MovementManager2.onWorldUnload(event.world)
}
@SubscribeEvent
def chunkWatch(event:ChunkWatchEvent.Watch)
{
RelocationSPH.onChunkWatch(event.player, event.chunk)
}
@SubscribeEvent
def chunkWatch(event: ChunkWatchEvent.Watch) {
RelocationSPH.onChunkWatch(event.player, event.chunk)
}
@SubscribeEvent
def chunkUnwatch(event:ChunkWatchEvent.UnWatch)
{
RelocationSPH.onChunkUnWatch(event.player, event.chunk)
}
@SubscribeEvent
def chunkUnwatch(event: ChunkWatchEvent.UnWatch) {
RelocationSPH.onChunkUnWatch(event.player, event.chunk)
}
@SubscribeEvent
def serverTick(event:TickEvent.ServerTickEvent)
{
if (event.phase == TickEvent.Phase.END)
{
RelocationSPH.onTickEnd()
MovementManager2.onTick(false)
}
@SubscribeEvent
def serverTick(event: TickEvent.ServerTickEvent) {
if (event.phase == TickEvent.Phase.END) {
RelocationSPH.onTickEnd()
MovementManager2.onTick(false)
}
}
}
object RelocationClientEventHandler
{
@SubscribeEvent
def onRenderTick(e:TickEvent.RenderTickEvent)
{
if (e.phase == TickEvent.Phase.START)
MovingRenderer.onPreRenderTick(e.renderTickTime)
else MovingRenderer.onPostRenderTick()
}
object RelocationClientEventHandler {
@SubscribeEvent
def onRenderTick(e: TickEvent.RenderTickEvent) {
if (e.phase == TickEvent.Phase.START)
MovingRenderer.onPreRenderTick(e.renderTickTime)
else MovingRenderer.onPostRenderTick()
}
@SubscribeEvent
def onRenderWorld(e:RenderWorldLastEvent)
{
MovingRenderer.onRenderWorldEvent()
}
@SubscribeEvent
def onRenderWorld(e: RenderWorldLastEvent) {
MovingRenderer.onRenderWorldEvent()
}
@SubscribeEvent
def clientTick(event:TickEvent.ClientTickEvent)
{
if (event.phase == TickEvent.Phase.END)
MovementManager2.onTick(true)
@SubscribeEvent
def clientTick(event: TickEvent.ClientTickEvent) {
if (event.phase == TickEvent.Phase.END) {
MovementManager2.onTick(true)
MovingRenderer.onTick()
}
}
}
}
+48 -23
View File
@@ -12,28 +12,53 @@ import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher
import net.minecraft.tileentity.TileEntity
object ASMHacks
{
@SideOnly(Side.CLIENT)
def renderTileEntityAt(te:TileEntity, x:Double, y:Double, z:Double, tick:Float):Unit =
{
if (MovementManager2.isMoving(te.getWorldObj, te.xCoord, te.yCoord, te.zCoord))
{
val s = MovementManager2.getEnclosedStructure(te.getWorldObj, te.xCoord, te.yCoord, te.zCoord)
val vec = MovingRenderer.renderPos(s, tick)
object ASMHacks {
@SideOnly(Side.CLIENT)
def renderTileEntityAt(
te: TileEntity,
x: Double,
y: Double,
z: Double,
tick: Float
): Unit = {
if (
MovementManager2.isMoving(te.getWorldObj, te.xCoord, te.yCoord, te.zCoord)
) {
val s = MovementManager2.getEnclosedStructure(
te.getWorldObj,
te.xCoord,
te.yCoord,
te.zCoord
)
val vec = MovingRenderer.renderPos(s, tick)
TileEntityRendererDispatcher.instance.renderTileEntityAt(te,
x+MathLib.clamp(-1F, 1F, vec.x.toFloat),
y+MathLib.clamp(-1F, 1F, vec.y.toFloat),
z+MathLib.clamp(-1F, 1F, vec.z.toFloat), tick)
}
else TileEntityRendererDispatcher.instance.renderTileEntityAt(te, x, y, z, tick)
}
TileEntityRendererDispatcher.instance.renderTileEntityAt(
te,
x + MathLib.clamp(-1f, 1f, vec.x.toFloat),
y + MathLib.clamp(-1f, 1f, vec.y.toFloat),
z + MathLib.clamp(-1f, 1f, vec.z.toFloat),
tick
)
} else
TileEntityRendererDispatcher.instance.renderTileEntityAt(
te,
x,
y,
z,
tick
)
}
@SideOnly(Side.CLIENT)
def getRenderType(block:Block, x:Int, y:Int, z:Int):Int =
{
if (MovingRenderer.renderHack && MovementManager2.isMoving(Minecraft.getMinecraft.theWorld, x, y, z)) -1
else block.getRenderType
}
}
@SideOnly(Side.CLIENT)
def getRenderType(block: Block, x: Int, y: Int, z: Int): Int = {
if (
MovingRenderer.renderHack && MovementManager2.isMoving(
Minecraft.getMinecraft.theWorld,
x,
y,
z
)
) -1
else block.getRenderType
}
}
@@ -9,30 +9,30 @@ import mrtjp.relocation.api.{ITileMover, RelocationAPI}
import mrtjp.relocation.{MovementManager2, MovingTileRegistry}
import net.minecraft.world.World
object RelocationAPI_Impl extends RelocationAPI
{
var isPreInit = true
object RelocationAPI_Impl extends RelocationAPI {
var isPreInit = true
override def registerTileMover(name:String, desc:String, handler:ITileMover) =
{
assert(isPreInit)
MovingTileRegistry.registerTileMover(name, desc, handler)
}
override def registerTileMover(
name: String,
desc: String,
handler: ITileMover
) = {
assert(isPreInit)
MovingTileRegistry.registerTileMover(name, desc, handler)
}
override def registerPreferredMover(key:String, value:String)
{
assert(isPreInit)
MovingTileRegistry.preferredMovers :+= (key, value)
}
override def registerPreferredMover(key: String, value: String) {
assert(isPreInit)
MovingTileRegistry.preferredMovers :+= (key, value)
}
override def registerMandatoryMover(key:String, value:String)
{
assert(isPreInit)
MovingTileRegistry.mandatoryMovers :+= (key, value)
}
override def registerMandatoryMover(key: String, value: String) {
assert(isPreInit)
MovingTileRegistry.mandatoryMovers :+= (key, value)
}
override def getRelocator = Relocator_Impl
override def getRelocator = Relocator_Impl
override def isMoving(world:World, x:Int, y:Int, z:Int) =
MovementManager2.isMoving(world, x, y, z)
}
override def isMoving(world: World, x: Int, y: Int, z: Int) =
MovementManager2.isMoving(world, x, y, z)
}
@@ -15,107 +15,108 @@ import net.minecraft.world.World
import scala.collection.JavaConversions._
import scala.collection.mutable.{Set => MSet, Stack => MStack}
class RelocationRun
{
var world:World = null
var dir = -1
var speed = 0.0
var callback:IMovementCallback = null
val blocks = MSet[BlockCoord]()
class RelocationRun {
var world: World = null
var dir = -1
var speed = 0.0
var callback: IMovementCallback = null
val blocks = MSet[BlockCoord]()
def clear()
{
world = null
dir = -1
speed = 0
callback = null
blocks.clear()
}
def clear() {
world = null
dir = -1
speed = 0
callback = null
blocks.clear()
}
}
object Relocator_Impl extends Relocator
{
var mainStack = new MStack[RelocationRun]()
var tempStack = new MStack[RelocationRun]()
object Relocator_Impl extends Relocator {
var mainStack = new MStack[RelocationRun]()
var tempStack = new MStack[RelocationRun]()
private def assertState()
{
if (mainStack.isEmpty) throw new IllegalStateException("Relocator stack is empty.")
}
private def assertState() {
if (mainStack.isEmpty)
throw new IllegalStateException("Relocator stack is empty.")
}
override def push()
{
val r = if (tempStack.isEmpty) new RelocationRun else tempStack.pop()
mainStack.push(r)
}
override def push() {
val r = if (tempStack.isEmpty) new RelocationRun else tempStack.pop()
mainStack.push(r)
}
override def pop()
{
assertState()
val r = mainStack.pop()
r.clear()
tempStack.push(r)
}
override def pop() {
assertState()
val r = mainStack.pop()
r.clear()
tempStack.push(r)
}
override def setWorld(world:World)
{
assertState()
val top = mainStack.top
if (top.world != null) throw new IllegalStateException("World already set.")
top.world = world
}
override def setWorld(world: World) {
assertState()
val top = mainStack.top
if (top.world != null) throw new IllegalStateException("World already set.")
top.world = world
}
override def setDirection(dir:Int)
{
assertState()
val top = mainStack.top
if (top.dir != -1) throw new IllegalStateException("Direction already set.")
top.dir = dir
}
override def setDirection(dir: Int) {
assertState()
val top = mainStack.top
if (top.dir != -1) throw new IllegalStateException("Direction already set.")
top.dir = dir
}
override def setSpeed(speed:Double)
{
assertState()
val top = mainStack.top
if (top.speed > 0) throw new IllegalStateException("Speed already set.")
top.speed = speed
}
override def setSpeed(speed: Double) {
assertState()
val top = mainStack.top
if (top.speed > 0) throw new IllegalStateException("Speed already set.")
top.speed = speed
}
override def setCallback(callback: IMovementCallback) {
assertState()
val top = mainStack.top
if (top.callback != null)
throw new IllegalStateException("Callback already set.")
top.callback = callback
}
override def setCallback(callback:IMovementCallback)
{
assertState()
val top = mainStack.top
if (top.callback != null) throw new IllegalStateException("Callback already set.")
top.callback = callback
}
override def addBlock(x: Int, y: Int, z: Int) {
assertState()
mainStack.top.blocks += new BlockCoord(x, y, z)
}
override def addBlock(x:Int, y:Int, z:Int)
{
assertState()
mainStack.top.blocks += new BlockCoord(x, y, z)
}
override def addBlock(bc: BlockPos) {
addBlock(bc.x, bc.y, bc.z)
}
override def addBlock(bc:BlockPos)
{
addBlock(bc.x, bc.y, bc.z)
}
override def addBlocks(blocks: JSet[BlockPos]) {
for (b <- blocks) addBlock(b)
}
override def addBlocks(blocks:JSet[BlockPos])
{
for (b <- blocks) addBlock(b)
}
override def execute() =
{
assertState()
val top = mainStack.top
if (top.world == null) throw new IllegalStateException("World must be set before move.")
if (top.world.isRemote) throw new IllegalStateException("Movements cannot be executed client-side.")
if (top.dir == -1) throw new IllegalStateException("Direction must be set before move.")
if (top.speed <= 0) throw new IllegalStateException("Speed must be greater than 0.")
if (top.speed >= 1) throw new IllegalStateException("Speed must be less than 1.")
if (top.blocks.isEmpty) throw new IllegalStateException("No blocks queued for move.")
MovementManager2.tryStartMove(top.world, top.blocks.toSet, top.dir, top.speed, top.callback)
}
}
override def execute() = {
assertState()
val top = mainStack.top
if (top.world == null)
throw new IllegalStateException("World must be set before move.")
if (top.world.isRemote)
throw new IllegalStateException(
"Movements cannot be executed client-side."
)
if (top.dir == -1)
throw new IllegalStateException("Direction must be set before move.")
if (top.speed <= 0)
throw new IllegalStateException("Speed must be greater than 0.")
if (top.speed >= 1)
throw new IllegalStateException("Speed must be less than 1.")
if (top.blocks.isEmpty)
throw new IllegalStateException("No blocks queued for move.")
MovementManager2.tryStartMove(
top.world,
top.blocks.toSet,
top.dir,
top.speed,
top.callback
)
}
}
@@ -6,94 +6,109 @@
package mrtjp.relocation.handler
import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.{FMLInitializationEvent, FMLPostInitializationEvent, FMLPreInitializationEvent}
import cpw.mods.fml.common.event.{
FMLInitializationEvent,
FMLPostInitializationEvent,
FMLPreInitializationEvent
}
import mrtjp.core.data.{ModConfig, SpecialConfigGui, TModGuiFactory}
import mrtjp.relocation.api._
import mrtjp.relocation.{BlockMovingRow, MovingTileRegistry}
import mrtjp.relocation.Tags
import net.minecraft.client.gui.GuiScreen
import org.apache.logging.log4j.LogManager
@Mod(modid = RelocationMod.modID, useMetadata = true, modLanguage = "scala", guiFactory = "mrtjp.relocation.handler.GuiConfigFactory", acceptedMinecraftVersions = "[1.7.10]", dependencies = "required-after:MrTJPCoreMod", name = RelocationMod.modName, version = RelocationMod.version)
object RelocationMod
{
RelocationAPI.instance = RelocationAPI_Impl
@Mod(
modid = RelocationMod.modID,
useMetadata = true,
modLanguage = "scala",
guiFactory = "mrtjp.relocation.handler.GuiConfigFactory",
acceptedMinecraftVersions = "[1.7.10]",
dependencies = "required-after:MrTJPCoreMod",
name = RelocationMod.modName,
version = RelocationMod.version
)
object RelocationMod {
RelocationAPI.instance = RelocationAPI_Impl
final val modID = "ForgeRelocation"
final val modName = "ForgeRelocation"
final val version = "GRADLETOKEN_VERSION"
final val modID = "ForgeRelocation"
final val modName = "ForgeRelocation"
final val version = Tags.VERSION
val log = LogManager.getFormatterLogger(modID)
val log = LogManager.getFormatterLogger(modID)
var blockMovingRow:BlockMovingRow = _
var blockMovingRow: BlockMovingRow = _
@Mod.EventHandler
def preInit(event:FMLPreInitializationEvent)
{
RelocationProxy.preinit()
}
@Mod.EventHandler
def preInit(event: FMLPreInitializationEvent) {
RelocationProxy.preinit()
}
@Mod.EventHandler
def init(event:FMLInitializationEvent)
{
RelocationAPI_Impl.isPreInit = false
RelocationConfig.loadConfig()
RelocationProxy.init()
}
@Mod.EventHandler
def init(event: FMLInitializationEvent) {
RelocationAPI_Impl.isPreInit = false
RelocationConfig.loadConfig()
RelocationProxy.init()
}
@Mod.EventHandler
def postInit(event:FMLPostInitializationEvent)
{
RelocationProxy.postinit()
}
@Mod.EventHandler
def postInit(event: FMLPostInitializationEvent) {
RelocationProxy.postinit()
}
}
class RelocationConfigGui(parent:GuiScreen) extends SpecialConfigGui(parent, "ForgeRelocation", RelocationConfig.config)
class GuiConfigFactory extends TModGuiFactory
{
override def mainConfigGuiClass() = classOf[RelocationConfigGui]
class RelocationConfigGui(parent: GuiScreen)
extends SpecialConfigGui(parent, "ForgeRelocation", RelocationConfig.config)
class GuiConfigFactory extends TModGuiFactory {
override def mainConfigGuiClass() = classOf[RelocationConfigGui]
}
object RelocationConfig extends ModConfig("ForgeRelocation")
{
var moveLimit = 2048
object RelocationConfig extends ModConfig("ForgeRelocation") {
var moveLimit = 2048
var moverMap = Array(
"default -> saveload"
var moverMap = Array(
"default -> saveload"
)
override protected def initValues() {
val general = new BaseCategory("General", "Basic settings")
moveLimit = general.put(
"moveLimit",
moveLimit,
"Maximum amount of blocks that can be moved at once."
)
override protected def initValues()
{
val general = new BaseCategory("General", "Basic settings")
moveLimit = general.put("moveLimit", moveLimit, "Maximum amount of blocks that can be moved at once.")
val movers = new BaseCategory("Tile Movers", buildMoverDesc)
moverMap = movers.put("mover registry", moverMap)
moverMap = movers.put(
"mover registry",
MovingTileRegistry.parseAndSetMovers(moverMap),
true
)
}
val movers = new BaseCategory("Tile Movers", buildMoverDesc)
moverMap = movers.put("mover registry", moverMap)
moverMap = movers.put("mover registry", MovingTileRegistry.parseAndSetMovers(moverMap), true)
def buildMoverDesc: String = {
var s =
"Used to configure which registered Tile Mover is used for a block. Key-Value pairs are defined using \n" +
"the syntax key -> value. \n"
s += "Most blocks are configurable, but some mods may have opted to lock which handlers can be used for its \n" +
"blocks.\n"
s += "Possible keys: \n"
s += " 'default' - to assign default handler. \n"
s += " 'mod:<modID>' - to assign every block from a mod. \n"
s += " '<modID>:<blockname>' - to assign block from a mod for every meta. \n"
s += " '<modID>:<blockname>m<meta>' - to assign block from mod for specific meta. \n"
s += "\nAvailable tile movers:\n"
for ((k, v) <- MovingTileRegistry.moverDescMap)
s += " '" + k + "' - " + v + "\n"
if (MovingTileRegistry.mandatoryMovers.nonEmpty) {
s += "\nMovers locked via API:\n"
for ((k, v) <- MovingTileRegistry.mandatoryMovers)
s += " " + k + " -> " + v + "\n"
}
def buildMoverDesc:String =
{
var s = "Used to configure which registered Tile Mover is used for a block. Key-Value pairs are defined using \n" +
"the syntax key -> value. \n"
s += "Most blocks are configurable, but some mods may have opted to lock which handlers can be used for its \n" +
"blocks.\n"
s += "Possible keys: \n"
s += " 'default' - to assign default handler. \n"
s += " 'mod:<modID>' - to assign every block from a mod. \n"
s += " '<modID>:<blockname>' - to assign block from a mod for every meta. \n"
s += " '<modID>:<blockname>m<meta>' - to assign block from mod for specific meta. \n"
s += "\nAvailable tile movers:\n"
for ((k, v) <- MovingTileRegistry.moverDescMap)
s += " '"+k+"' - "+v+"\n"
if (MovingTileRegistry.mandatoryMovers.nonEmpty)
{
s += "\nMovers locked via API:\n"
for ((k, v) <- MovingTileRegistry.mandatoryMovers)
s += " "+k+" -> "+v+"\n"
}
s
}
s
}
}
@@ -10,7 +10,10 @@ import java.util.{LinkedList => JLinkedList, List => JList}
import codechicken.lib.data.MCDataOutputWrapper
import codechicken.lib.packet.PacketCustom
import codechicken.lib.packet.PacketCustom.{IClientPacketHandler, IServerPacketHandler}
import codechicken.lib.packet.PacketCustom.{
IClientPacketHandler,
IServerPacketHandler
}
import mrtjp.relocation.MovementManager2
import net.minecraft.client.Minecraft
import net.minecraft.entity.player.{EntityPlayer, EntityPlayerMP}
@@ -21,163 +24,168 @@ import net.minecraft.util.ChatComponentText
import net.minecraft.world.{ChunkCoordIntPair, World}
import scala.collection.JavaConversions._
import scala.collection.mutable.{HashMap => MHashMap, Map => MMap, MultiMap => MMultiMap, Set => MSet}
/**
* Tweaked version of Chickenbones' compressed end-of-tick tile data stream.
*/
class RelocationPH
{
val channel = RelocationMod
import scala.collection.mutable.{
HashMap => MHashMap,
Map => MMap,
MultiMap => MMultiMap,
Set => MSet
}
object RelocationCPH extends RelocationPH with IClientPacketHandler
{
def handlePacket(packet: PacketCustom, mc: Minecraft, netHandler:INetHandlerPlayClient) {
try {
packet.getType match {
case 1 => handleChunkDesc(packet, mc.theWorld)
case 2 => handleChunkData(packet, mc.theWorld)
}
}
catch {
case e:RuntimeException if e.getMessage.startsWith("DC: ") =>
netHandler.handleDisconnect(new S40PacketDisconnect(new ChatComponentText(e.getMessage.substring(4))))
}
}
def handleChunkData(packet:PacketCustom, world:World)
{
var i = packet.readUByte()
while (i != 255) {
MovementManager2.read(world, packet, i)
i = packet.readUByte()
}
}
def handleChunkDesc(packet:PacketCustom, world:World)
{
MovementManager2.readDesc(world, packet)
}
/** Tweaked version of Chickenbones' compressed end-of-tick tile data stream.
*/
class RelocationPH {
val channel = RelocationMod
}
object RelocationSPH extends RelocationPH with IServerPacketHandler
{
class MCByteStream(bout:ByteArrayOutputStream) extends MCDataOutputWrapper(new DataOutputStream(bout))
{
def getBytes = bout.toByteArray
object RelocationCPH extends RelocationPH with IClientPacketHandler {
def handlePacket(
packet: PacketCustom,
mc: Minecraft,
netHandler: INetHandlerPlayClient
) {
try {
packet.getType match {
case 1 => handleChunkDesc(packet, mc.theWorld)
case 2 => handleChunkData(packet, mc.theWorld)
}
} catch {
case e: RuntimeException if e.getMessage.startsWith("DC: ") =>
netHandler.handleDisconnect(
new S40PacketDisconnect(
new ChatComponentText(e.getMessage.substring(4))
)
)
}
}
override def handlePacket(packetCustom:PacketCustom, entityPlayerMP:EntityPlayerMP, iNetHandlerPlayServer:INetHandlerPlayServer){}
def handleChunkData(packet: PacketCustom, world: World) {
var i = packet.readUByte()
while (i != 255) {
MovementManager2.read(world, packet, i)
i = packet.readUByte()
}
}
private val updateMap = MMap[World, MMap[Set[ChunkCoordIntPair], MCByteStream]]()
private val chunkWatchers = new MHashMap[Int, MSet[ChunkCoordIntPair]] with MMultiMap[Int, ChunkCoordIntPair]
private val newWatchers = MMap[Int, JLinkedList[ChunkCoordIntPair]]()
def handleChunkDesc(packet: PacketCustom, world: World) {
MovementManager2.readDesc(world, packet)
}
}
def onTickEnd()
{
object RelocationSPH extends RelocationPH with IServerPacketHandler {
class MCByteStream(bout: ByteArrayOutputStream)
extends MCDataOutputWrapper(new DataOutputStream(bout)) {
def getBytes = bout.toByteArray
}
override def handlePacket(
packetCustom: PacketCustom,
entityPlayerMP: EntityPlayerMP,
iNetHandlerPlayServer: INetHandlerPlayServer
) {}
private val updateMap =
MMap[World, MMap[Set[ChunkCoordIntPair], MCByteStream]]()
private val chunkWatchers = new MHashMap[Int, MSet[ChunkCoordIntPair]]
with MMultiMap[Int, ChunkCoordIntPair]
private val newWatchers = MMap[Int, JLinkedList[ChunkCoordIntPair]]()
def onTickEnd() {
val players = getServerPlayers
sendData(players)
sendDesc(players)
}
def onWorldUnload(world: World) {
if (!world.isRemote) {
updateMap.remove(world)
if (chunkWatchers.nonEmpty) {
val players = getServerPlayers
sendData(players)
sendDesc(players)
for (p <- players)
if (p.worldObj.provider.dimensionId == world.provider.dimensionId)
chunkWatchers.remove(p.getEntityId)
}
}
}
def onWorldUnload(world:World)
{
if(!world.isRemote)
{
updateMap.remove(world)
if (chunkWatchers.nonEmpty)
{
val players = getServerPlayers
for (p <- players) if (p.worldObj.provider.dimensionId == world.provider.dimensionId)
chunkWatchers.remove(p.getEntityId)
}
def onChunkWatch(p: EntityPlayer, c: ChunkCoordIntPair) {
newWatchers.getOrElseUpdate(p.getEntityId, new JLinkedList).add(c)
}
def onChunkUnWatch(p: EntityPlayer, c: ChunkCoordIntPair) {
newWatchers.get(p.getEntityId) match {
case Some(chunks) => chunks.remove(c)
case _ =>
}
chunkWatchers.removeBinding(p.getEntityId, c)
}
private def getServerPlayers: Seq[EntityPlayerMP] =
MinecraftServer.getServer.getConfigurationManager.playerEntityList
.asInstanceOf[JList[EntityPlayerMP]]
private def sendData(players: Seq[EntityPlayerMP]) {
for (p <- players if chunkWatchers.containsKey(p.getEntityId)) {
updateMap.get(p.worldObj) match {
case Some(m) if m.nonEmpty =>
val chunks = chunkWatchers(p.getEntityId)
val packet = new PacketCustom(channel, 2).compress()
var send = false
for ((uchunks, stream) <- m if uchunks.exists(chunks.contains)) {
send = true
packet.writeByteArray(stream.getBytes)
packet.writeByte(255) // terminator
}
if (send) packet.sendToPlayer(p)
case _ =>
}
}
updateMap.foreach(_._2.clear())
}
private def sendDesc(players: Seq[EntityPlayerMP]) {
for (p <- players if newWatchers.containsKey(p.getEntityId)) {
val watched = newWatchers(p.getEntityId)
val pkt = getDescPacket(p.worldObj, watched.toSet)
if (pkt != null) pkt.sendToPlayer(p)
for (c <- watched)
chunkWatchers.addBinding(p.getEntityId, c)
}
newWatchers.clear()
}
private def getDescPacket(
world: World,
chunks: Set[ChunkCoordIntPair]
): PacketCustom = {
val packet = new PacketCustom(channel, 1)
if (MovementManager2.writeDesc(world, chunks, packet)) packet else null
}
def forceSendData() {
sendData(getServerPlayers)
}
def forceSendDesc() {
sendDesc(getServerPlayers)
}
def getStream(world: World, chunks: Set[ChunkCoordIntPair], key: Int) = {
updateMap
.getOrElseUpdate(
world, {
if (world.isRemote)
throw new IllegalArgumentException(
"Cannot use RelocationSPH on a client world"
)
MMap()
}
}
def onChunkWatch(p:EntityPlayer, c:ChunkCoordIntPair)
{
newWatchers.getOrElseUpdate(p.getEntityId, new JLinkedList).add(c)
}
def onChunkUnWatch(p:EntityPlayer, c:ChunkCoordIntPair)
{
newWatchers.get(p.getEntityId) match
{
case Some(chunks) => chunks.remove(c)
case _ =>
)
.getOrElseUpdate(
chunks, {
val s = new MCByteStream(new ByteArrayOutputStream)
s.writeByte(key)
s
}
chunkWatchers.removeBinding(p.getEntityId, c)
}
private def getServerPlayers:Seq[EntityPlayerMP] =
MinecraftServer.getServer.getConfigurationManager.playerEntityList
.asInstanceOf[JList[EntityPlayerMP]]
private def sendData(players:Seq[EntityPlayerMP])
{
for(p <- players if chunkWatchers.containsKey(p.getEntityId))
{
updateMap.get(p.worldObj) match
{
case Some(m) if m.nonEmpty =>
val chunks = chunkWatchers(p.getEntityId)
val packet = new PacketCustom(channel, 2).compress()
var send = false
for((uchunks, stream) <- m if uchunks.exists(chunks.contains))
{
send = true
packet.writeByteArray(stream.getBytes)
packet.writeByte(255) //terminator
}
if(send) packet.sendToPlayer(p)
case _ =>
}
}
updateMap.foreach(_._2.clear())
}
private def sendDesc(players:Seq[EntityPlayerMP])
{
for(p <- players if newWatchers.containsKey(p.getEntityId))
{
val watched = newWatchers(p.getEntityId)
val pkt = getDescPacket(p.worldObj, watched.toSet)
if(pkt != null) pkt.sendToPlayer(p)
for(c <- watched)
chunkWatchers.addBinding(p.getEntityId, c)
}
newWatchers.clear()
}
private def getDescPacket(world:World, chunks:Set[ChunkCoordIntPair]):PacketCustom =
{
val packet = new PacketCustom(channel, 1)
if(MovementManager2.writeDesc(world, chunks, packet)) packet else null
}
def forceSendData()
{
sendData(getServerPlayers)
}
def forceSendDesc()
{
sendDesc(getServerPlayers)
}
def getStream(world:World, chunks:Set[ChunkCoordIntPair], key:Int) =
{
updateMap.getOrElseUpdate(world,
{
if(world.isRemote)
throw new IllegalArgumentException("Cannot use RelocationSPH on a client world")
MMap()
}).getOrElseUpdate(chunks,
{
val s = new MCByteStream(new ByteArrayOutputStream)
s.writeByte(key)
s
})
}
}
)
}
}
@@ -12,66 +12,66 @@ import mrtjp.relocation._
import mrtjp.relocation.api.RelocationAPI.{instance => API}
import net.minecraftforge.common.MinecraftForge
class RelocationProxy_server
{
def preinit()
{
RelocationMod.blockMovingRow = new BlockMovingRow
class RelocationProxy_server {
def preinit() {
RelocationMod.blockMovingRow = new BlockMovingRow
API.registerTileMover("saveload",
"Saves the tile and then reloads it in the next position. Reliable but CPU intensive.",
new SaveLoadTileMover)
API.registerTileMover(
"saveload",
"Saves the tile and then reloads it in the next position. Reliable but CPU intensive.",
new SaveLoadTileMover
)
API.registerTileMover("coordpush",
"Physically changes the location of tiles. Works if tiles do not cache their position.",
new CoordPushTileMover)
API.registerTileMover(
"coordpush",
"Physically changes the location of tiles. Works if tiles do not cache their position.",
new CoordPushTileMover
)
API.registerTileMover("static", "Setting this disables movement for the specified block.",
new StaticTileMover)
API.registerTileMover(
"static",
"Setting this disables movement for the specified block.",
new StaticTileMover
)
API.registerPreferredMover("default", "saveload")
API.registerPreferredMover("mod:minecraft", "coordpush")
API.registerPreferredMover("mod:Relocation", "coordpush")
API.registerPreferredMover("mod:ComputerCraft", "coordpush")
API.registerPreferredMover("mod:EnderStorage", "coordpush")
API.registerPreferredMover("mod:ChickenChunks", "coordpush")
API.registerPreferredMover("mod:Translocator", "coordpush")
API.registerPreferredMover("mod:ProjRed|Compatibility", "coordpush")
API.registerPreferredMover("mod:ProjRed|Core", "coordpush")
API.registerPreferredMover("mod:ProjRed|Expansion", "coordpush")
API.registerPreferredMover("mod:ProjRed|Exploration", "coordpush")
API.registerPreferredMover("mod:ProjRed|Fabrication", "coordpush")
API.registerPreferredMover("mod:ProjRed|Illumination", "coordpush")
API.registerPreferredMover("mod:ProjRed|Integration", "coordpush")
API.registerPreferredMover("mod:ProjRed|Transmission", "coordpush")
API.registerPreferredMover("mod:ProjRed|Transportation", "coordpush")
}
API.registerPreferredMover("default", "saveload")
API.registerPreferredMover("mod:minecraft", "coordpush")
API.registerPreferredMover("mod:Relocation", "coordpush")
API.registerPreferredMover("mod:ComputerCraft", "coordpush")
API.registerPreferredMover("mod:EnderStorage", "coordpush")
API.registerPreferredMover("mod:ChickenChunks", "coordpush")
API.registerPreferredMover("mod:Translocator", "coordpush")
API.registerPreferredMover("mod:ProjRed|Compatibility", "coordpush")
API.registerPreferredMover("mod:ProjRed|Core", "coordpush")
API.registerPreferredMover("mod:ProjRed|Expansion", "coordpush")
API.registerPreferredMover("mod:ProjRed|Exploration", "coordpush")
API.registerPreferredMover("mod:ProjRed|Fabrication", "coordpush")
API.registerPreferredMover("mod:ProjRed|Illumination", "coordpush")
API.registerPreferredMover("mod:ProjRed|Integration", "coordpush")
API.registerPreferredMover("mod:ProjRed|Transmission", "coordpush")
API.registerPreferredMover("mod:ProjRed|Transportation", "coordpush")
}
def init()
{
}
def init() {}
def postinit()
{
PacketCustom.assignHandler(RelocationSPH.channel, RelocationSPH)
def postinit() {
PacketCustom.assignHandler(RelocationSPH.channel, RelocationSPH)
FMLCommonHandler.instance.bus.register(RelocationEventHandler)
MinecraftForge.EVENT_BUS.register(RelocationEventHandler)
}
FMLCommonHandler.instance.bus.register(RelocationEventHandler)
MinecraftForge.EVENT_BUS.register(RelocationEventHandler)
}
}
class RelocationProxy_client extends RelocationProxy_server
{
@SideOnly(Side.CLIENT)
override def postinit()
{
super.postinit()
PacketCustom.assignHandler(RelocationCPH.channel, RelocationCPH)
class RelocationProxy_client extends RelocationProxy_server {
@SideOnly(Side.CLIENT)
override def postinit() {
super.postinit()
PacketCustom.assignHandler(RelocationCPH.channel, RelocationCPH)
FMLCommonHandler.instance.bus.register(RelocationClientEventHandler)
MinecraftForge.EVENT_BUS.register(RelocationClientEventHandler)
FMLCommonHandler.instance.bus.register(RelocationClientEventHandler)
MinecraftForge.EVENT_BUS.register(RelocationClientEventHandler)
}
}
}
object RelocationProxy extends RelocationProxy_client
object RelocationProxy extends RelocationProxy_client
+505 -349
View File
@@ -17,403 +17,559 @@ import net.minecraft.client.Minecraft
import net.minecraft.init.Blocks
import net.minecraft.world.{ChunkCoordIntPair, World}
import net.minecraftforge.common.DimensionManager
import scala.collection.mutable.{
HashMap => MHashMap,
MultiMap => MMultiMap,
Set => MSet
}
import scala.collection.mutable.{HashMap => MHashMap, MultiMap => MMultiMap, Set => MSet}
import scala.ref.WeakReference
object MovementManager2
{
val serverRelocations = MHashMap[Int, WorldStructs]()
val clientRelocations = MHashMap[Int, WorldStructs]()
object MovementManager2 {
val serverRelocations = new WorldStructsMap
val clientRelocations = new WorldStructsMap
def relocationMap(isClient:Boolean) = if (isClient) clientRelocations else serverRelocations
def relocationMap(isClient: Boolean) =
if (isClient) clientRelocations else serverRelocations
def getWorldStructs(w:World) =
relocationMap(w.isRemote).getOrElseUpdate(w.provider.dimensionId, new WorldStructs)
def getWorldStructs(w: World) =
relocationMap(w.isRemote).getOrCreate(w.provider.dimensionId)
def getWorld(dim:Int, isClient:Boolean) =
if (!isClient) DimensionManager.getWorld(dim)
else getClientWorld(dim)
def getWorld(dim: Int, isClient: Boolean) =
if (!isClient) DimensionManager.getWorld(dim)
else getClientWorld(dim)
@SideOnly(Side.CLIENT)
private def getClientWorld(dim:Int):World =
{
val w = Minecraft.getMinecraft.theWorld
if (w.provider.dimensionId == dim) w else null
@SideOnly(Side.CLIENT)
private def getClientWorld(dim: Int): World = {
val w = Minecraft.getMinecraft.theWorld
if (w.provider.dimensionId == dim) w else null
}
def writeDesc(w: World, chunks: Set[ChunkCoordIntPair], out: MCDataOutput) = {
var send = false
for (
s <- getWorldStructs(w).structs if s.getChunks.exists(chunks.contains)
) {
send = true
out.writeShort(s.id)
s.writeDesc(out)
}
if (send) out.writeShort(Short.MaxValue)
send
}
def readDesc(w: World, in: MCDataInput) {
var id = in.readUShort()
while (id != Short.MaxValue) {
val struct = new BlockStruct
struct.id = id
struct.readDesc(in)
addStructToWorld(w, struct)
id = in.readUShort()
}
}
def read(w: World, in: MCDataInput, key: Int) = key match {
case 1 =>
val struct = new BlockStruct
struct.id = in.readUShort()
struct.readDesc(in)
addStructToWorld(w, struct)
for (b <- struct.allBlocks) // rerender all moving blocks
w.func_147479_m(b.x, b.y, b.z)
case 2 =>
val id = in.readUShort()
getWorldStructs(w).structs.find(_.id == id) match {
case Some(struct) => clientCycleMove(w, struct)
case None =>
throw new RuntimeException(
s"DC: Moving structure with id $id was not found client-side."
)
}
case _ =>
throw new RuntimeException(
s"DC: Packet with ID $key was not handled. " +
s"Skipped ${in.asInstanceOf[PacketCustom].getByteBuf.array().length} bytes."
)
}
def sendStruct(w: World, struct: BlockStruct) {
val out = RelocationSPH.getStream(w, struct.getChunks, 1)
out.writeShort(struct.id)
struct.writeDesc(out)
RelocationSPH.forceSendData()
}
def sendCycle(w: World, struct: BlockStruct) {
RelocationSPH.getStream(w, struct.getChunks, 2).writeShort(struct.id)
RelocationSPH.forceSendData()
}
def isMoving(w: World, x: Int, y: Int, z: Int) = {
if (w == null) false
else getWorldStructs(w).contains(x, y, z)
}
def addStructToWorld(w: World, b: BlockStruct) {
getWorldStructs(w).addStruct(b)
b.onAdded(w)
}
def getEnclosedStructure(w: World, x: Int, y: Int, z: Int) =
getWorldStructs(w).structs.find(_.contains(x, y, z)).orNull
def tryStartMove(
w: World,
blocks: Set[BlockCoord],
moveDir: Int,
speed: Double,
c: IMovementCallback
): Boolean = {
if (blocks.size > RelocationConfig.moveLimit) return false
if (
blocks.exists { b =>
val block = w.getBlock(b.x, b.y, b.z)
block != null && block.getBlockHardness(w, b.x, b.y, b.z) < 0
}
) return false
val map = new MHashMap[(Int, Int), MSet[Int]]
with MMultiMap[(Int, Int), Int]
for (b <- blocks)
map.addBinding(MathLib.normal(b, moveDir), MathLib.basis(b, moveDir))
val shift = if ((moveDir & 1) == 1) 1 else -1
val rowB = Array.newBuilder[BlockRow]
for (normal <- map.keys) {
val line = map(normal).toArray
val sline =
if (shift == 1) line.sorted else line.sorted(Ordering[Int].reverse)
for ((basis, size) <- MathLib.splitLine(sline, shift)) {
val c = MathLib.rhrAxis(moveDir, normal, basis + shift)
rowB += new BlockRow(c, moveDir, size)
}
}
def writeDesc(w:World, chunks:Set[ChunkCoordIntPair], out:MCDataOutput) =
{
var send = false
for (s <- getWorldStructs(w).structs if s.getChunks.exists(chunks.contains))
{
send = true
out.writeShort(s.id)
s.writeDesc(out)
val rows = rowB.result()
if (
rows.exists(row =>
!MovingTileRegistry.canRunOverBlock(w, row.pos.x, row.pos.y, row.pos.z)
)
) return false
for (r <- rows) TileMovingRow.setBlockForRow(w, r)
val struct = new BlockStruct
struct.id = BlockStruct.claimID()
struct.speed = speed
struct.rows = rows
struct.callback = WeakReference(c)
addStructToWorld(w, struct)
sendStruct(w, struct)
true
}
def onTick(isClient: Boolean) {
val map = relocationMap(isClient)
map.foreach { (dim, ws) =>
if (ws.nonEmpty) {
ws.pushAll()
val world = getWorld(dim, isClient)
if (world != null)
for (bs <- ws.structs)
for (br <- bs.rows)
br.pushEntities(world, bs.progress)
}
}
if (!isClient) {
map.foreach { (dim, ws) =>
val finished = ws.removeFinished()
if (finished.nonEmpty) {
val w = getWorld(dim, false)
if (w != null) for (s <- finished) {
cycleMove(w, s)
sendCycle(w, s)
}
}
if (send) out.writeShort(Short.MaxValue)
send
}
}
}
def readDesc(w:World, in:MCDataInput)
{
var id = in.readUShort()
while (id != Short.MaxValue)
{
val struct = new BlockStruct
struct.id = id
struct.readDesc(in)
addStructToWorld(w, struct)
id = in.readUShort()
}
}
def onWorldUnload(w: World) {
getWorldStructs(w).clear()
}
def read(w:World, in:MCDataInput, key:Int) = key match
{
case 1 =>
val struct = new BlockStruct
struct.id = in.readUShort()
struct.readDesc(in)
addStructToWorld(w, struct)
for (b <- struct.allBlocks) //rerender all moving blocks
w.func_147479_m(b.x, b.y, b.z)
case 2 =>
val id = in.readUShort()
getWorldStructs(w).structs.find(_.id == id) match
{
case Some(struct) => clientCycleMove(w, struct)
case None => throw new RuntimeException(s"DC: Moving structure with id $id was not found client-side.")
}
case _ => throw new RuntimeException(s"DC: Packet with ID $key was not handled. " +
s"Skipped ${in.asInstanceOf[PacketCustom].getByteBuf.array().length} bytes.")
}
def clientCycleMove(w: World, struct: BlockStruct) {
getWorldStructs(w).removeStruct(struct)
struct.rows.foreach(_.pushEntities(w, 1.0))
cycleMove(w, struct)
}
def sendStruct(w:World, struct:BlockStruct)
{
val out = RelocationSPH.getStream(w, struct.getChunks, 1)
out.writeShort(struct.id)
struct.writeDesc(out)
RelocationSPH.forceSendData()
}
def cycleMove(w: World, struct: BlockStruct) {
struct.doMove(w)
struct.postMove(w)
struct.endMove(w)
def sendCycle(w:World, struct:BlockStruct)
{
RelocationSPH.getStream(w, struct.getChunks, 2).writeShort(struct.id)
RelocationSPH.forceSendData()
}
Utils.rescheduleTicks(
w,
struct.preMoveBlocks,
struct.allBlocks,
struct.moveDir
)
def isMoving(w:World, x:Int, y:Int, z:Int) = getWorldStructs(w).contains(x, y, z)
val changes = MSet[BlockCoord]()
for (r <- struct.rows) r.cacheChanges(w, changes)
for (bc <- changes)
w.notifyBlockOfNeighborChange(bc.x, bc.y, bc.z, Blocks.air)
def addStructToWorld(w:World, b:BlockStruct)
{
getWorldStructs(w).addStruct(b)
b.onAdded(w)
}
def getEnclosedStructure(w:World, x:Int, y:Int, z:Int) =
getWorldStructs(w).structs.find(_.contains(x, y, z)).orNull
def tryStartMove(w:World, blocks:Set[BlockCoord], moveDir:Int, speed:Double, c:IMovementCallback):Boolean =
{
if (blocks.size > RelocationConfig.moveLimit) return false
val map = new MHashMap[(Int, Int), MSet[Int]] with MMultiMap[(Int, Int), Int]
for (b <- blocks) map.addBinding(MathLib.normal(b, moveDir), MathLib.basis(b, moveDir))
val shift = if ((moveDir&1) == 1) 1 else -1
val rowB = Set.newBuilder[BlockRow]
for (normal <- map.keys)
{
val line = map(normal).toArray
val sline = if (shift == 1) line.sorted else line.sorted(Ordering[Int].reverse)
for ((basis, size) <- MathLib.splitLine(sline, shift))
{
val c = MathLib.rhrAxis(moveDir, normal, basis+shift)
rowB += new BlockRow(c, moveDir, size)
}
}
val rows = rowB.result()
if (rows.exists(row => !MovingTileRegistry.canRunOverBlock(w, row.pos.x, row.pos.y, row.pos.z))) return false
for (r <- rows) TileMovingRow.setBlockForRow(w, r)
val struct = new BlockStruct
struct.id = BlockStruct.claimID()
struct.speed = speed
struct.rows = rows
struct.callback = WeakReference(c)
addStructToWorld(w, struct)
sendStruct(w, struct)
true
}
def onTick(isClient:Boolean)
{
val map = relocationMap(isClient)
for ((dim, ws) <- map) if (ws.nonEmpty)
{
ws.pushAll()
val world = getWorld(dim, isClient)
if (world != null) for (bs <- ws.structs) for (br <- bs.rows)
br.pushEntities(world, bs.progress)
}
if (!isClient)
{
val fin = map.map(pair => (pair._1, pair._2.removeFinished())).filter(_._2.nonEmpty)
for ((dim, b) <- fin)
{
val w = getWorld(dim, false)
if (w != null) for (s <- b)
{
cycleMove(w, s)
sendCycle(w, s)
}
}
}
}
def onWorldUnload(w:World)
{
getWorldStructs(w).clear()
}
def clientCycleMove(w:World, struct:BlockStruct)
{
getWorldStructs(w).removeStruct(struct)
struct.rows.foreach(_.pushEntities(w, 1.0))
cycleMove(w, struct)
}
def cycleMove(w:World, struct:BlockStruct)
{
struct.doMove(w)
struct.postMove(w)
struct.endMove(w)
Utils.rescheduleTicks(w, struct.preMoveBlocks, struct.allBlocks, struct.moveDir)
val changes = MSet[BlockCoord]()
for (r <- struct.rows) r.cacheChanges(w, changes)
for (bc <- changes) w.notifyBlockOfNeighborChange(bc.x, bc.y, bc.z, Blocks.air)
Utils.rerenderBlocks(w, struct.preMoveBlocks)
}
Utils.rerenderBlocks(w, struct.preMoveBlocks)
}
}
class WorldStructs
{
var structs:Set[BlockStruct] = Set.empty
class WorldStructsMap {
private var dims = new Array[Int](4)
private var structs = new Array[WorldStructs](4)
private var size = 0
def isEmpty = structs.isEmpty
def nonEmpty = !isEmpty
def contains(x:Int, y:Int, z:Int) = structs.exists(_.contains(x, y, z))
def addStruct(b:BlockStruct){ structs += b }
def pushAll(){ structs.foreach(_.push()) }
def removeFinished() =
{
val finished = structs.filter(_.isFinished)
structs = structs.filterNot(_.isFinished)
finished
def getOrCreate(dim: Int): WorldStructs = synchronized {
var i = 0
while (i < size) {
if (dims(i) == dim) return structs(i)
i += 1
}
def removeStruct(s:BlockStruct)
{
structs = structs.filterNot(_ == s)
val ws = new WorldStructs
if (size == dims.length) {
val nd = new Array[Int](dims.length * 2)
val ns = new Array[WorldStructs](dims.length * 2)
System.arraycopy(dims, 0, nd, 0, size)
System.arraycopy(structs, 0, ns, 0, size)
dims = nd
structs = ns
}
dims(size) = dim
structs(size) = ws
size += 1
ws
}
def clear(){structs = Set.empty}
def getChunks:Set[ChunkCoordIntPair] =
{
structs.flatMap(_.getChunks)
def foreach(f: (Int, WorldStructs) => Unit) {
val n = synchronized { size }
val ds = new Array[Int](n)
val ss = new Array[WorldStructs](n)
synchronized {
System.arraycopy(dims, 0, ds, 0, n)
System.arraycopy(structs, 0, ss, 0, n)
}
var i = 0
while (i < n) {
f(ds(i), ss(i))
i += 1
}
}
}
object BlockStruct
{
private var maxID = 0
def claimID() =
{
if (maxID < 32765) maxID += 1//little less than Short.MaxValue (reserved for terminator)
else maxID = 0
maxID
class WorldStructs {
private val noStructs = new Array[BlockStruct](0)
private var structsArr = new Array[BlockStruct](4)
private var numStructs = 0
def isEmpty = synchronized { numStructs == 0 }
def nonEmpty = synchronized { numStructs > 0 }
def contains(x: Int, y: Int, z: Int): Boolean = synchronized {
var i = 0
while (i < numStructs) {
if (structsArr(i).contains(x, y, z)) return true
i += 1
}
false
}
def addStruct(b: BlockStruct): Unit = synchronized {
var i = 0
while (i < numStructs) {
if (structsArr(i).id == b.id) return
i += 1
}
if (numStructs == structsArr.length) {
val ns = new Array[BlockStruct](structsArr.length * 2)
System.arraycopy(structsArr, 0, ns, 0, numStructs)
structsArr = ns
}
structsArr(numStructs) = b
numStructs += 1
}
def pushAll() = synchronized {
var i = 0
while (i < numStructs) {
structsArr(i).push()
i += 1
}
}
def removeFinished(): Array[BlockStruct] = synchronized {
var nf = 0
var i = 0
while (i < numStructs) {
if (structsArr(i).isFinished) nf += 1
i += 1
}
if (nf == 0) return noStructs
val finished = new Array[BlockStruct](nf)
var finish = 0
var keep = 0
i = 0
while (i < numStructs) {
val s = structsArr(i)
if (s.isFinished) {
finished(finish) = s
finish += 1
} else {
structsArr(keep) = s
keep += 1
}
i += 1
}
var j = keep
while (j < numStructs) {
structsArr(j) = null
j += 1
}
numStructs = keep
finished
}
def removeStruct(s: BlockStruct) = synchronized {
var keep = 0
var i = 0
while (i < numStructs) {
val cur = structsArr(i)
if (cur != s) {
structsArr(keep) = cur
keep += 1
}
i += 1
}
var j = keep
while (j < numStructs) {
structsArr(j) = null
j += 1
}
numStructs = keep
}
def clear() = synchronized {
var i = 0
while (i < numStructs) {
structsArr(i) = null
i += 1
}
numStructs = 0
}
def foreachStruct(f: BlockStruct => Unit) = synchronized {
var i = 0
while (i < numStructs) {
f(structsArr(i))
i += 1
}
}
def structs: Array[BlockStruct] = synchronized {
java.util.Arrays.copyOf(structsArr, numStructs)
}
def getChunks: Set[ChunkCoordIntPair] = synchronized {
val c = Set.newBuilder[ChunkCoordIntPair]
var i = 0
while (i < numStructs) {
c ++= structsArr(i).getChunks
i += 1
}
c.result()
}
}
class MoveDesc(b:WeakReference[BlockStruct]) extends IMovementDescriptor
{
def this(b:BlockStruct) = this(new WeakReference(b))
override def isMoving = b match {
case WeakReference(b:BlockStruct) => !b.isFinished
case _ => false
}
override def getProgress = b match {
case WeakReference(b:BlockStruct) => b.progress
case _ => -1
}
override def getSize = b match {
case WeakReference(b:BlockStruct) => b.allBlocks.size
case _ => 0
}
object BlockStruct {
private var maxID = 0
def claimID() = {
if (maxID < 32765)
maxID += 1 // little less than Short.MaxValue (reserved for terminator)
else maxID = 0
maxID
}
}
class BlockStruct
{
var id = -1
var speed = 1/16D
var rows:Set[BlockRow] = Set.empty
var callback = WeakReference[IMovementCallback](null)
class MoveDesc(b: WeakReference[BlockStruct]) extends IMovementDescriptor {
def this(b: BlockStruct) = this(new WeakReference(b))
var progress = 0.0D
override def isMoving = b match {
case WeakReference(b: BlockStruct) => !b.isFinished
case _ => false
}
lazy val allBlocks = rows.flatMap(_.allBlocks)
lazy val preMoveBlocks = rows.flatMap(_.preMoveBlocks)
lazy val postMoveBlocks = rows.flatMap(_.postMoveBlocks)
override def getProgress = b match {
case WeakReference(b: BlockStruct) => b.progress
case _ => -1
}
def moveDir = rows.head.moveDir
def contains(x:Int, y:Int, z:Int) = rows.exists(_.contains(x, y, z))
def push(){ progress = math.min(1.0, progress+speed) }
def isFinished = progress >= 1.0D
def getChunks:Set[ChunkCoordIntPair] =
{
val c = Set.newBuilder[ChunkCoordIntPair]
for (b <- allBlocks)
c += new ChunkCoordIntPair(b.x>>4, b.z>>4)
c.result()
}
def onAdded(w:World)
{
if (!w.isRemote) callback match
{
case WeakReference(c) =>
c.setDescriptor(new MoveDesc(this))
c.onMovementStarted()
case _ =>
}
}
def doMove(w:World)
{
for (r <- rows) r.doMove(w)
}
def postMove(w:World)
{
for (r <- rows) r.postMove(w)
}
def endMove(w:World)
{
for (r <- rows) r.endMove(w)
if (!w.isRemote) callback match
{
case WeakReference(c) => c.onMovementFinished()
case _ =>
}
}
override def equals(obj:scala.Any) = obj match
{
case that:BlockStruct => id == that.id
case _ => false
}
def writeDesc(out:MCDataOutput)
{
out.writeFloat(progress.toFloat)
out.writeFloat(speed.toFloat)
out.writeByte(rows.size)
for (r <- rows)
{
out.writeLong(WorldLib.packCoords(r.pos))
out.writeByte(r.moveDir)
out.writeShort(r.size)
}
}
def readDesc(in:MCDataInput)
{
progress = in.readFloat()
speed = in.readFloat()
val rb = Set.newBuilder[BlockRow]
for (i <- 0 until in.readUByte())
rb += new BlockRow(WorldLib.unpackCoords(in.readLong()), in.readUByte(), in.readUShort())
rows = rb.result()
}
override def getSize = b match {
case WeakReference(b: BlockStruct) => b.allBlocks.size
case _ => 0
}
}
class BlockRow(val pos:BlockCoord, val moveDir:Int, val size:Int)
{
val allBlocks = 0 to size map {i => pos.copy.offset(moveDir^1, i)}
val preMoveBlocks = allBlocks drop 1
val postMoveBlocks = allBlocks dropRight 1
class BlockStruct {
var id = -1
var speed = 1 / 16d
var rows: Array[BlockRow] = Array.empty
var callback = WeakReference[IMovementCallback](null)
def contains(x:Int, y:Int, z:Int) =
{
import MathLib.{basis, normal, shift}
var progress = 0.0d
import math.{max, min}
lazy val allBlocks: Set[BlockCoord] = rows.iterator.flatMap(_.allBlocks).toSet
lazy val preMoveBlocks: Set[BlockCoord] =
rows.iterator.flatMap(_.preMoveBlocks).toSet
lazy val postMoveBlocks: Set[BlockCoord] =
rows.iterator.flatMap(_.postMoveBlocks).toSet
if (normal(x, y, z, moveDir) == normal(pos, moveDir))
{
val b1 = basis(pos, moveDir)
val b2 = b1+size*shift(moveDir^1)
min(b1, b2) to max(b1, b2) contains basis(x, y, z, moveDir)
}
else false
def moveDir = rows(0).moveDir
def contains(x: Int, y: Int, z: Int): Boolean = {
var i = 0
while (i < rows.length) {
if (rows(i).contains(x, y, z)) return true
i += 1
}
false
}
def pushEntities(w:World, progress:Double)
{
WorldLib.uncheckedGetTileEntity(w, pos.x, pos.y, pos.z) match
{
case te:TileMovingRow => te.pushEntities(this, progress)
case _ =>
}
def push() { progress = math.min(1.0, progress + speed) }
def isFinished = progress >= 1.0d
def getChunks: Set[ChunkCoordIntPair] = {
val c = Set.newBuilder[ChunkCoordIntPair]
for (b <- allBlocks)
c += new ChunkCoordIntPair(b.x >> 4, b.z >> 4)
c.result()
}
def onAdded(w: World) {
if (!w.isRemote) callback match {
case WeakReference(c) =>
c.setDescriptor(new MoveDesc(this))
c.onMovementStarted()
case _ =>
}
}
def doMove(w:World)
{
if (pos.y < 0 || pos.y >= 256) return
def doMove(w: World) {
for (r <- rows) r.doMove(w)
}
w.removeTileEntity(pos.x, pos.y, pos.z)
WorldLib.uncheckedSetBlock(w, pos.x, pos.y, pos.z, Blocks.air, 0) //Remove movement block
def postMove(w: World) {
for (r <- rows) r.postMove(w)
}
for (b <- preMoveBlocks)
MovingTileRegistry.move(w, b.x, b.y, b.z, moveDir)
def endMove(w: World) {
for (r <- rows) r.endMove(w)
if (!w.isRemote) callback match {
case WeakReference(c) => c.onMovementFinished()
case _ =>
}
}
def postMove(w:World)
{
for (b <- postMoveBlocks)
MovingTileRegistry.postMove(w, b.x, b.y, b.z)
override def equals(obj: scala.Any) = obj match {
case that: BlockStruct => id == that.id
case _ => false
}
override def hashCode() = id
def writeDesc(out: MCDataOutput) {
out.writeFloat(progress.toFloat)
out.writeFloat(speed.toFloat)
out.writeByte(rows.length)
for (r <- rows) {
out.writeLong(WorldLib.packCoords(r.pos))
out.writeByte(r.moveDir)
out.writeShort(r.size)
}
}
def endMove(w:World){}
def readDesc(in: MCDataInput) {
progress = in.readFloat()
speed = in.readFloat()
val rb = Array.newBuilder[BlockRow]
for (i <- 0 until in.readUByte())
rb += new BlockRow(
WorldLib.unpackCoords(in.readLong()),
in.readUByte(),
in.readUShort()
)
rows = rb.result()
}
}
def cacheChanges(w:World, changes:MSet[BlockCoord])
{
for (i <- 0 to size)
{
val c = pos.copy.offset(moveDir^1, i)
changes += c
for (s <- 0 until 6; s1 <- 0 until 6 if s1 != (s^1))
changes += c.copy.offset(s).offset(s1)
}
class BlockRow(val pos: BlockCoord, val moveDir: Int, val size: Int) {
val allBlocks = 0 to size map { i => pos.copy.offset(moveDir ^ 1, i) }
val preMoveBlocks = allBlocks drop 1
val postMoveBlocks = allBlocks dropRight 1
def contains(x: Int, y: Int, z: Int) = {
import MathLib.{basis, normal, shift}
if (normal(x, y, z, moveDir) == normal(pos, moveDir)) {
val b1 = basis(pos, moveDir)
val b2 = b1 + size * shift(moveDir ^ 1)
val b = basis(x, y, z, moveDir)
b >= math.min(b1, b2) && b <= math.max(b1, b2)
} else false
}
def pushEntities(w: World, progress: Double) {
WorldLib.uncheckedGetTileEntity(w, pos.x, pos.y, pos.z) match {
case te: TileMovingRow => te.pushEntities(this, progress)
case _ =>
}
}
}
def doMove(w: World) {
if (pos.y < 0 || pos.y >= 256) return
w.removeTileEntity(pos.x, pos.y, pos.z)
WorldLib.uncheckedSetBlock(
w,
pos.x,
pos.y,
pos.z,
Blocks.air,
0
) // Remove movement block
for (b <- preMoveBlocks)
MovingTileRegistry.move(w, b.x, b.y, b.z, moveDir)
}
def postMove(w: World) {
for (b <- postMoveBlocks)
MovingTileRegistry.postMove(w, b.x, b.y, b.z)
}
def endMove(w: World) {}
def cacheChanges(w: World, changes: MSet[BlockCoord]) {
for (i <- 0 to size) {
val c = pos.copy.offset(moveDir ^ 1, i)
changes += c
for (s <- 0 until 6; s1 <- 0 until 6 if s1 != (s ^ 1))
changes += c.copy.offset(s).offset(s1)
}
}
}
+135 -145
View File
@@ -20,176 +20,166 @@ import net.minecraft.world.World
import scala.collection.immutable.ListMap
object MovingTileRegistry extends ITileMover
{
val rKeyVal = raw"([^\s]+.+[^\s]+)\s*->\s*([^\s]+.+[^\s]+)".r
val rName = raw"([^\s]+.+[^\s]+)".r
val rNameMetaM = raw"([^\s]+.+[^\s]+)m(\d+)".r
val rMod = raw"mod:([^\s]+.+[^\s]+)".r
object MovingTileRegistry extends ITileMover {
val rKeyVal = raw"([^\s]+.+[^\s]+)\s*->\s*([^\s]+.+[^\s]+)".r
val rName = raw"([^\s]+.+[^\s]+)".r
val rNameMetaM = raw"([^\s]+.+[^\s]+)m(\d+)".r
val rMod = raw"mod:([^\s]+.+[^\s]+)".r
var blockMetaMap = Map[(Block, Int), ITileMover]()
var modMap = Map[String, ITileMover]()
var blockMetaMap = Map[(Block, Int), ITileMover]()
var modMap = Map[String, ITileMover]()
var moverDescMap = Map[String, String]()
var moverNameMap = Map[String, ITileMover]()
var moverDescMap = Map[String, String]()
var moverNameMap = Map[String, ITileMover]()
var defaultMover:ITileMover = _
var preferredMovers = Seq[(String, String)]()
var mandatoryMovers = Seq[(String, String)]()
var defaultMover: ITileMover = _
var preferredMovers = Seq[(String, String)]()
var mandatoryMovers = Seq[(String, String)]()
def parseKV(kv:Seq[String]) = kv.map { case rKeyVal(k, v) => (k, v); case s => throw new MatchError(s"Illegal [k -> v] pair: $s") }
def parseBlockMeta(b:String) = b match
{
case rNameMetaM(name, meta) => Block.getBlockFromName(fixName(name)) -> meta.toInt
case rName(name) => Block.getBlockFromName(fixName(name)) -> -1
case _ => throw new MatchError(s"Illegal set part: $b")
}
def fixName(name:String) = name.indexOf(':') match
{
case -1 => "minecraft:"+name
case i => name
def parseKV(kv: Seq[String]) = kv.map {
case rKeyVal(k, v) => (k, v);
case s => throw new MatchError(s"Illegal [k -> v] pair: $s")
}
def parseBlockMeta(b: String) = b match {
case rNameMetaM(name, meta) =>
Block.getBlockFromName(fixName(name)) -> meta.toInt
case rName(name) => Block.getBlockFromName(fixName(name)) -> -1
case _ => throw new MatchError(s"Illegal set part: $b")
}
def fixName(name: String) = name.indexOf(':') match {
case -1 => "minecraft:" + name
case i => name
}
def parseAndSetMovers(kv: Seq[String]) = {
var moverMap = ListMap(parseKV(kv): _*)
for ((k, v) <- preferredMovers)
if (!moverMap.contains(k)) moverMap += k -> v
for (pair <- mandatoryMovers) moverMap += pair
moverMap.foreach(h => setMover(h._1, h._2))
moverMap.map(p => p._1 + " -> " + p._2).toArray
}
def setMover(that: String, m: String) {
if (!moverNameMap.contains(m)) return
val h = moverNameMap(m)
that match {
case "default" => defaultMover = h
case rMod(mod) if Loader.isModLoaded(mod) => modMap += mod -> h
case _ => blockMetaMap += parseBlockMeta(that) -> h
}
}
def parseAndSetMovers(kv:Seq[String]) =
{
var moverMap = ListMap(parseKV(kv):_*)
for ((k, v) <- preferredMovers) if (!moverMap.contains(k)) moverMap += k -> v
for (pair <- mandatoryMovers) moverMap += pair
moverMap.foreach(h => setMover(h._1, h._2))
moverMap.map(p => p._1+" -> "+p._2).toArray
}
def registerTileMover(name: String, desc: String, m: ITileMover) {
moverDescMap += name -> desc
moverNameMap += name -> m
}
def setMover(that:String, m:String)
{
if (!moverNameMap.contains(m)) return
val h = moverNameMap(m)
that match
{
case "default" => defaultMover = h
case rMod(mod) if Loader.isModLoaded(mod) => modMap += mod -> h
case _ => blockMetaMap += parseBlockMeta(that) -> h
}
}
private def getHandler(b: Block, m: Int) = {
blockMetaMap.getOrElse(
(b, m),
blockMetaMap.getOrElse(
(b, -1),
modMap.getOrElse(BlockLib.getModId(b), defaultMover)
)
)
}
def registerTileMover(name:String, desc:String, m:ITileMover)
{
moverDescMap += name -> desc
moverNameMap += name -> m
override def canMove(w: World, x: Int, y: Int, z: Int) = {
val meta = w.getBlockMetadata(x, y, z)
w.getBlock(x, y, z) match {
case block: Block => getHandler(block, meta).canMove(w, x, y, z)
case _ => false
}
}
private def getHandler(b:Block, m:Int) =
{
blockMetaMap.getOrElse((b, m), blockMetaMap.getOrElse((b, -1),
modMap.getOrElse(BlockLib.getModId(b), defaultMover)))
override def move(w: World, x: Int, y: Int, z: Int, side: Int) {
val meta = w.getBlockMetadata(x, y, z)
w.getBlock(x, y, z) match {
case block: Block => getHandler(block, meta).move(w, x, y, z, side)
case _ =>
}
}
override def canMove(w:World, x:Int, y:Int, z:Int) =
{
val meta = w.getBlockMetadata(x, y, z)
w.getBlock(x, y, z) match
{
case block:Block => getHandler(block, meta).canMove(w, x, y, z)
case _ => false
}
override def postMove(w: World, x: Int, y: Int, z: Int) {
val meta = w.getBlockMetadata(x, y, z)
w.getBlock(x, y, z) match {
case block: Block => getHandler(block, meta).postMove(w, x, y, z)
case _ =>
}
}
override def move(w:World, x:Int, y:Int, z:Int, side:Int)
{
val meta = w.getBlockMetadata(x, y, z)
w.getBlock(x, y, z) match
{
case block:Block => getHandler(block, meta).move(w, x, y, z, side)
case _ =>
}
}
override def postMove(w:World, x:Int, y:Int, z:Int)
{
val meta = w.getBlockMetadata(x, y, z)
w.getBlock(x, y, z) match
{
case block:Block => getHandler(block, meta).postMove(w, x, y, z)
case _ =>
}
}
def canRunOverBlock(w:World, x:Int, y:Int, z:Int) =
{
if (w.blockExists(x, y, z))
w.isAirBlock(x, y, z) || WorldLib.isBlockSoft(w, x, y, z, w.getBlock(x, y, z))
else false
}
def canRunOverBlock(w: World, x: Int, y: Int, z: Int) = {
if (w.blockExists(x, y, z))
w.isAirBlock(x, y, z) || WorldLib.isBlockSoft(
w,
x,
y,
z,
w.getBlock(x, y, z)
)
else false
}
}
class CoordPushTileMover extends ITileMover
{
override def canMove(w:World, x:Int, y:Int, z:Int) = true
class CoordPushTileMover extends ITileMover {
override def canMove(w: World, x: Int, y: Int, z: Int) = true
override def move(w:World, x:Int, y:Int, z:Int, side:Int)
{
val (b, meta, te) = getBlockInfo(w, x, y, z)
val pos = new BlockCoord(x, y, z).offset(side)
if (te != null)
{
te.invalidate()
uncheckedRemoveTileEntity(w, x, y, z)
}
uncheckedSetBlock(w, x, y, z, Blocks.air, 0)
uncheckedSetBlock(w, pos.x, pos.y, pos.z, b, meta)
if (te != null)
{
te.xCoord = pos.x
te.yCoord = pos.y
te.zCoord = pos.z
te.validate()
uncheckedSetTileEntity(w, pos.x, pos.y, pos.z, te)
}
override def move(w: World, x: Int, y: Int, z: Int, side: Int) {
val (b, meta, te) = getBlockInfo(w, x, y, z)
val pos = new BlockCoord(x, y, z).offset(side)
if (te != null) {
te.invalidate()
uncheckedRemoveTileEntity(w, x, y, z)
}
uncheckedSetBlock(w, x, y, z, Blocks.air, 0)
uncheckedSetBlock(w, pos.x, pos.y, pos.z, b, meta)
if (te != null) {
te.xCoord = pos.x
te.yCoord = pos.y
te.zCoord = pos.z
te.validate()
uncheckedSetTileEntity(w, pos.x, pos.y, pos.z, te)
}
}
override def postMove(w:World, x:Int, y:Int, z:Int){}
override def postMove(w: World, x: Int, y: Int, z: Int) {}
}
class SaveLoadTileMover extends ITileMover
{
override def canMove(w:World, x:Int, y:Int, z:Int) = true
class SaveLoadTileMover extends ITileMover {
override def canMove(w: World, x: Int, y: Int, z: Int) = true
override def move(w:World, x:Int, y:Int, z:Int, side:Int)
{
val (b, meta, te) = getBlockInfo(w, x, y, z)
val pos = new BlockCoord(x, y, z).offset(side)
val tag = if (te != null)
{
val tag = new NBTTagCompound
te.writeToNBT(tag)
tag.setInteger("x", pos.x)
tag.setInteger("y", pos.y)
tag.setInteger("z", pos.z)
te.onChunkUnload()
w.removeTileEntity(x, y, z)
tag
}
else null
uncheckedSetBlock(w, x, y, z, Blocks.air, 0)
uncheckedSetBlock(w, pos.x, pos.y, pos.z, b, meta)
if (tag != null)
{
TileEntity.createAndLoadEntity(tag) match
{
case te:TileEntity =>
w.getChunkFromBlockCoords(pos.x, pos.z).addTileEntity(te)
case _ =>
}
}
override def move(w: World, x: Int, y: Int, z: Int, side: Int) {
val (b, meta, te) = getBlockInfo(w, x, y, z)
val pos = new BlockCoord(x, y, z).offset(side)
val tag = if (te != null) {
val tag = new NBTTagCompound
te.writeToNBT(tag)
tag.setInteger("x", pos.x)
tag.setInteger("y", pos.y)
tag.setInteger("z", pos.z)
te.onChunkUnload()
w.removeTileEntity(x, y, z)
tag
} else null
uncheckedSetBlock(w, x, y, z, Blocks.air, 0)
uncheckedSetBlock(w, pos.x, pos.y, pos.z, b, meta)
if (tag != null) {
TileEntity.createAndLoadEntity(tag) match {
case te: TileEntity =>
w.getChunkFromBlockCoords(pos.x, pos.z).addTileEntity(te)
case _ =>
}
}
}
override def postMove(w:World, x:Int, y:Int, z:Int){}
override def postMove(w: World, x: Int, y: Int, z: Int) {}
}
class StaticTileMover extends ITileMover
{
override def canMove(w:World, x:Int, y:Int, z:Int) = false
class StaticTileMover extends ITileMover {
override def canMove(w: World, x: Int, y: Int, z: Int) = false
override def move(w:World, x:Int, y:Int, z:Int, side:Int){}
override def move(w: World, x: Int, y: Int, z: Int, side: Int) {}
override def postMove(w:World, x:Int, y:Int, z:Int){}
}
override def postMove(w: World, x: Int, y: Int, z: Int) {}
}
+152 -123
View File
@@ -12,164 +12,193 @@ import net.minecraft.block.Block
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher
import net.minecraft.client.renderer.{OpenGlHelper, RenderBlocks, RenderHelper, Tessellator}
import net.minecraft.client.renderer.{
OpenGlHelper,
RenderBlocks,
RenderHelper,
Tessellator
}
import net.minecraft.world.{EnumSkyBlock, IBlockAccess, World}
import net.minecraftforge.common.util.ForgeDirection
import org.lwjgl.opengl.GL11._
object MovingRenderer
{
var isRendering = false
var renderHack = true
object MovingRenderer {
var isRendering = false
var renderHack = true
private var oldWorld:World = null
private var frame = 0.0f
private var renderBlocks:RenderBlocks = null
private var oldWorld: World = null
private var frame = 0.0f
private var renderBlocks: RenderBlocks = null
private def mc = Minecraft.getMinecraft
private def world = mc.theWorld
private def tes = Tessellator.instance
private val renderStruct: BlockStruct => Unit = { s =>
for (b <- s.preMoveBlocks)
render(b.x, b.y, b.z, renderPos(s, frame))
}
private def render(x:Int, y:Int, z:Int, rpos:Vector3)
{
val oldOcclusion = mc.gameSettings.ambientOcclusion
mc.gameSettings.ambientOcclusion = 0
private def mc = Minecraft.getMinecraft
private def world = mc.theWorld
val block = world.getBlock(x, y, z)
if (block == null) return
private def render(x: Int, y: Int, z: Int, rpos: Vector3) {
val oldOcclusion = mc.gameSettings.ambientOcclusion
mc.gameSettings.ambientOcclusion = 0
val engine = TileEntityRendererDispatcher.instance.field_147553_e
if (engine != null) engine.bindTexture(TextureMap.locationBlocksTexture)
mc.entityRenderer.enableLightmap(frame)
val block = world.getBlock(x, y, z)
if (block == null) return
val light = world.getLightBrightnessForSkyBlocks(x, y, z, block.getLightValue(world, x, y, z))
val l1 = light%65536
val l2 = light/65536
val engine = TileEntityRendererDispatcher.instance.field_147553_e
if (engine != null) engine.bindTexture(TextureMap.locationBlocksTexture)
mc.entityRenderer.enableLightmap(frame)
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, l1, l2)
glColor4f(0, 0, 0, 0)
RenderHelper.disableStandardItemLighting()
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_BLEND)
glDisable(GL_CULL_FACE)
glShadeModel(if (Minecraft.isAmbientOcclusionEnabled) GL_SMOOTH else GL_FLAT)
val light = world.getLightBrightnessForSkyBlocks(
x,
y,
z,
block.getLightValue(world, x, y, z)
)
val l1 = light % 65536
val l2 = light / 65536
for (pass <- 0 to 1)
{
tes.startDrawingQuads()
tes.setTranslation(
-TileEntityRendererDispatcher.staticPlayerX+MathLib.clamp(-1F, 1F, rpos.x.toFloat),
-TileEntityRendererDispatcher.staticPlayerY+MathLib.clamp(-1F, 1F, rpos.y.toFloat),
-TileEntityRendererDispatcher.staticPlayerZ+MathLib.clamp(-1F, 1F, rpos.z.toFloat))
tes.setColorOpaque(1, 1, 1)
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, l1, l2)
glColor4f(0, 0, 0, 0)
RenderHelper.disableStandardItemLighting()
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_BLEND)
glDisable(GL_CULL_FACE)
glShadeModel(
if (Minecraft.isAmbientOcclusionEnabled) GL_SMOOTH else GL_FLAT
)
block.getRenderBlockPass
if (block.canRenderInPass(pass))
{
renderHack = false
renderBlocks.renderBlockByRenderType(block, x, y, z)
renderHack = true
}
for (pass <- 0 to 1) {
val tess = Tessellator.instance
tess.startDrawingQuads()
tess.setTranslation(
-TileEntityRendererDispatcher.staticPlayerX + MathLib
.clamp(-1f, 1f, rpos.x.toFloat),
-TileEntityRendererDispatcher.staticPlayerY + MathLib
.clamp(-1f, 1f, rpos.y.toFloat),
-TileEntityRendererDispatcher.staticPlayerZ + MathLib.clamp(
-1f,
1f,
rpos.z.toFloat
)
)
tess.setColorOpaque(1, 1, 1)
tes.setTranslation(0, 0, 0)
tes.draw()
}
RenderHelper.enableStandardItemLighting()
mc.entityRenderer.disableLightmap(frame)
mc.gameSettings.ambientOcclusion = oldOcclusion
block.getRenderBlockPass
if (block.canRenderInPass(pass)) {
renderHack = false
renderBlocks.renderBlockByRenderType(block, x, y, z)
renderHack = true
}
tess.setTranslation(0, 0, 0)
tess.draw()
}
RenderHelper.enableStandardItemLighting()
mc.entityRenderer.disableLightmap(frame)
mc.gameSettings.ambientOcclusion = oldOcclusion
}
def onRenderWorldEvent() {
if (oldWorld != world) {
oldWorld = world
renderBlocks = new MovingRenderBlocks(new MovingWorld(world))
renderBlocks.renderAllFaces = true
}
def onRenderWorldEvent()
{
if (oldWorld != world)
{
oldWorld = world
renderBlocks = new MovingRenderBlocks(new MovingWorld(world))
renderBlocks.renderAllFaces = true
}
MovementManager2.getWorldStructs(world).foreachStruct(renderStruct)
}
for (s <- MovementManager2.getWorldStructs(world).structs) for (b <- s.preMoveBlocks)
render(b.x, b.y, b.z, renderPos(s, frame))
def onTick() = {
if (oldWorld != null && world == null) {
oldWorld = null
renderBlocks = null
}
}
def onPreRenderTick(time:Float)
{
isRendering = true
frame = time
}
def onPreRenderTick(time: Float) {
isRendering = true
frame = time
}
def onPostRenderTick()
{
isRendering = false
}
def onPostRenderTick() {
isRendering = false
}
def renderPos(s:BlockStruct, partial:Float) =
{
new Vector3(BlockCoord.sideOffsets(s.moveDir))
.multiply(s.progress+s.speed*partial)
}
def renderPos(s: BlockStruct, partial: Float) = {
new Vector3(BlockCoord.sideOffsets(s.moveDir))
.multiply(s.progress + s.speed * partial)
}
}
@SideOnly(Side.CLIENT)
class MovingRenderBlocks(w:IBlockAccess) extends RenderBlocks(w)
{
val eps = 1.0/0x10000
class MovingRenderBlocks(w: IBlockAccess) extends RenderBlocks(w) {
val eps = 1.0 / 0x10000
override def renderStandardBlock(block:Block, x:Int, y:Int, z:Int) =
{
if (MovementManager2.isMoving(Minecraft.getMinecraft.theWorld, x, y, z))
{
if (renderMinX == 0.0D) renderMinX += eps
if (renderMinY == 0.0D) renderMinY += eps
if (renderMinZ == 0.0D) renderMinZ += eps
if (renderMaxX == 1.0D) renderMaxX -= eps
if (renderMaxY == 1.0D) renderMaxY -= eps
if (renderMaxZ == 1.0D) renderMaxZ -= eps
}
super.renderStandardBlock(block, x, y, z)
override def renderStandardBlock(block: Block, x: Int, y: Int, z: Int) = {
if (MovementManager2.isMoving(Minecraft.getMinecraft.theWorld, x, y, z)) {
if (renderMinX == 0.0d) renderMinX += eps
if (renderMinY == 0.0d) renderMinY += eps
if (renderMinZ == 0.0d) renderMinZ += eps
if (renderMaxX == 1.0d) renderMaxX -= eps
if (renderMaxY == 1.0d) renderMaxY -= eps
if (renderMaxZ == 1.0d) renderMaxZ -= eps
}
super.renderStandardBlock(block, x, y, z)
}
}
class MovingWorld(val world:World) extends IBlockAccess
{
override def getBlock(x:Int, y:Int, z:Int) = world.getBlock(x, y, z)
class MovingWorld(val world: World) extends IBlockAccess {
override def getBlock(x: Int, y: Int, z: Int) = world.getBlock(x, y, z)
override def getTileEntity(x:Int, y:Int, z:Int) = world.getTileEntity(x, y, z)
override def getTileEntity(x: Int, y: Int, z: Int) =
world.getTileEntity(x, y, z)
def computeLightValue(x:Int, y:Int, z:Int, tpe:EnumSkyBlock) =
{
(for (s <- 0 until 6; c = new BlockCoord(x, y, z).offset(s))
yield world.getSavedLightValue(tpe, c.x, c.y, c.z)).max
def computeLightValue(x: Int, y: Int, z: Int, tpe: EnumSkyBlock) = {
(for (s <- 0 until 6; c = new BlockCoord(x, y, z).offset(s))
yield world.getSavedLightValue(tpe, c.x, c.y, c.z)).max
}
@SideOnly(Side.CLIENT)
override def getLightBrightnessForSkyBlocks(
x: Int,
y: Int,
z: Int,
light: Int
) =
MovementManager2.isMoving(Minecraft.getMinecraft.theWorld, x, y, z) match {
case true =>
val l1 = computeLightValue(x, y, z, EnumSkyBlock.Sky)
val l2 = computeLightValue(x, y, z, EnumSkyBlock.Block)
l1 << 20 | Seq(l2, light).max << 4
case false => world.getLightBrightnessForSkyBlocks(x, y, z, light)
}
@SideOnly(Side.CLIENT)
override def getLightBrightnessForSkyBlocks(x:Int, y:Int, z:Int, light:Int) =
MovementManager2.isMoving(Minecraft.getMinecraft.theWorld, x, y, z) match
{
case true =>
val l1 = computeLightValue(x, y, z, EnumSkyBlock.Sky)
val l2 = computeLightValue(x, y, z, EnumSkyBlock.Block)
l1<<20|Seq(l2, light).max<<4
case false => world.getLightBrightnessForSkyBlocks(x, y, z, light)
}
override def getBlockMetadata(x: Int, y: Int, z: Int) =
world.getBlockMetadata(x, y, z)
override def getBlockMetadata(x:Int, y:Int, z:Int) = world.getBlockMetadata(x, y, z)
@SideOnly(Side.CLIENT)
override def isAirBlock(x: Int, y: Int, z: Int) = world.isAirBlock(x, y, z)
@SideOnly(Side.CLIENT)
override def isAirBlock(x:Int, y:Int, z:Int) = world.isAirBlock(x, y, z)
@SideOnly(Side.CLIENT)
override def getBiomeGenForCoords(x: Int, z: Int) =
world.getBiomeGenForCoords(x, z)
@SideOnly(Side.CLIENT)
override def getBiomeGenForCoords(x:Int, z:Int) = world.getBiomeGenForCoords(x, z)
@SideOnly(Side.CLIENT)
override def getHeight = world.getHeight
@SideOnly(Side.CLIENT)
override def getHeight = world.getHeight
@SideOnly(Side.CLIENT)
override def extendedLevelsInChunkCache() = world.extendedLevelsInChunkCache()
@SideOnly(Side.CLIENT)
override def extendedLevelsInChunkCache() = world.extendedLevelsInChunkCache()
override def isBlockProvidingPowerTo(x: Int, y: Int, z: Int, side: Int) =
world.isBlockProvidingPowerTo(x, y, z, side)
override def isBlockProvidingPowerTo(x:Int, y:Int, z:Int, side:Int) =
world.isBlockProvidingPowerTo(x, y, z, side)
override def isSideSolid(x:Int, y:Int, z:Int, side:ForgeDirection, _default:Boolean) =
world.isSideSolid(x, y, z, side, _default)
}
override def isSideSolid(
x: Int,
y: Int,
z: Int,
side: ForgeDirection,
_default: Boolean
) =
world.isSideSolid(x, y, z, side, _default)
}
+90 -69
View File
@@ -5,7 +5,12 @@
*/
package mrtjp.relocation
import java.util.{ArrayList => JAList, List => JList, Set => JSet, TreeSet => JTreeSet}
import java.util.{
ArrayList => JAList,
List => JList,
Set => JSet,
TreeSet => JTreeSet
}
import codechicken.lib.vec.BlockCoord
import cpw.mods.fml.common.ObfuscationReflectionHelper
@@ -19,78 +24,94 @@ import net.minecraft.world._
import scala.collection.JavaConversions._
import scala.collection.immutable.HashSet
object Utils
{
def rescheduleTicks(world:World, blocks:Set[BlockCoord], allBlocks:Set[BlockCoord], dir:Int) = world match
{
case world:WorldServer =>
val hash = ObfuscationReflectionHelper.getPrivateValue(classOf[WorldServer], world, "field_73064_N",
"pendingTickListEntriesHashSet").asInstanceOf[JSet[NextTickListEntry]]
object Utils {
def rescheduleTicks(
world: World,
blocks: Set[BlockCoord],
allBlocks: Set[BlockCoord],
dir: Int
) = world match {
case world: WorldServer =>
val hash = ObfuscationReflectionHelper
.getPrivateValue(
classOf[WorldServer],
world,
"field_73064_N",
"pendingTickListEntriesHashSet"
)
.asInstanceOf[JSet[NextTickListEntry]]
val tree = ObfuscationReflectionHelper.getPrivateValue(classOf[WorldServer], world, "field_73065_O",
"pendingTickListEntriesTreeSet").asInstanceOf[JTreeSet[NextTickListEntry]]
val tree = ObfuscationReflectionHelper
.getPrivateValue(
classOf[WorldServer],
world,
"field_73065_O",
"pendingTickListEntriesTreeSet"
)
.asInstanceOf[JTreeSet[NextTickListEntry]]
val list = ObfuscationReflectionHelper.getPrivateValue(classOf[WorldServer], world, "field_94579_S",
"pendingTickListEntriesThisTick").asInstanceOf[JAList[NextTickListEntry]]
val list = ObfuscationReflectionHelper
.getPrivateValue(
classOf[WorldServer],
world,
"field_94579_S",
"pendingTickListEntriesThisTick"
)
.asInstanceOf[JAList[NextTickListEntry]]
val isOptifine = world.getClass.getName == "WorldServerOF"
val isOptifine = world.getClass.getName == "WorldServerOF"
val chunks = allBlocks.map(b => world.getChunkFromBlockCoords(b.x, b.z)).filter(_ != null)
val chunks = allBlocks
.map(b => world.getChunkFromBlockCoords(b.x, b.z))
.filter(_ != null)
val scheduledTicks = chunks.flatMap(ch => world.getPendingBlockUpdates(ch, !isOptifine)
.asInstanceOf[JAList[NextTickListEntry]] match
{
case null => HashSet[NextTickListEntry]()
case tList => tList.toSet
})
if (isOptifine) for (tick <- scheduledTicks)
{
tree.remove(tick)
hash.remove(tick)
list.remove(tick)
}
for (tick <- scheduledTicks)
{
val bc = new BlockCoord(tick.xCoord, tick.yCoord, tick.zCoord)
if (blocks(bc))
{
bc.offset(dir)
tick.xCoord = bc.x
tick.yCoord = bc.y
tick.zCoord = bc.z
}
}
for (tick <- scheduledTicks) if (!hash.contains(tick))
{
hash.add(tick)
tree.add(tick)
}
case _ =>
}
def rerenderBlocks(world:World, blocks:Set[BlockCoord])
{
if (world.isRemote)
{
val mc = Minecraft.getMinecraft
val teList = mc.renderGlobal.tileEntities.asInstanceOf[JList[TileEntity]]
for (pass <- 0 to 1)
{
for(c <- blocks; te = world.getTileEntity(c.x, c.y, c.z))
{
if (te != null) pass match
{
case 0 => teList.remove(te)
case 1 => teList.add(te)
}
mc.renderGlobal.markBlockForRenderUpdate(c.x, c.y, c.z)
}
mc.renderGlobal.updateRenderers(mc.renderViewEntity, false)
}
val scheduledTicks = chunks.flatMap(ch =>
world
.getPendingBlockUpdates(ch, !isOptifine)
.asInstanceOf[JAList[NextTickListEntry]] match {
case null => HashSet[NextTickListEntry]()
case tList => tList.toSet
}
)
if (isOptifine) for (tick <- scheduledTicks) {
tree.remove(tick)
hash.remove(tick)
list.remove(tick)
}
for (tick <- scheduledTicks) {
val bc = new BlockCoord(tick.xCoord, tick.yCoord, tick.zCoord)
if (blocks(bc)) {
bc.offset(dir)
tick.xCoord = bc.x
tick.yCoord = bc.y
tick.zCoord = bc.z
}
}
for (tick <- scheduledTicks) if (!hash.contains(tick)) {
hash.add(tick)
tree.add(tick)
}
case _ =>
}
def rerenderBlocks(world: World, blocks: Set[BlockCoord]) {
if (world.isRemote) {
val mc = Minecraft.getMinecraft
val teList = mc.renderGlobal.tileEntities.asInstanceOf[JList[TileEntity]]
for (pass <- 0 to 1) {
for (c <- blocks; te = world.getTileEntity(c.x, c.y, c.z)) {
if (te != null) pass match {
case 0 => teList.remove(te)
case 1 => teList.add(te)
}
mc.renderGlobal.markBlockForRenderUpdate(c.x, c.y, c.z)
}
mc.renderGlobal.updateRenderers(mc.renderViewEntity, false)
}
}
}
}
}