Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bee6aa9c4 | ||
|
|
21da7aae0e | ||
|
|
eacf6f7dd7 | ||
|
|
cd90218a37 | ||
|
|
93b3283d8b | ||
|
|
51cc5d1cd1 | ||
|
|
614b2d4e3e | ||
|
|
aebd3ebf8c | ||
|
|
ccb66ee3b1 | ||
|
|
d37209b9e1 | ||
|
|
972ccacc69 | ||
|
|
e58530f587 | ||
|
|
c75c509fda | ||
|
|
b2c051b597 | ||
|
|
5b34a69e2b | ||
|
|
582ed32314 | ||
|
|
f1324c86be | ||
|
|
77d2debe5d | ||
|
|
cca754773a | ||
|
|
ebc1762cb6 | ||
|
|
6820516d89 | ||
|
|
3529de5863 | ||
|
|
58973e61f7 | ||
|
|
35ca8210c0 | ||
|
|
b13c6544b6 | ||
|
|
9be7a99f25 | ||
|
|
cffa422164 | ||
|
|
79ea033e26 | ||
|
|
da006885b4 |
No files matched your search
@@ -0,0 +1,2 @@
|
||||
# Ignore spotlessApply reformat
|
||||
79ea033e261260e200647154a04f97c5e638b07a
|
||||
@@ -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
|
||||
@@ -30,3 +30,4 @@ src/main/resources/mixins.*.json
|
||||
*.bat
|
||||
*.DS_Store
|
||||
!gradlew.bat
|
||||
layout.json
|
||||
@@ -1,6 +0,0 @@
|
||||
jar {
|
||||
manifest {
|
||||
attributes 'FMLCorePlugin': 'mrtjp.relocation.asm.RelocationPlugin'
|
||||
attributes 'FMLCorePluginContainsFMLMod': true
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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" "$@"
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,2 @@
|
||||
repositories {
|
||||
maven {
|
||||
name 'GTNH Maven'
|
||||
url 'http://jenkins.usrv.eu:8081/nexus/content/repositories/public/'
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@@ -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"
|
||||
}]
|
||||
|
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 205 KiB |
@@ -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": ""
|
||||
}]
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||