mirror of
https://github.com/GTNewHorizons/CodeChickenCore.git
synced 2026-11-15 09:34:53 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd7d5c269f | ||
|
|
89dac36ebc | ||
|
|
18bac36c10 | ||
|
|
a9643dba1c | ||
|
|
31d26db5b4 | ||
|
|
2077a8da86 | ||
|
|
ba757e4237 | ||
|
|
b738e8e073 | ||
|
|
a385d29ab3 | ||
|
|
60d44f3c7b | ||
|
|
6209831d08 | ||
|
|
7ae8b15810 | ||
|
|
08f3e4d42a | ||
|
|
9bd4c63b00 | ||
|
|
6e90633d31 | ||
|
|
f02dbc956c | ||
|
|
63f36ca383 | ||
|
|
bb008a1265 | ||
|
|
bb98bdc6d4 | ||
|
|
4e5bcf829c | ||
|
|
678970e48b | ||
|
|
5ad7ebe1ac | ||
|
|
033009fed5 | ||
|
|
acd863e748 | ||
|
|
850e2b9368 | ||
|
|
4713f7aebd | ||
|
|
b999279656 | ||
|
|
1879ba2071 | ||
|
|
9d600169ac | ||
|
|
4e7eb37f3f |
No files matched your search
@@ -3,9 +3,9 @@ name: Build and test
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master, main ]
|
branches: [ master, main, release/** ]
|
||||||
push:
|
push:
|
||||||
branches: [ master, main ]
|
branches: [ master, main, release/** ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-test:
|
build-and-test:
|
||||||
|
|||||||
@@ -27,3 +27,6 @@ whitelist.json
|
|||||||
*.iws
|
*.iws
|
||||||
src/main/resources/mixins.*.json
|
src/main/resources/mixins.*.json
|
||||||
*.bat
|
*.bat
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
*.sh
|
||||||
@@ -6,3 +6,10 @@ minecraft {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
testLogging {
|
||||||
|
events "passed", "skipped", "failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,3 +3,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.gtnewhorizons.gtnhconvention'
|
id 'com.gtnewhorizons.gtnhconvention'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
minecraft {
|
||||||
|
//extraRunJvmArguments.add("-Dccc.dev.runtimePublic=true")
|
||||||
|
//extraRunJvmArguments.add("-Dccc.dev.deobfuscate=true")
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
// Add your dependencies here
|
// Add your dependencies here
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
testImplementation(platform('org.junit:junit-bom:5.14.1'))
|
||||||
|
testImplementation('org.junit.jupiter:junit-jupiter')
|
||||||
|
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
|
||||||
}
|
}
|
||||||
+46
-6
@@ -14,7 +14,7 @@ modId = CodeChickenCore
|
|||||||
modGroup = codechicken
|
modGroup = codechicken
|
||||||
|
|
||||||
# Whether to use modGroup as the maven publishing group.
|
# Whether to use modGroup as the maven publishing group.
|
||||||
# Due to a history of using JitPack, the default is com.github.GTNewHorizons for all mods.
|
# When false, com.github.GTNewHorizons is used.
|
||||||
useModGroupForPublishing = false
|
useModGroupForPublishing = false
|
||||||
|
|
||||||
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
|
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
|
||||||
@@ -39,9 +39,33 @@ remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/co
|
|||||||
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
|
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
|
||||||
developmentEnvironmentUserName = Developer
|
developmentEnvironmentUserName = Developer
|
||||||
|
|
||||||
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
|
# Enables modern Java syntax support. Valid values:
|
||||||
# See https://github.com/bsideup/jabel for details on how this works.
|
# - false: No modern syntax, Java 8 only
|
||||||
enableModernJavaSyntax = true
|
# - 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 = jabel
|
||||||
|
|
||||||
|
# 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.
|
# 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.
|
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
|
||||||
@@ -90,7 +114,9 @@ usesMixinDebug = false
|
|||||||
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
||||||
mixinPlugin =
|
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 =
|
mixinsPackage =
|
||||||
|
|
||||||
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
||||||
@@ -145,7 +171,7 @@ modrinthProjectId = codechickencore-unofficial
|
|||||||
# type can be one of [project, version],
|
# type can be one of [project, version],
|
||||||
# and the name is the Modrinth project or version slug/id of the other mod.
|
# 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
|
# 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 =
|
modrinthRelations =
|
||||||
|
|
||||||
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
||||||
@@ -154,6 +180,11 @@ modrinthRelations =
|
|||||||
# Leave this empty if you don't want to publish on CurseForge.
|
# Leave this empty if you don't want to publish on CurseForge.
|
||||||
curseForgeProjectId = 746279
|
curseForgeProjectId = 746279
|
||||||
|
|
||||||
|
# Comma-separated supported CurseForge environments: client, server (case-insensitive).
|
||||||
|
# Use client or server for mods that only support one environment. Defaults to client,server.
|
||||||
|
# These tags describe where the mod can run, not whether installation is required on both sides.
|
||||||
|
curseForgeEnvironments = client,server
|
||||||
|
|
||||||
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
||||||
# Syntax: type1:name1;type2:name2;...
|
# Syntax: type1:name1;type2:name2;...
|
||||||
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
||||||
@@ -166,6 +197,12 @@ curseForgeRelations =
|
|||||||
# projects. New projects should not use this parameter.
|
# projects. New projects should not use this parameter.
|
||||||
# customArchiveBaseName =
|
# customArchiveBaseName =
|
||||||
|
|
||||||
|
# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory.
|
||||||
|
# runClientWorkingDirectory = run/client
|
||||||
|
|
||||||
|
# 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.
|
# 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'.
|
# 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.
|
# The check is ONLY performed if the version is a git tag.
|
||||||
@@ -195,3 +232,6 @@ curseForgeRelations =
|
|||||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||||
# ideaCheckSpotlessOnBuild = true
|
# 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/539ea72837c6244075f8ee037babc29e/redirect
|
||||||
|
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
|
||||||
|
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect
|
||||||
|
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
|
||||||
|
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9064f22734b42ac03e85df04b632e167/redirect
|
||||||
|
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/4d0277c49991306ac78048580fe34bcf/redirect
|
||||||
|
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect
|
||||||
|
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect
|
||||||
|
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/a9fa3b809e484a1e1ac4308a5dda661a/redirect
|
||||||
|
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/aa99913fa6d767d899ffc96082da01ca/redirect
|
||||||
|
toolchainVersion=25
|
||||||
Vendored
BIN
Binary file not shown.
+3
-1
@@ -1,7 +1,9 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
|
retries=0
|
||||||
|
retryBackOffMs=500
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright © 2015-2021 the original authors.
|
# Copyright © 2015 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
# gradlew start up script for POSIX generated by Gradle.
|
||||||
#
|
#
|
||||||
# Important for running:
|
# Important for running:
|
||||||
#
|
#
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
# bash, then to run this script, type that shell name before the whole
|
# bash, then to run this script, type that shell name before the whole
|
||||||
# command line, like:
|
# command line, like:
|
||||||
#
|
#
|
||||||
# ksh Gradle
|
# ksh gradlew
|
||||||
#
|
#
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
# requires all of these POSIX shell features:
|
# requires all of these POSIX shell features:
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -86,8 +86,7 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# 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
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
' "$PWD" ) || exit
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -115,7 +114,6 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -173,7 +171,6 @@ fi
|
|||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if "$cygwin" || "$msys" ; then
|
if "$cygwin" || "$msys" ; then
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
@@ -206,15 +203,14 @@ fi
|
|||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# and any embedded shellness will be escaped.
|
# 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
|
# * 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.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
Vendored
+12
-24
@@ -19,12 +19,12 @@
|
|||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem gradlew startup script for Windows
|
||||||
@rem
|
@rem
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables, and ensure extensions are enabled
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
setlocal EnableExtensions
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
@@ -51,7 +51,7 @@ echo. 1>&2
|
|||||||
echo Please set the JAVA_HOME variable in your environment to match the 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
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
"%COMSPEC%" /c exit 1
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
@@ -65,30 +65,18 @@ echo. 1>&2
|
|||||||
echo Please set the JAVA_HOME variable in your environment to match the 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
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
"%COMSPEC%" /c exit 1
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute gradlew
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||||
|
@rem which allows us to clear the local environment before executing the java command
|
||||||
|
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
||||||
|
|
||||||
:end
|
:exitWithErrorLevel
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
||||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
"%COMSPEC%" /c exit %ERRORLEVEL%
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
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
|
|
||||||
|
|
||||||
:omega
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
// Add any additional repositiroes for your dependencies here
|
// Add any additional repositiroes for your dependencies here
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
}
|
}
|
||||||
+1
-1
@@ -17,7 +17,7 @@ pluginManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.29'
|
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.30'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
package codechicken.core;
|
package codechicken.core;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
import net.minecraft.launchwrapper.Launch;
|
import net.minecraft.launchwrapper.Launch;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
@@ -22,6 +23,7 @@ import cpw.mods.fml.common.Loader;
|
|||||||
import cpw.mods.fml.common.ModClassLoader;
|
import cpw.mods.fml.common.ModClassLoader;
|
||||||
import cpw.mods.fml.relauncher.CoreModManager;
|
import cpw.mods.fml.relauncher.CoreModManager;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class ClassDiscoverer {
|
public class ClassDiscoverer {
|
||||||
|
|
||||||
public IStringMatcher matcher;
|
public IStringMatcher matcher;
|
||||||
@@ -35,17 +37,12 @@ public class ClassDiscoverer {
|
|||||||
for (int i = 0; i < superclasses.length; i++)
|
for (int i = 0; i < superclasses.length; i++)
|
||||||
this.superclasses[i] = superclasses[i].getName().replace('.', '/');
|
this.superclasses[i] = superclasses[i].getName().replace('.', '/');
|
||||||
|
|
||||||
classes = new ArrayList<Class<?>>();
|
classes = new ArrayList<>();
|
||||||
modClassLoader = (ModClassLoader) Loader.instance().getModClassLoader();
|
modClassLoader = (ModClassLoader) Loader.instance().getModClassLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassDiscoverer(Class<?>... superclasses) {
|
public ClassDiscoverer(Class<?>... superclasses) {
|
||||||
this(new IStringMatcher() {
|
this(test -> true, superclasses);
|
||||||
|
|
||||||
public boolean matches(String test) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}, superclasses);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Class<?>> findClasses() {
|
public ArrayList<Class<?>> findClasses() {
|
||||||
@@ -63,7 +60,7 @@ public class ClassDiscoverer {
|
|||||||
byte[] bytes = Launch.classLoader.getClassBytes(classname);
|
byte[] bytes = Launch.classLoader.getClassBytes(classname);
|
||||||
if (bytes == null) return;
|
if (bytes == null) return;
|
||||||
|
|
||||||
ClassNode cnode = ASMHelper.createClassNode(bytes);
|
ClassNode cnode = ASMHelper.createClassNode(bytes, ClassReader.SKIP_CODE);
|
||||||
for (String superclass : superclasses)
|
for (String superclass : superclasses)
|
||||||
if (!cnode.interfaces.contains(superclass) && !cnode.superName.equals(superclass)) return;
|
if (!cnode.interfaces.contains(superclass) && !cnode.superName.equals(superclass)) return;
|
||||||
|
|
||||||
@@ -86,7 +83,7 @@ public class ClassDiscoverer {
|
|||||||
List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries())
|
List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries())
|
||||||
.addAll(CoreModManager.getLoadedCoremods()).build();
|
.addAll(CoreModManager.getLoadedCoremods()).build();
|
||||||
File[] minecraftSources = modClassLoader.getParentSources();
|
File[] minecraftSources = modClassLoader.getParentSources();
|
||||||
HashSet<String> searchedSources = new HashSet<String>();
|
HashSet<String> searchedSources = new HashSet<>();
|
||||||
for (File minecraftSource : minecraftSources) {
|
for (File minecraftSource : minecraftSources) {
|
||||||
if (searchedSources.contains(minecraftSource.getAbsolutePath())) continue;
|
if (searchedSources.contains(minecraftSource.getAbsolutePath())) continue;
|
||||||
searchedSources.add(minecraftSource.getAbsolutePath());
|
searchedSources.add(minecraftSource.getAbsolutePath());
|
||||||
@@ -114,21 +111,19 @@ public class ClassDiscoverer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readFromZipFile(File file) throws IOException {
|
private void readFromZipFile(File file) throws IOException {
|
||||||
FileInputStream fileinputstream = new FileInputStream(file);
|
try (ZipFile zipFile = new ZipFile(file)) {
|
||||||
ZipInputStream zipinputstream = new ZipInputStream(fileinputstream);
|
Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
|
||||||
do {
|
while (zipEntries.hasMoreElements()) {
|
||||||
ZipEntry zipentry = zipinputstream.getNextEntry();
|
ZipEntry zipentry = zipEntries.nextElement();
|
||||||
if (zipentry == null) {
|
String fullname = zipentry.getName().replace('\\', '/');
|
||||||
break;
|
if (fullname.startsWith("META-INF/versions/")) continue;
|
||||||
|
int pos = fullname.lastIndexOf('/');
|
||||||
|
String name = pos == -1 ? fullname : fullname.substring(pos + 1);
|
||||||
|
if (!zipentry.isDirectory() && matcher.matches(name)) {
|
||||||
|
checkAddClass(fullname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
String fullname = zipentry.getName().replace('\\', '/');
|
}
|
||||||
int pos = fullname.lastIndexOf('/');
|
|
||||||
String name = pos == -1 ? fullname : fullname.substring(pos + 1);
|
|
||||||
if (!zipentry.isDirectory() && matcher.matches(name)) {
|
|
||||||
checkAddClass(fullname);
|
|
||||||
}
|
|
||||||
} while (true);
|
|
||||||
fileinputstream.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readFromDirectory(File directory, File basedirectory) {
|
private void readFromDirectory(File directory, File basedirectory) {
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ package codechicken.core;
|
|||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiScreen;
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
|
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||||
|
import net.minecraft.client.resources.IResourceManager;
|
||||||
|
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||||
import net.minecraft.network.NetworkManager;
|
import net.minecraft.network.NetworkManager;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.util.EnumChatFormatting;
|
import net.minecraft.util.EnumChatFormatting;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import codechicken.core.internal.CCCEventHandler;
|
import codechicken.core.internal.CCCEventHandler;
|
||||||
|
import codechicken.lib.colour.LocalizedColours;
|
||||||
import cpw.mods.fml.common.FMLCommonHandler;
|
import cpw.mods.fml.common.FMLCommonHandler;
|
||||||
import cpw.mods.fml.common.ModContainer;
|
import cpw.mods.fml.common.ModContainer;
|
||||||
import cpw.mods.fml.relauncher.Side;
|
import cpw.mods.fml.relauncher.Side;
|
||||||
@@ -65,4 +69,16 @@ public class ClientUtils extends CommonUtils {
|
|||||||
.replace("Supporters:", EnumChatFormatting.AQUA + "Supporters:");
|
.replace("Supporters:", EnumChatFormatting.AQUA + "Supporters:");
|
||||||
GuiModListScroll.register(mod);
|
GuiModListScroll.register(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public static void registerLocalizedColourReloadListener() {
|
||||||
|
((IReloadableResourceManager) mc().getResourceManager())
|
||||||
|
.registerReloadListener(new IResourceManagerReloadListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResourceManagerReload(IResourceManager resourceManager) {
|
||||||
|
LocalizedColours.reloadLocalizedColours();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,7 @@ import org.lwjgl.input.Keyboard;
|
|||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||||
|
import codechicken.lib.colour.LocalizedColours;
|
||||||
import codechicken.lib.gui.GuiDraw;
|
import codechicken.lib.gui.GuiDraw;
|
||||||
import codechicken.lib.vec.Rectangle4i;
|
import codechicken.lib.vec.Rectangle4i;
|
||||||
import cpw.mods.fml.client.GuiModList;
|
import cpw.mods.fml.client.GuiModList;
|
||||||
@@ -148,10 +149,11 @@ public class GuiModListScroll {
|
|||||||
double dy = scroll % (height + 20);
|
double dy = scroll % (height + 20);
|
||||||
GL11.glPushMatrix();
|
GL11.glPushMatrix();
|
||||||
GL11.glTranslated(0, -dy, 0);
|
GL11.glTranslated(0, -dy, 0);
|
||||||
GuiDraw.fontRenderer.drawSplitString(description, x1, y1draw, x2 - x1, 0xDDDDDD);
|
GuiDraw.fontRenderer.drawSplitString(description, x1, y1draw, x2 - x1, LocalizedColours.MOD_DESCRIPTION_TEXT);
|
||||||
if (needsScroll) {
|
if (needsScroll) {
|
||||||
GL11.glTranslated(0, height + 20, 0);
|
GL11.glTranslated(0, height + 20, 0);
|
||||||
GuiDraw.fontRenderer.drawSplitString(description, x1, y1draw, x2 - x1, 0xDDDDDD);
|
GuiDraw.fontRenderer
|
||||||
|
.drawSplitString(description, x1, y1draw, x2 - x1, LocalizedColours.MOD_DESCRIPTION_TEXT);
|
||||||
}
|
}
|
||||||
GL11.glPopMatrix();
|
GL11.glPopMatrix();
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,22 @@ public class ReflectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a field of the object {@code instance} of type {@code class1} to {@code value}.
|
||||||
|
*
|
||||||
|
* @deprecated According to {@link Class#getDeclaredFields()}, the array of fields has no defined order, therefore
|
||||||
|
* selecting a field based on its index will result in JVM-specific behaviour. Use
|
||||||
|
* {@link #setField(Class, Object, String, Object)} instead.
|
||||||
|
*
|
||||||
|
* @param class1 The class which defines the field in question.
|
||||||
|
* @param instance The object being altered - must be an instance of {@code class1}
|
||||||
|
* @param fieldindex The index of the field being set.
|
||||||
|
* @param value The value to set the field to.
|
||||||
|
* @throws IllegalArgumentException If {@code instance} is not an instance of {@code class1}, or if {@code value}
|
||||||
|
* doesn't match the type of the field.
|
||||||
|
* @throws IllegalAccessException If unable to write to the field.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static void setField(Class<?> class1, Object instance, int fieldindex, Object value)
|
public static void setField(Class<?> class1, Object instance, int fieldindex, Object value)
|
||||||
throws IllegalArgumentException, IllegalAccessException {
|
throws IllegalArgumentException, IllegalAccessException {
|
||||||
Field field = class1.getDeclaredFields()[fieldindex];
|
Field field = class1.getDeclaredFields()[fieldindex];
|
||||||
@@ -179,6 +195,21 @@ public class ReflectionManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a field of the object {@code instance} of type {@code class1}.
|
||||||
|
*
|
||||||
|
* @deprecated According to {@link Class#getDeclaredFields()}, the array of fields has no defined order, therefore
|
||||||
|
* selecting a field based on its index will result in JVM-specific behaviour. Use
|
||||||
|
* {@link #getField(Class, Class, Object, String)} instead.
|
||||||
|
*
|
||||||
|
* @param class1 The class which defines the field in question.
|
||||||
|
* @param fieldType The type of the field being read.
|
||||||
|
* @param instance The object being read from - must be an instance of {@code class1}
|
||||||
|
* @param fieldIndex The index of the field being read.
|
||||||
|
* @throws IllegalArgumentException If {@code instance} is not an instance of {@code class1}.
|
||||||
|
* @throws IllegalAccessException If unable to read from the field.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static <T> T getField(Class<?> class1, Class<T> fieldType, Object instance, int fieldIndex)
|
public static <T> T getField(Class<?> class1, Class<T> fieldType, Object instance, int fieldIndex)
|
||||||
throws IllegalArgumentException, IllegalAccessException {
|
throws IllegalArgumentException, IllegalAccessException {
|
||||||
Field field = class1.getDeclaredFields()[fieldIndex];
|
Field field = class1.getDeclaredFields()[fieldIndex];
|
||||||
|
|||||||
@@ -5,32 +5,19 @@ import java.lang.reflect.Field;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableBiMap;
|
import com.google.common.collect.ImmutableBiMap;
|
||||||
|
|
||||||
import codechicken.lib.asm.ObfMapping;
|
|
||||||
import cpw.mods.fml.common.asm.transformers.AccessTransformer;
|
import cpw.mods.fml.common.asm.transformers.AccessTransformer;
|
||||||
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
||||||
|
|
||||||
|
// This AccessTransformer will make all minecraft classes public at runtime in MCP just as they are in modloader.
|
||||||
|
// You should ONLY use this when you are testing with a mod that relies on runtime publicity and doesn't include
|
||||||
|
// access transformers. Such mods are doing the wrong thing and should be fixed.
|
||||||
public class CodeChickenAccessTransformer extends AccessTransformer {
|
public class CodeChickenAccessTransformer extends AccessTransformer {
|
||||||
|
|
||||||
private static boolean makeAllPublic;
|
private static final Field f_classNameBiMap;
|
||||||
private static Field f_classNameBiMap;
|
@SuppressWarnings("FieldMayBeFinal")
|
||||||
private static Object emptyMap = ImmutableBiMap.of();
|
private static Object emptyMap = ImmutableBiMap.of();
|
||||||
|
|
||||||
public CodeChickenAccessTransformer() throws IOException {
|
static {
|
||||||
super();
|
|
||||||
loadPublicConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadPublicConfig() {
|
|
||||||
if (ObfMapping.obfuscated) return;
|
|
||||||
|
|
||||||
makeAllPublic = CodeChickenCoreModContainer.config.getTag("dev.runtimePublic").setComment(
|
|
||||||
"Enabling this setting will make all minecraft classes public at runtime in MCP just as they are in modloader."
|
|
||||||
+ "\nYou should ONLY use this when you are testing with a mod that relies on runtime publicity and doesn't include access transformers."
|
|
||||||
+ "\nSuch mods are doing the wrong thing and should be fixed.")
|
|
||||||
.getBooleanValue(false);
|
|
||||||
|
|
||||||
if (!makeAllPublic) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f_classNameBiMap = FMLDeobfuscatingRemapper.class.getDeclaredField("classNameBiMap");
|
f_classNameBiMap = FMLDeobfuscatingRemapper.class.getDeclaredField("classNameBiMap");
|
||||||
f_classNameBiMap.setAccessible(true);
|
f_classNameBiMap.setAccessible(true);
|
||||||
@@ -39,16 +26,18 @@ public class CodeChickenAccessTransformer extends AccessTransformer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CodeChickenAccessTransformer() throws IOException {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||||
boolean setPublic = makeAllPublic && name.startsWith("net.minecraft.");
|
boolean setPublic = name.startsWith("net.minecraft.");
|
||||||
if (setPublic) setClassMap(name);
|
if (setPublic) setClassMap(name);
|
||||||
bytes = super.transform(name, transformedName, bytes);
|
bytes = super.transform(name, transformedName, bytes);
|
||||||
if (setPublic) restoreClassMap();
|
if (setPublic) restoreClassMap();
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreClassMap() {
|
private static void restoreClassMap() {
|
||||||
try {
|
try {
|
||||||
f_classNameBiMap.set(FMLDeobfuscatingRemapper.INSTANCE, emptyMap);
|
f_classNameBiMap.set(FMLDeobfuscatingRemapper.INSTANCE, emptyMap);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -56,7 +45,7 @@ public class CodeChickenAccessTransformer extends AccessTransformer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setClassMap(String name) {
|
private static void setClassMap(String name) {
|
||||||
try {
|
try {
|
||||||
f_classNameBiMap.set(FMLDeobfuscatingRemapper.INSTANCE, ImmutableBiMap.of(name.replace('.', '/'), ""));
|
f_classNameBiMap.set(FMLDeobfuscatingRemapper.INSTANCE, ImmutableBiMap.of(name.replace('.', '/'), ""));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package codechicken.core.asm;
|
package codechicken.core.asm;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -13,7 +12,6 @@ import codechicken.core.ClientUtils;
|
|||||||
import codechicken.core.featurehack.LiquidTextures;
|
import codechicken.core.featurehack.LiquidTextures;
|
||||||
import codechicken.core.internal.CCCEventHandler;
|
import codechicken.core.internal.CCCEventHandler;
|
||||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||||
import codechicken.lib.config.ConfigFile;
|
|
||||||
import cpw.mods.fml.common.DummyModContainer;
|
import cpw.mods.fml.common.DummyModContainer;
|
||||||
import cpw.mods.fml.common.FMLCommonHandler;
|
import cpw.mods.fml.common.FMLCommonHandler;
|
||||||
import cpw.mods.fml.common.LoadController;
|
import cpw.mods.fml.common.LoadController;
|
||||||
@@ -26,14 +24,6 @@ import cpw.mods.fml.common.versioning.VersionRange;
|
|||||||
|
|
||||||
public class CodeChickenCoreModContainer extends DummyModContainer {
|
public class CodeChickenCoreModContainer extends DummyModContainer {
|
||||||
|
|
||||||
public static ConfigFile config;
|
|
||||||
|
|
||||||
public static void loadConfig() {
|
|
||||||
if (config == null)
|
|
||||||
config = new ConfigFile(new File(CodeChickenCorePlugin.minecraftDir, "config/CodeChickenCore.cfg"))
|
|
||||||
.setComment("CodeChickenCore configuration file.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeChickenCoreModContainer() {
|
public CodeChickenCoreModContainer() {
|
||||||
super(getModMetadata());
|
super(getModMetadata());
|
||||||
}
|
}
|
||||||
@@ -75,6 +65,7 @@ public class CodeChickenCoreModContainer extends DummyModContainer {
|
|||||||
public void init(FMLInitializationEvent event) {
|
public void init(FMLInitializationEvent event) {
|
||||||
if (event.getSide().isClient()) {
|
if (event.getSide().isClient()) {
|
||||||
ClientUtils.enhanceSupportersList("CodeChickenCore");
|
ClientUtils.enhanceSupportersList("CodeChickenCore");
|
||||||
|
ClientUtils.registerLocalizedColourReloadListener();
|
||||||
|
|
||||||
FMLCommonHandler.instance().bus().register(new CCCEventHandler());
|
FMLCommonHandler.instance().bus().register(new CCCEventHandler());
|
||||||
MinecraftForge.EVENT_BUS.register(new CCCEventHandler());
|
MinecraftForge.EVENT_BUS.register(new CCCEventHandler());
|
||||||
|
|||||||
@@ -7,35 +7,50 @@ import java.util.HashSet;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
import net.minecraft.launchwrapper.IClassTransformer;
|
import net.minecraft.launchwrapper.IClassTransformer;
|
||||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
import net.minecraft.launchwrapper.Launch;
|
||||||
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
import codechicken.lib.asm.ASMHelper;
|
import codechicken.lib.asm.ASMHelper;
|
||||||
import codechicken.lib.asm.ClassHeirachyManager;
|
|
||||||
import codechicken.lib.asm.ObfMapping;
|
import codechicken.lib.asm.ObfMapping;
|
||||||
|
import cpw.mods.fml.relauncher.FMLRelaunchLog;
|
||||||
|
|
||||||
public class DefaultImplementationTransformer implements IClassTransformer {
|
public class DefaultImplementationTransformer implements IClassTransformer {
|
||||||
|
|
||||||
private static LaunchClassLoader cl = (LaunchClassLoader) ClassHeirachyManager.class.getClassLoader();
|
private static final HashMap<String, InterfaceImpl> impls = new HashMap<>();
|
||||||
|
|
||||||
private static ClassNode getClassNode(String name) {
|
public static void registerDefaultImpl(String iname, String cname) {
|
||||||
try {
|
if (impls.isEmpty()) {
|
||||||
return ASMHelper.createClassNode(cl.getClassBytes(name.replace('/', '.')));
|
String name = DefaultImplementationTransformer.class.getName();
|
||||||
} catch (IOException e) {
|
FMLRelaunchLog.finer("Registering transformer %s", name);
|
||||||
throw new RuntimeException(e);
|
Launch.classLoader.registerTransformer(name);
|
||||||
}
|
}
|
||||||
|
impls.put(iname.replace('.', '/'), new InterfaceImpl(iname, cname));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||||
|
if (transformedName.startsWith("net.minecraft") || impls.isEmpty()) return bytes;
|
||||||
|
|
||||||
|
ClassNode cnode = ASMHelper.createClassNode(bytes);
|
||||||
|
boolean changed = false;
|
||||||
|
for (String iname : cnode.interfaces) {
|
||||||
|
InterfaceImpl impl = impls.get(iname);
|
||||||
|
if (impl != null) changed |= impl.patch(cnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed ? ASMHelper.createBytes(cnode, 0) : bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class InterfaceImpl {
|
static class InterfaceImpl {
|
||||||
|
|
||||||
public final String iname;
|
public final String iname;
|
||||||
public ArrayList<MethodNode> impls = new ArrayList<MethodNode>();
|
public ArrayList<MethodNode> impls = new ArrayList<>();
|
||||||
|
|
||||||
public InterfaceImpl(String iname, String cname) {
|
public InterfaceImpl(String iname, String cname) {
|
||||||
this.iname = iname;
|
this.iname = iname;
|
||||||
HashSet<String> names = new HashSet<String>();
|
HashSet<String> names = new HashSet<>();
|
||||||
ClassNode inode = getClassNode(iname);
|
ClassNode inode = getClassNode(iname);
|
||||||
for (MethodNode method : inode.methods) names.add(method.name + method.desc);
|
for (MethodNode method : inode.methods) names.add(method.name + method.desc);
|
||||||
|
|
||||||
@@ -47,7 +62,7 @@ public class DefaultImplementationTransformer implements IClassTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean patch(ClassNode cnode) {
|
public boolean patch(ClassNode cnode) {
|
||||||
LinkedList<String> names = new LinkedList<String>();
|
LinkedList<String> names = new LinkedList<>();
|
||||||
for (MethodNode method : cnode.methods) {
|
for (MethodNode method : cnode.methods) {
|
||||||
ObfMapping m = new ObfMapping(cnode.name, method.name, method.desc).toRuntime();
|
ObfMapping m = new ObfMapping(cnode.name, method.name, method.desc).toRuntime();
|
||||||
names.add(m.s_name + m.s_desc);
|
names.add(m.s_name + m.s_desc);
|
||||||
@@ -69,25 +84,13 @@ public class DefaultImplementationTransformer implements IClassTransformer {
|
|||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static HashMap<String, InterfaceImpl> impls = new HashMap<String, InterfaceImpl>();
|
private static ClassNode getClassNode(String name) {
|
||||||
|
try {
|
||||||
public static void registerDefaultImpl(String iname, String cname) {
|
return ASMHelper.createClassNode(Launch.classLoader.getClassBytes(name.replace('/', '.')));
|
||||||
impls.put(iname.replace('.', '/'), new InterfaceImpl(iname, cname));
|
} catch (IOException e) {
|
||||||
}
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
|
||||||
if (transformedName.startsWith("net.minecraft") || impls.isEmpty()) return bytes;
|
|
||||||
|
|
||||||
ClassNode cnode = ASMHelper.createClassNode(bytes);
|
|
||||||
boolean changed = false;
|
|
||||||
for (String iname : cnode.interfaces) {
|
|
||||||
InterfaceImpl impl = impls.get(iname);
|
|
||||||
if (impl != null) changed |= impl.patch(cnode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed ? ASMHelper.createBytes(cnode, 0) : bytes;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package codechicken.core.asm;
|
package codechicken.core.asm;
|
||||||
|
|
||||||
import static codechicken.core.launch.CodeChickenCorePlugin.logger;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -11,7 +9,9 @@ import java.lang.reflect.Method;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
import net.minecraft.launchwrapper.IClassTransformer;
|
import net.minecraft.launchwrapper.IClassTransformer;
|
||||||
@@ -21,14 +21,18 @@ import net.minecraft.launchwrapper.LaunchClassLoader;
|
|||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
|
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||||
|
import cpw.mods.fml.relauncher.FMLRelaunchLog;
|
||||||
|
|
||||||
public class DelegatedTransformer implements IClassTransformer {
|
public class DelegatedTransformer implements IClassTransformer {
|
||||||
|
|
||||||
private static ArrayList<IClassTransformer> delegatedTransformers;
|
private static final ArrayList<IClassTransformer> delegatedTransformers;
|
||||||
private static Method m_defineClass;
|
private static final Method m_defineClass;
|
||||||
private static Field f_cachedClasses;
|
private static final Field f_cachedClasses;
|
||||||
|
private static IClassTransformer[] transformers;
|
||||||
|
|
||||||
public DelegatedTransformer() {
|
static {
|
||||||
delegatedTransformers = new ArrayList<IClassTransformer>();
|
delegatedTransformers = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
m_defineClass = ClassLoader.class
|
m_defineClass = ClassLoader.class
|
||||||
.getDeclaredMethod("defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE);
|
.getDeclaredMethod("defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE);
|
||||||
@@ -41,14 +45,75 @@ public class DelegatedTransformer implements IClassTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] transform(String name, String tname, byte[] bytes) {
|
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
||||||
if (bytes == null) return null;
|
if (basicClass == null) return null;
|
||||||
for (IClassTransformer trans : delegatedTransformers) bytes = trans.transform(name, tname, bytes);
|
for (IClassTransformer t : transformers) {
|
||||||
return bytes;
|
basicClass = t.transform(name, transformedName, basicClass);
|
||||||
|
}
|
||||||
|
return basicClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void load() {
|
||||||
|
scanModsForDelegatedTransformers();
|
||||||
|
final int size = delegatedTransformers.size();
|
||||||
|
if (size == 0) {
|
||||||
|
CodeChickenCorePlugin.logger
|
||||||
|
.debug("No delegated transformer found, skipping registration of main DelegatedTransformer.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CodeChickenCorePlugin.logger
|
||||||
|
.debug("Found " + size + " delegated transformers, registering main DelegatedTransformer.");
|
||||||
|
transformers = delegatedTransformers.toArray(new IClassTransformer[0]);
|
||||||
|
String name = DelegatedTransformer.class.getName();
|
||||||
|
FMLRelaunchLog.finer("Registering transformer %s", name);
|
||||||
|
Launch.classLoader.registerTransformer(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void scanModsForDelegatedTransformers() {
|
||||||
|
File modsDir = new File(CodeChickenCorePlugin.minecraftDir, "mods");
|
||||||
|
if (modsDir.exists()) {
|
||||||
|
final File[] files = modsDir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
scanMod(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File versionModsDir = new File(
|
||||||
|
CodeChickenCorePlugin.minecraftDir,
|
||||||
|
"mods/" + CodeChickenCorePlugin.currentMcVersion);
|
||||||
|
if (versionModsDir.exists()) {
|
||||||
|
final File[] files = versionModsDir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
scanMod(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void scanMod(File file) {
|
||||||
|
if (!file.getName().endsWith(".jar") && !file.getName().endsWith(".zip")) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
try (JarFile jar = new JarFile(file)) {
|
||||||
|
Manifest manifest = jar.getManifest();
|
||||||
|
if (manifest == null) return;
|
||||||
|
Attributes attr = manifest.getMainAttributes();
|
||||||
|
if (attr == null) return;
|
||||||
|
|
||||||
|
String transformer = attr.getValue("CCTransformer");
|
||||||
|
if (transformer != null) {
|
||||||
|
addTransformer(transformer, jar, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
CodeChickenCorePlugin.logger.error("CodeChickenCore: Failed to read jar file: " + file.getName(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addTransformer(String transformer, JarFile jar, File jarFile) {
|
public static void addTransformer(String transformer, JarFile jar, File jarFile) {
|
||||||
logger.debug("Adding CCTransformer: " + transformer);
|
CodeChickenCorePlugin.logger.debug("Adding CCTransformer: " + transformer);
|
||||||
try {
|
try {
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
bytes = Launch.classLoader.getClassBytes(transformer);
|
bytes = Launch.classLoader.getClassBytes(transformer);
|
||||||
@@ -107,7 +172,7 @@ public class DelegatedTransformer implements IClassTransformer {
|
|||||||
byte[] depbytes = readFully(jar.getInputStream(entry));
|
byte[] depbytes = readFully(jar.getInputStream(entry));
|
||||||
defineDependancies(depbytes, jar, jarFile, depStack);
|
defineDependancies(depbytes, jar, jarFile, depStack);
|
||||||
|
|
||||||
logger.debug("Defining dependancy: " + dependancy);
|
CodeChickenCorePlugin.logger.debug("Defining dependancy: " + dependancy);
|
||||||
|
|
||||||
defineClass(dependancy.replace('/', '.'), depbytes);
|
defineClass(dependancy.replace('/', '.'), depbytes);
|
||||||
}
|
}
|
||||||
@@ -128,7 +193,6 @@ public class DelegatedTransformer implements IClassTransformer {
|
|||||||
while ((r = stream.read()) != -1) {
|
while ((r = stream.read()) != -1) {
|
||||||
bos.write(r);
|
bos.write(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bos.toByteArray();
|
return bos.toByteArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,6 @@ import com.google.common.collect.HashMultimap;
|
|||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
import codechicken.lib.asm.ASMHelper;
|
import codechicken.lib.asm.ASMHelper;
|
||||||
import codechicken.lib.asm.ASMInit;
|
|
||||||
import codechicken.lib.asm.CC_ClassWriter;
|
import codechicken.lib.asm.CC_ClassWriter;
|
||||||
import codechicken.lib.asm.ObfMapping;
|
import codechicken.lib.asm.ObfMapping;
|
||||||
import codechicken.obfuscator.IHeirachyEvaluator;
|
import codechicken.obfuscator.IHeirachyEvaluator;
|
||||||
@@ -35,15 +34,11 @@ import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
|||||||
|
|
||||||
public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes, IHeirachyEvaluator {
|
public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes, IHeirachyEvaluator {
|
||||||
|
|
||||||
static {
|
|
||||||
ASMInit.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LoadPlugin implements IFMLLoadingPlugin {
|
public static class LoadPlugin implements IFMLLoadingPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getASMTransformerClass() {
|
public String[] getASMTransformerClass() {
|
||||||
return new String[0];
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -118,26 +113,20 @@ public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void load() {
|
public static void load() {
|
||||||
CodeChickenCoreModContainer.loadConfig();
|
run = new ObfuscationRun(
|
||||||
|
false,
|
||||||
|
ObfMapping.MCPRemapper.getConfFiles(),
|
||||||
|
ObfuscationRun.fillDefaults(new HashMap<String, String>()));
|
||||||
|
run.obf.setHeirachyEvaluator(instance);
|
||||||
|
run.setQuiet().parseMappings();
|
||||||
|
Collections.addAll(excludedPackages, run.config.get("excludedPackages").split(";"));
|
||||||
|
|
||||||
if (CodeChickenCoreModContainer.config.getTag("dev.deobfuscate")
|
if (ObfMapping.obfuscated) {
|
||||||
.setComment("set to true to completely deobfuscate mcp names")
|
ObfMapping.loadMCPRemapper();
|
||||||
.getBooleanValue(!ObfMapping.obfuscated)) {
|
run.setSeargeConstants();
|
||||||
run = new ObfuscationRun(
|
getTransformers().add(instance);
|
||||||
false,
|
} else {
|
||||||
ObfMapping.MCPRemapper.getConfFiles(),
|
getTransformers().add(0, instance); // insert transformer as first.
|
||||||
ObfuscationRun.fillDefaults(new HashMap<String, String>()));
|
|
||||||
run.obf.setHeirachyEvaluator(instance);
|
|
||||||
run.setQuiet().parseMappings();
|
|
||||||
Collections.addAll(excludedPackages, run.config.get("excludedPackages").split(";"));
|
|
||||||
|
|
||||||
if (ObfMapping.obfuscated) {
|
|
||||||
ObfMapping.loadMCPRemapper();
|
|
||||||
run.setSeargeConstants();
|
|
||||||
getTransformers().add(instance);
|
|
||||||
} else {
|
|
||||||
getTransformers().add(0, instance); // insert transformer as first.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ import static codechicken.lib.asm.InsnComparator.findOnce;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import net.minecraft.launchwrapper.IClassTransformer;
|
import net.minecraft.launchwrapper.IClassTransformer;
|
||||||
|
import net.minecraft.launchwrapper.Launch;
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.tree.JumpInsnNode;
|
import org.objectweb.asm.tree.JumpInsnNode;
|
||||||
import org.objectweb.asm.tree.LabelNode;
|
import org.objectweb.asm.tree.LabelNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||||
import codechicken.lib.asm.ASMBlock;
|
import codechicken.lib.asm.ASMBlock;
|
||||||
import codechicken.lib.asm.ASMInit;
|
|
||||||
import codechicken.lib.asm.ASMReader;
|
import codechicken.lib.asm.ASMReader;
|
||||||
import codechicken.lib.asm.ModularASMTransformer;
|
import codechicken.lib.asm.ModularASMTransformer;
|
||||||
import codechicken.lib.asm.ModularASMTransformer.MethodReplacer;
|
import codechicken.lib.asm.ModularASMTransformer.MethodReplacer;
|
||||||
@@ -20,20 +21,29 @@ import codechicken.lib.asm.ModularASMTransformer.MethodTransformer;
|
|||||||
import codechicken.lib.asm.ModularASMTransformer.MethodWriter;
|
import codechicken.lib.asm.ModularASMTransformer.MethodWriter;
|
||||||
import codechicken.lib.asm.ObfMapping;
|
import codechicken.lib.asm.ObfMapping;
|
||||||
import codechicken.lib.config.ConfigTag;
|
import codechicken.lib.config.ConfigTag;
|
||||||
|
import cpw.mods.fml.relauncher.FMLRelaunchLog;
|
||||||
|
|
||||||
public class TweakTransformer implements IClassTransformer, Opcodes {
|
public class TweakTransformer implements IClassTransformer, Opcodes {
|
||||||
|
|
||||||
static {
|
private static final ModularASMTransformer transformer = new ModularASMTransformer();
|
||||||
ASMInit.init();
|
private static final Map<String, ASMBlock> blocks = ASMReader
|
||||||
}
|
.loadResource("/assets/codechickencore/asm/tweaks.asm");
|
||||||
|
|
||||||
private static ModularASMTransformer transformer = new ModularASMTransformer();
|
|
||||||
private static Map<String, ASMBlock> blocks = ASMReader.loadResource("/assets/codechickencore/asm/tweaks.asm");
|
|
||||||
public static ConfigTag tweaks;
|
public static ConfigTag tweaks;
|
||||||
|
|
||||||
public static void load() {
|
public static void load() {
|
||||||
CodeChickenCoreModContainer.loadConfig();
|
loadTransformersFromConfig();
|
||||||
tweaks = CodeChickenCoreModContainer.config.getTag("tweaks")
|
if (transformer.isEmpty()) {
|
||||||
|
CodeChickenCorePlugin.logger
|
||||||
|
.debug("No tweaks parsed from config, skipping registration of TweakTransformer.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String name = TweakTransformer.class.getName();
|
||||||
|
FMLRelaunchLog.finer("Registering transformer %s", name);
|
||||||
|
Launch.classLoader.registerTransformer(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void loadTransformersFromConfig() {
|
||||||
|
tweaks = CodeChickenCorePlugin.config.getTag("tweaks")
|
||||||
.setComment("Various tweaks that can be applied to game mechanics.").useBraces();
|
.setComment("Various tweaks that can be applied to game mechanics.").useBraces();
|
||||||
tweaks.removeTag("persistantLava");
|
tweaks.removeTag("persistantLava");
|
||||||
|
|
||||||
@@ -103,7 +113,7 @@ public class TweakTransformer implements IClassTransformer, Opcodes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] transform(String name, String tname, byte[] bytes) {
|
public final byte[] transform(String name, String tname, byte[] bytes) {
|
||||||
return transformer.transform(name, bytes);
|
return transformer.transform(name, bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,8 @@ import net.minecraft.util.ResourceLocation;
|
|||||||
|
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import codechicken.lib.colour.LocalizedColours;
|
||||||
|
|
||||||
public class GuiCCButton extends GuiWidget {
|
public class GuiCCButton extends GuiWidget {
|
||||||
|
|
||||||
public String text;
|
public String text;
|
||||||
@@ -73,7 +75,8 @@ public class GuiCCButton extends GuiWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getTextColour(int mousex, int mousey) {
|
public int getTextColour(int mousex, int mousey) {
|
||||||
return !isEnabled ? 0xFFA0A0A0 : pointInside(mousex, mousey) ? 0xFFFFFFA0 : 0xFFE0E0E0;
|
return !isEnabled ? LocalizedColours.BUTTON_TEXT_DISABLED
|
||||||
|
: pointInside(mousex, mousey) ? LocalizedColours.BUTTON_TEXT_HOVER : LocalizedColours.BUTTON_TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GuiCCButton setActionCommand(String string) {
|
public GuiCCButton setActionCommand(String string) {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import net.minecraft.util.ChatAllowedCharacters;
|
|||||||
|
|
||||||
import org.lwjgl.input.Keyboard;
|
import org.lwjgl.input.Keyboard;
|
||||||
|
|
||||||
|
import codechicken.lib.colour.LocalizedColours;
|
||||||
|
|
||||||
public class GuiCCTextField extends GuiWidget {
|
public class GuiCCTextField extends GuiWidget {
|
||||||
|
|
||||||
private String text;
|
private String text;
|
||||||
@@ -120,8 +122,8 @@ public class GuiCCTextField extends GuiWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void drawBackground() {
|
public void drawBackground() {
|
||||||
drawRect(x - 1, y - 1, x + width + 1, y + height + 1, 0xffa0a0a0);
|
drawRect(x - 1, y - 1, x + width + 1, y + height + 1, LocalizedColours.TEXT_FIELD_BORDER);
|
||||||
drawRect(x, y, x + width, y + height, 0xff000000);
|
drawRect(x, y, x + width, y + height, LocalizedColours.TEXT_FIELD_BACKGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDrawText() {
|
public String getDrawText() {
|
||||||
@@ -135,7 +137,7 @@ public class GuiCCTextField extends GuiWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getTextColour() {
|
public int getTextColour() {
|
||||||
return isEnabled ? 0xe0e0e0 : 0x707070;
|
return isEnabled ? LocalizedColours.TEXT_FIELD_TEXT : LocalizedColours.TEXT_FIELD_TEXT_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GuiCCTextField setMaxStringLength(int i) {
|
public GuiCCTextField setMaxStringLength(int i) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package codechicken.core.gui;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
|
||||||
|
import codechicken.lib.colour.LocalizedColours;
|
||||||
import codechicken.lib.math.MathHelper;
|
import codechicken.lib.math.MathHelper;
|
||||||
import codechicken.lib.vec.Rectangle4i;
|
import codechicken.lib.vec.Rectangle4i;
|
||||||
|
|
||||||
@@ -184,28 +185,29 @@ public abstract class GuiScrollPane extends GuiWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void drawBackground(float frame) {
|
public void drawBackground(float frame) {
|
||||||
drawRect(x, y, x + width, y + height, 0xff000000);
|
drawRect(x, y, x + width, y + height, LocalizedColours.SCROLL_PANE_BACKGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void drawContent(int mx, int my, float frame);
|
public abstract void drawContent(int mx, int my, float frame);
|
||||||
|
|
||||||
public void drawOverlay(float frame) {
|
public void drawOverlay(float frame) {
|
||||||
// outlines
|
// outlines
|
||||||
drawRect(x, y - 1, x + width, y, 0xffa0a0a0); // top
|
drawRect(x, y - 1, x + width, y, LocalizedColours.SCROLL_PANE_OVERLAY_TOP);
|
||||||
drawRect(x, y + height, x + width, y + height + 1, 0xffa0a0a0); // bottom
|
drawRect(x, y + height, x + width, y + height + 1, LocalizedColours.SCROLL_PANE_OVERLAY_BOTTOM);
|
||||||
drawRect(x - 1, y - 1, x, y + height + 1, 0xffa0a0a0); // left
|
drawRect(x - 1, y - 1, x, y + height + 1, LocalizedColours.SCROLL_PANE_OVERLAY_LEFT);
|
||||||
drawRect(x + width, y - 1, x + width + 1, y + height + 1, 0xffa0a0a0); // right
|
drawRect(x + width, y - 1, x + width + 1, y + height + 1, LocalizedColours.SCROLL_PANE_OVERLAY_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawScrollbar(float frame) {
|
public void drawScrollbar(float frame) {
|
||||||
Rectangle r = scrollbarBounds();
|
Rectangle r = scrollbarBounds();
|
||||||
|
|
||||||
drawRect(r.x, r.y, r.x + r.width, r.y + r.height, 0xFF8B8B8B); // corners
|
drawRect(r.x, r.y, r.x + r.width, r.y + r.height, LocalizedColours.SCROLLBAR_CORNERS);
|
||||||
drawRect(r.x, r.y, r.x + r.width - 1, r.y + r.height - 1, 0xFFF0F0F0); // topleft up
|
drawRect(r.x, r.y, r.x + r.width - 1, r.y + r.height - 1, LocalizedColours.SCROLLBAR_TOP_LEFT);
|
||||||
drawRect(r.x + 1, r.y + 1, r.x + r.width, r.y + r.height, 0xFF555555); // bottom right down
|
drawRect(r.x + 1, r.y + 1, r.x + r.width, r.y + r.height, LocalizedColours.SCROLLBAR_BOTTOM_RIGHT);
|
||||||
drawRect(r.x + 1, r.y + 1, r.x + r.width - 1, r.y + r.height - 1, 0xFFC6C6C6); // scrollbar
|
drawRect(r.x + 1, r.y + 1, r.x + r.width - 1, r.y + r.height - 1, LocalizedColours.SCROLLBAR_FILL);
|
||||||
|
|
||||||
int algn = scrollbarGuideAlignment();
|
int algn = scrollbarGuideAlignment();
|
||||||
if (algn != 0) drawRect(algn > 0 ? r.x + r.width : r.x - 1, y, r.x, y + height, 0xFF808080); // lineguide
|
if (algn != 0)
|
||||||
|
drawRect(algn > 0 ? r.x + r.width : r.x - 1, y, r.x, y + height, LocalizedColours.SCROLLBAR_GUIDE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,9 +9,6 @@ import java.text.CharacterIterator;
|
|||||||
import java.text.StringCharacterIterator;
|
import java.text.StringCharacterIterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.jar.Attributes;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
import java.util.jar.Manifest;
|
|
||||||
|
|
||||||
import javax.swing.JEditorPane;
|
import javax.swing.JEditorPane;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
@@ -21,48 +18,87 @@ import javax.swing.event.HyperlinkListener;
|
|||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import codechicken.core.asm.CodeChickenCoreModContainer;
|
|
||||||
import codechicken.core.asm.DelegatedTransformer;
|
import codechicken.core.asm.DelegatedTransformer;
|
||||||
import codechicken.core.asm.MCPDeobfuscationTransformer;
|
import codechicken.core.asm.MCPDeobfuscationTransformer;
|
||||||
import codechicken.core.asm.Tags;
|
import codechicken.core.asm.Tags;
|
||||||
import codechicken.core.asm.TweakTransformer;
|
import codechicken.core.asm.TweakTransformer;
|
||||||
|
import codechicken.lib.config.ConfigFile;
|
||||||
import codechicken.lib.config.ConfigTag;
|
import codechicken.lib.config.ConfigTag;
|
||||||
import cpw.mods.fml.common.FMLCommonHandler;
|
import cpw.mods.fml.common.FMLCommonHandler;
|
||||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||||
import cpw.mods.fml.common.versioning.VersionParser;
|
import cpw.mods.fml.common.versioning.VersionParser;
|
||||||
import cpw.mods.fml.relauncher.CoreModManager;
|
import cpw.mods.fml.relauncher.CoreModManager;
|
||||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||||
import cpw.mods.fml.relauncher.IFMLCallHook;
|
|
||||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
|
|
||||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions;
|
|
||||||
|
|
||||||
@TransformerExclusions(value = { "codechicken.core.asm", "codechicken.obfuscator" })
|
@IFMLLoadingPlugin.MCVersion("1.7.10")
|
||||||
@MCVersion("1.7.10")
|
@IFMLLoadingPlugin.TransformerExclusions({ "codechicken.core.asm", "codechicken.obfuscator", "codechicken.lib.asm",
|
||||||
public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
"codechicken.lib.config" })
|
||||||
|
public class CodeChickenCorePlugin implements IFMLLoadingPlugin {
|
||||||
|
|
||||||
public static final String mcVersion = "[1.7.10]";
|
public static final String mcVersion = "[1.7.10]";
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final String version = Tags.VERSION;
|
public static final String version = Tags.VERSION;
|
||||||
|
|
||||||
|
public static ConfigFile config;
|
||||||
public static File minecraftDir;
|
public static File minecraftDir;
|
||||||
public static String currentMcVersion;
|
public static String currentMcVersion;
|
||||||
public static Logger logger = LogManager.getLogger("CodeChickenCore");
|
public static Logger logger = LogManager.getLogger("CodeChickenCore");
|
||||||
|
|
||||||
public CodeChickenCorePlugin() {
|
public CodeChickenCorePlugin() {
|
||||||
if (minecraftDir != null) return; // get called twice, once for IFMLCallHook
|
if (minecraftDir != null) return;
|
||||||
|
|
||||||
minecraftDir = (File) FMLInjectionData.data()[6];
|
minecraftDir = (File) FMLInjectionData.data()[6];
|
||||||
currentMcVersion = (String) FMLInjectionData.data()[4];
|
currentMcVersion = (String) FMLInjectionData.data()[4];
|
||||||
|
config = new ConfigFile(new File(minecraftDir, "config/CodeChickenCore.cfg"))
|
||||||
|
.setComment("CodeChickenCore configuration file.");
|
||||||
|
if (Boolean.getBoolean("ccc.dev.deobfuscate")) {
|
||||||
|
injectDeobfPlugin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
injectDeobfPlugin();
|
@Override
|
||||||
|
public String[] getASMTransformerClass() {
|
||||||
|
versionCheck(mcVersion, "CodeChickenCore");
|
||||||
|
return new String[] { "codechicken.lib.asm.ClassHeirachyManager", "codechicken.lib.asm.RedirectorTransformer" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccessTransformerClass() {
|
||||||
|
if (Boolean.getBoolean("ccc.dev.runtimePublic")) {
|
||||||
|
return "codechicken.core.asm.CodeChickenAccessTransformer";
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModContainerClass() {
|
||||||
|
return "codechicken.core.asm.CodeChickenCoreModContainer";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSetupClass() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectData(Map<String, Object> data) {
|
||||||
|
ConfigTag checkRAM = CodeChickenCorePlugin.config.getTag("checks")
|
||||||
|
.setComment("Configuration options for checking various requirements for a modpack.").useBraces();
|
||||||
|
if (checkRAM.getTag("checkRAM")
|
||||||
|
.setComment("If set to true, check RAM available for Minecraft before continuing to load")
|
||||||
|
.getBooleanValue(false)) {
|
||||||
|
systemCheck(checkRAM);
|
||||||
|
}
|
||||||
|
TweakTransformer.load();
|
||||||
|
DelegatedTransformer.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void injectDeobfPlugin() {
|
private void injectDeobfPlugin() {
|
||||||
try {
|
try {
|
||||||
Class<?> wrapperClass = Class.forName("cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper");
|
Class<?> wrapperClass = Class.forName("cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper");
|
||||||
Constructor wrapperConstructor = wrapperClass
|
Constructor<?> wrapperConstructor = wrapperClass
|
||||||
.getConstructor(String.class, IFMLLoadingPlugin.class, File.class, Integer.TYPE, String[].class);
|
.getConstructor(String.class, IFMLLoadingPlugin.class, File.class, Integer.TYPE, String[].class);
|
||||||
Field f_loadPlugins = CoreModManager.class.getDeclaredField("loadPlugins");
|
Field f_loadPlugins = CoreModManager.class.getDeclaredField("loadPlugins");
|
||||||
wrapperConstructor.setAccessible(true);
|
wrapperConstructor.setAccessible(true);
|
||||||
@@ -76,7 +112,7 @@ public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
|||||||
0,
|
0,
|
||||||
new String[0]));
|
new String[0]));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Failed to inject MCPDeobfuscation Transformer", e);
|
logger.error("Failed to inject FMLPluginWrapper for MCPDeobfuscation Transformer", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,74 +222,4 @@ public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
|||||||
FMLCommonHandler.instance().exitJava(-98, true);
|
FMLCommonHandler.instance().exitJava(-98, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getASMTransformerClass() {
|
|
||||||
versionCheck(mcVersion, "CodeChickenCore");
|
|
||||||
return new String[] { "codechicken.lib.asm.ClassHeirachyManager", "codechicken.core.asm.TweakTransformer",
|
|
||||||
"codechicken.core.asm.DelegatedTransformer", "codechicken.core.asm.DefaultImplementationTransformer",
|
|
||||||
"codechicken.lib.asm.RedirectorTransformer" };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAccessTransformerClass() {
|
|
||||||
return "codechicken.core.asm.CodeChickenAccessTransformer";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getModContainerClass() {
|
|
||||||
return "codechicken.core.asm.CodeChickenCoreModContainer";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSetupClass() {
|
|
||||||
return getClass().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void injectData(Map<String, Object> data) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void call() {
|
|
||||||
CodeChickenCoreModContainer.loadConfig();
|
|
||||||
ConfigTag checkRAM;
|
|
||||||
checkRAM = CodeChickenCoreModContainer.config.getTag("checks")
|
|
||||||
.setComment("Configuration options for checking various requirements for a modpack.").useBraces();
|
|
||||||
if (checkRAM.getTag("checkRAM")
|
|
||||||
.setComment("If set to true, check RAM available for Minecraft before continuing to load")
|
|
||||||
.getBooleanValue(false))
|
|
||||||
systemCheck(checkRAM);
|
|
||||||
TweakTransformer.load();
|
|
||||||
scanCodeChickenMods();
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scanCodeChickenMods() {
|
|
||||||
File modsDir = new File(minecraftDir, "mods");
|
|
||||||
for (File file : modsDir.listFiles()) scanMod(file);
|
|
||||||
File versionModsDir = new File(minecraftDir, "mods/" + currentMcVersion);
|
|
||||||
if (versionModsDir.exists()) for (File file : versionModsDir.listFiles()) scanMod(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scanMod(File file) {
|
|
||||||
if (!file.getName().endsWith(".jar") && !file.getName().endsWith(".zip")) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
JarFile jar = new JarFile(file);
|
|
||||||
try {
|
|
||||||
Manifest manifest = jar.getManifest();
|
|
||||||
if (manifest == null) return;
|
|
||||||
Attributes attr = manifest.getMainAttributes();
|
|
||||||
if (attr == null) return;
|
|
||||||
|
|
||||||
String transformer = attr.getValue("CCTransformer");
|
|
||||||
if (transformer != null) DelegatedTransformer.addTransformer(transformer, jar, file);
|
|
||||||
} finally {
|
|
||||||
jar.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("CodeChickenCore: Failed to read jar file: " + file.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
package codechicken.core.launch;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.swing.Box;
|
|
||||||
import javax.swing.JDialog;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
|
|
||||||
import cpw.mods.fml.common.versioning.ComparableVersion;
|
|
||||||
import cpw.mods.fml.relauncher.IFMLCallHook;
|
|
||||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
|
||||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For autodownloading stuff. This is really unoriginal, mostly ripped off FML, credits to cpw.
|
|
||||||
*/
|
|
||||||
@MCVersion("1.7.10")
|
|
||||||
public class DepLoader implements IFMLLoadingPlugin, IFMLCallHook {
|
|
||||||
|
|
||||||
public interface IDownloadDisplay {
|
|
||||||
|
|
||||||
void resetProgress(int sizeGuess);
|
|
||||||
|
|
||||||
void setPokeThread(Thread currentThread);
|
|
||||||
|
|
||||||
void updateProgress(int fullLength);
|
|
||||||
|
|
||||||
boolean shouldStopIt();
|
|
||||||
|
|
||||||
void updateProgressString(String string, Object... data);
|
|
||||||
|
|
||||||
Object makeDialog();
|
|
||||||
|
|
||||||
void showErrorDialog(String name, String url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public static class Downloader extends JOptionPane implements IDownloadDisplay {
|
|
||||||
|
|
||||||
boolean stopIt;
|
|
||||||
Thread pokeThread;
|
|
||||||
|
|
||||||
private Box makeProgressPanel() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JDialog makeDialog() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void requestClose(String message) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateProgressString(String progressUpdate, Object... data) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resetProgress(int sizeGuess) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateProgress(int fullLength) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPokeThread(Thread currentThread) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldStopIt() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showErrorDialog(String name, String url) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DummyDownloader implements IDownloadDisplay {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resetProgress(int sizeGuess) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPokeThread(Thread currentThread) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateProgress(int fullLength) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldStopIt() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateProgressString(String string, Object... data) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object makeDialog() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showErrorDialog(String name, String url) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class VersionedFile {
|
|
||||||
|
|
||||||
public final Pattern pattern;
|
|
||||||
public final String filename;
|
|
||||||
public final ComparableVersion version;
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
public VersionedFile(String filename, Pattern pattern) {
|
|
||||||
this.pattern = pattern;
|
|
||||||
this.filename = filename;
|
|
||||||
Matcher m = pattern.matcher(filename);
|
|
||||||
if (m.matches()) {
|
|
||||||
name = m.group(1);
|
|
||||||
version = new ComparableVersion(m.group(2));
|
|
||||||
} else {
|
|
||||||
name = null;
|
|
||||||
version = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matches() {
|
|
||||||
return name != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Dependency {
|
|
||||||
|
|
||||||
public String url;
|
|
||||||
public VersionedFile file;
|
|
||||||
|
|
||||||
public String existing;
|
|
||||||
/**
|
|
||||||
* Flag set to add this dep to the classpath immediately because it is required for a coremod.
|
|
||||||
*/
|
|
||||||
public boolean coreLib;
|
|
||||||
|
|
||||||
public Dependency(String url, VersionedFile file, boolean coreLib) {
|
|
||||||
this.url = url;
|
|
||||||
this.file = file;
|
|
||||||
this.coreLib = coreLib;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DepLoadInst {
|
|
||||||
|
|
||||||
public DepLoadInst() {}
|
|
||||||
|
|
||||||
public void load() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void load() {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getASMTransformerClass() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getModContainerClass() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSetupClass() {
|
|
||||||
return getClass().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void injectData(Map<String, Object> data) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void call() {
|
|
||||||
load();
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAccessTransformerClass() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
package codechicken.lib.asm;
|
package codechicken.lib.asm;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.HashSet;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import net.minecraft.launchwrapper.IClassTransformer;
|
import net.minecraft.launchwrapper.IClassTransformer;
|
||||||
import net.minecraft.launchwrapper.Launch;
|
import net.minecraft.launchwrapper.Launch;
|
||||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
|
||||||
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.ClassReader;
|
||||||
|
|
||||||
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
||||||
|
|
||||||
@@ -18,47 +17,60 @@ import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
|||||||
*/
|
*/
|
||||||
public class ClassHeirachyManager implements IClassTransformer {
|
public class ClassHeirachyManager implements IClassTransformer {
|
||||||
|
|
||||||
|
private static final Map<String, ClassInfo> superclasses = new ConcurrentHashMap<>(1000);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ASMInit.init();
|
superclasses.put("java.lang.Object", ClassInfo.OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SuperCache {
|
@Override
|
||||||
|
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||||
String superclass;
|
if (bytes == null) return null;
|
||||||
public HashSet<String> parents = new HashSet<String>();
|
if (!superclasses.containsKey(transformedName)) {
|
||||||
private boolean flattened;
|
declareASM(transformedName, bytes);
|
||||||
|
|
||||||
public void add(String parent) {
|
|
||||||
parents.add(parent);
|
|
||||||
}
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
public void flatten() {
|
private static ClassInfo declareASM(String name, byte[] bytes) {
|
||||||
if (flattened) return;
|
final ClassReader classReader = new ClassReader(bytes);
|
||||||
|
final ClassInfo classInfo = new ClassInfo(classReader);
|
||||||
|
superclasses.put(name, classInfo);
|
||||||
|
return classInfo;
|
||||||
|
}
|
||||||
|
|
||||||
for (String s : new ArrayList<String>(parents)) {
|
private static ClassInfo declareReflection(String name) throws ClassNotFoundException {
|
||||||
SuperCache c = declareClass(s);
|
final Class<?> aclass = Class.forName(name);
|
||||||
if (c != null) {
|
final ClassInfo classInfo = new ClassInfo(aclass);
|
||||||
c.flatten();
|
superclasses.put(name, classInfo);
|
||||||
parents.addAll(c.parents);
|
return classInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ClassInfo declareClass(String name) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = Launch.classLoader.getClassBytes(unKey(name));
|
||||||
|
if (bytes != null) {
|
||||||
|
return declareASM(name, bytes);
|
||||||
}
|
}
|
||||||
flattened = true;
|
} catch (Exception ignored) {}
|
||||||
|
try {
|
||||||
|
return declareReflection(name);
|
||||||
|
} catch (ClassNotFoundException ignored) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toKey(String name) {
|
||||||
|
if (ObfMapping.obfuscated) {
|
||||||
|
return FMLDeobfuscatingRemapper.INSTANCE.map(name.replace('.', '/')).replace('/', '.');
|
||||||
}
|
}
|
||||||
|
return name.replace('/', '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HashMap<String, SuperCache> superclasses = new HashMap<String, SuperCache>();
|
private static String unKey(String name) {
|
||||||
private static LaunchClassLoader cl = Launch.classLoader;
|
if (ObfMapping.obfuscated) {
|
||||||
|
return FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/', '.');
|
||||||
public static String toKey(String name) {
|
}
|
||||||
if (ObfMapping.obfuscated)
|
return name.replace('/', '.');
|
||||||
name = FMLDeobfuscatingRemapper.INSTANCE.map(name.replace('.', '/')).replace('/', '.');
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String unKey(String name) {
|
|
||||||
if (ObfMapping.obfuscated)
|
|
||||||
name = FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/', '.');
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,83 +84,99 @@ public class ClassHeirachyManager implements IClassTransformer {
|
|||||||
|
|
||||||
if (name.equals(superclass)) return true;
|
if (name.equals(superclass)) return true;
|
||||||
|
|
||||||
SuperCache cache = declareClass(name);
|
ClassInfo classInfo = superclasses.get(name);
|
||||||
if (cache == null) // just can't handle this
|
if (classInfo == null) classInfo = declareClass(name);
|
||||||
return false;
|
if (classInfo == null) return false;
|
||||||
|
|
||||||
cache.flatten();
|
return classInfo.hasSuper(superclass);
|
||||||
return cache.parents.contains(superclass);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SuperCache declareClass(String name) {
|
|
||||||
name = toKey(name);
|
|
||||||
SuperCache cache = superclasses.get(name);
|
|
||||||
|
|
||||||
if (cache != null) return cache;
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] bytes = cl.getClassBytes(unKey(name));
|
|
||||||
if (bytes != null) cache = declareASM(bytes);
|
|
||||||
} catch (Exception e) {}
|
|
||||||
|
|
||||||
if (cache != null) return cache;
|
|
||||||
|
|
||||||
try {
|
|
||||||
cache = declareReflection(name);
|
|
||||||
} catch (ClassNotFoundException e) {}
|
|
||||||
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SuperCache declareReflection(String name) throws ClassNotFoundException {
|
|
||||||
Class<?> aclass = Class.forName(name);
|
|
||||||
|
|
||||||
SuperCache cache = getOrCreateCache(name);
|
|
||||||
if (aclass.isInterface()) cache.superclass = "java.lang.Object";
|
|
||||||
else if (name.equals("java.lang.Object")) return cache;
|
|
||||||
else cache.superclass = toKey(aclass.getSuperclass().getName());
|
|
||||||
|
|
||||||
cache.add(cache.superclass);
|
|
||||||
for (Class<?> iclass : aclass.getInterfaces()) cache.add(toKey(iclass.getName()));
|
|
||||||
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SuperCache declareASM(byte[] bytes) {
|
|
||||||
ClassNode node = ASMHelper.createClassNode(bytes);
|
|
||||||
String name = toKey(node.name);
|
|
||||||
|
|
||||||
SuperCache cache = getOrCreateCache(name);
|
|
||||||
cache.superclass = toKey(node.superName.replace('/', '.'));
|
|
||||||
cache.add(cache.superclass);
|
|
||||||
for (String iclass : node.interfaces) cache.add(toKey(iclass.replace('/', '.')));
|
|
||||||
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] transform(String name, String tname, byte[] bytes) {
|
|
||||||
if (bytes == null) return null;
|
|
||||||
|
|
||||||
if (!superclasses.containsKey(tname)) declareASM(bytes);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SuperCache getOrCreateCache(String name) {
|
|
||||||
SuperCache cache = superclasses.get(name);
|
|
||||||
if (cache == null) superclasses.put(name, cache = new SuperCache());
|
|
||||||
return cache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getSuperClass(String name, boolean runtime) {
|
public static String getSuperClass(String name, boolean runtime) {
|
||||||
name = toKey(name);
|
name = toKey(name);
|
||||||
SuperCache cache = declareClass(name);
|
|
||||||
if (cache == null) return "java.lang.Object";
|
|
||||||
|
|
||||||
cache.flatten();
|
ClassInfo classInfo = superclasses.get(name);
|
||||||
String s = cache.superclass;
|
if (classInfo == null) classInfo = declareClass(name);
|
||||||
if (!runtime) s = FMLDeobfuscatingRemapper.INSTANCE.unmap(s);
|
if (classInfo == null || classInfo.superclass == null) return "java.lang.Object";
|
||||||
|
|
||||||
|
final String s = classInfo.superclass;
|
||||||
|
if (!runtime) {
|
||||||
|
return FMLDeobfuscatingRemapper.INSTANCE.unmap(s);
|
||||||
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ClassInfo {
|
||||||
|
|
||||||
|
public static final ClassInfo OBJECT = new ClassInfo();
|
||||||
|
private static final Map<String, String> STRING_POOL = new ConcurrentHashMap<>(256);
|
||||||
|
|
||||||
|
public final String superclass;
|
||||||
|
public final String[] interfaces;
|
||||||
|
public ClassInfo parent;
|
||||||
|
|
||||||
|
private ClassInfo() {
|
||||||
|
this.superclass = null;
|
||||||
|
this.interfaces = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassInfo(ClassReader classReader) {
|
||||||
|
final String superName = classReader.getSuperName();
|
||||||
|
final String[] interfaces = classReader.getInterfaces();
|
||||||
|
|
||||||
|
if (superName == null || "java/lang/Object".equals(superName)) {
|
||||||
|
superclass = "java.lang.Object";
|
||||||
|
parent = OBJECT;
|
||||||
|
} else {
|
||||||
|
superclass = pool(toKey(superName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interfaces == null || interfaces.length == 0) {
|
||||||
|
this.interfaces = null;
|
||||||
|
} else {
|
||||||
|
this.interfaces = new String[interfaces.length];
|
||||||
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
|
this.interfaces[i] = pool(toKey(interfaces[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassInfo(Class<?> aclass) {
|
||||||
|
if (aclass.isInterface()) {
|
||||||
|
this.superclass = "java.lang.Object";
|
||||||
|
this.parent = OBJECT;
|
||||||
|
} else {
|
||||||
|
final Class<?> superclass = aclass.getSuperclass();
|
||||||
|
if (superclass == null || "java.lang.Object".equals(superclass.getName())) {
|
||||||
|
this.superclass = "java.lang.Object";
|
||||||
|
this.parent = OBJECT;
|
||||||
|
} else {
|
||||||
|
this.superclass = pool(toKey(superclass.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final Class<?>[] interfaces = aclass.getInterfaces();
|
||||||
|
if (interfaces.length == 0) {
|
||||||
|
this.interfaces = null;
|
||||||
|
} else {
|
||||||
|
this.interfaces = new String[interfaces.length];
|
||||||
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
|
this.interfaces[i] = pool(toKey(interfaces[i].getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasSuper(String superclass) {
|
||||||
|
if (this.superclass == null) return false;
|
||||||
|
if (this.superclass.equals(superclass)) return true;
|
||||||
|
ClassInfo parentInfo = this.parent;
|
||||||
|
if (parentInfo == null) parentInfo = superclasses.get(this.superclass);
|
||||||
|
if (parentInfo == null) parentInfo = declareClass(this.superclass);
|
||||||
|
if (parentInfo == null) return false;
|
||||||
|
this.parent = parentInfo;
|
||||||
|
return parentInfo.hasSuper(superclass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String pool(String s) {
|
||||||
|
return STRING_POOL.computeIfAbsent(s, Function.identity());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -275,17 +275,22 @@ public class ModularASMTransformer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashMap<String, ClassNodeTransformerList> transformers = new HashMap<String, ClassNodeTransformerList>();
|
public HashMap<String, ClassNodeTransformerList> transformers = new HashMap<>();
|
||||||
|
|
||||||
public void add(ClassNodeTransformer t) {
|
public void add(ClassNodeTransformer t) {
|
||||||
ClassNodeTransformerList list = transformers.get(t.className());
|
ClassNodeTransformerList list = transformers.get(t.className());
|
||||||
if (list == null) transformers.put(t.className(), list = new ClassNodeTransformerList());
|
if (list == null) {
|
||||||
|
transformers.put(t.className(), list = new ClassNodeTransformerList());
|
||||||
|
}
|
||||||
list.add(t);
|
list.add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return transformers.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] transform(String name, byte[] bytes) {
|
public byte[] transform(String name, byte[] bytes) {
|
||||||
if (bytes == null) return null;
|
if (bytes == null) return null;
|
||||||
|
|
||||||
ClassNodeTransformerList list = transformers.get(name);
|
ClassNodeTransformerList list = transformers.get(name);
|
||||||
return list == null ? bytes : list.transform(bytes);
|
return list == null ? bytes : list.transform(bytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,12 @@ public class RedirectorTransformer implements IClassTransformer, Opcodes {
|
|||||||
"hasBrightness",
|
"hasBrightness",
|
||||||
"brightness",
|
"brightness",
|
||||||
"side",
|
"side",
|
||||||
"lc"
|
"lc",
|
||||||
|
"normalAttrib",
|
||||||
|
"colourAttrib",
|
||||||
|
"lightCoordAttrib",
|
||||||
|
"sideAttrib",
|
||||||
|
"lightingAttrib"
|
||||||
|
|
||||||
);
|
);
|
||||||
Collections.addAll(redirectedSimpleMethods, "reset", "pullLightmap", "pushLightmap", "setDynamic", "draw");
|
Collections.addAll(redirectedSimpleMethods, "reset", "pullLightmap", "pushLightmap", "setDynamic", "draw");
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package codechicken.lib.colour;
|
||||||
|
|
||||||
|
import net.minecraft.util.StatCollector;
|
||||||
|
|
||||||
|
public final class LocalizedColours {
|
||||||
|
|
||||||
|
private static final String KEY_PREFIX = "codechickencore.color.";
|
||||||
|
|
||||||
|
public static int BUTTON_TEXT_DISABLED = 0xFFA0A0A0;
|
||||||
|
public static int BUTTON_TEXT_HOVER = 0xFFFFFFA0;
|
||||||
|
public static int BUTTON_TEXT = 0xFFE0E0E0;
|
||||||
|
public static int TEXT_FIELD_BORDER = 0xFFA0A0A0;
|
||||||
|
public static int TEXT_FIELD_BACKGROUND = 0xFF000000;
|
||||||
|
public static int TEXT_FIELD_TEXT = 0xE0E0E0;
|
||||||
|
public static int TEXT_FIELD_TEXT_DISABLED = 0x707070;
|
||||||
|
public static int SCROLL_PANE_BACKGROUND = 0xFF000000;
|
||||||
|
public static int SCROLL_PANE_OVERLAY_TOP = 0xFFA0A0A0;
|
||||||
|
public static int SCROLL_PANE_OVERLAY_BOTTOM = 0xFFA0A0A0;
|
||||||
|
public static int SCROLL_PANE_OVERLAY_LEFT = 0xFFA0A0A0;
|
||||||
|
public static int SCROLL_PANE_OVERLAY_RIGHT = 0xFFA0A0A0;
|
||||||
|
public static int SCROLLBAR_CORNERS = 0xFF8B8B8B;
|
||||||
|
public static int SCROLLBAR_TOP_LEFT = 0xFFF0F0F0;
|
||||||
|
public static int SCROLLBAR_BOTTOM_RIGHT = 0xFF555555;
|
||||||
|
public static int SCROLLBAR_FILL = 0xFFC6C6C6;
|
||||||
|
public static int SCROLLBAR_GUIDE = 0xFF808080;
|
||||||
|
public static int TOOLTIP_BG_START = 0xF0100010;
|
||||||
|
public static int TOOLTIP_BG_END = 0xF0100010;
|
||||||
|
public static int TOOLTIP_BORDER_START = 0x505000FF;
|
||||||
|
public static int TOOLTIP_BORDER_END = 0x5028007F;
|
||||||
|
public static int TOOLTIP_TEXT = 0xFFFFFFFF;
|
||||||
|
public static int ITEM_QUANTITY_TEXT = 0xFFFFFF;
|
||||||
|
public static int MOD_DESCRIPTION_TEXT = 0xDDDDDD;
|
||||||
|
|
||||||
|
private LocalizedColours() {}
|
||||||
|
|
||||||
|
public static void reloadLocalizedColours() {
|
||||||
|
BUTTON_TEXT_DISABLED = getLocalizedColor("buttonTextDisabled", BUTTON_TEXT_DISABLED);
|
||||||
|
BUTTON_TEXT_HOVER = getLocalizedColor("buttonTextHover", BUTTON_TEXT_HOVER);
|
||||||
|
BUTTON_TEXT = getLocalizedColor("buttonText", BUTTON_TEXT);
|
||||||
|
TEXT_FIELD_BORDER = getLocalizedColor("textFieldBorder", TEXT_FIELD_BORDER);
|
||||||
|
TEXT_FIELD_BACKGROUND = getLocalizedColor("textFieldBackground", TEXT_FIELD_BACKGROUND);
|
||||||
|
TEXT_FIELD_TEXT = getLocalizedColor("textFieldText", TEXT_FIELD_TEXT);
|
||||||
|
TEXT_FIELD_TEXT_DISABLED = getLocalizedColor("textFieldTextDisabled", TEXT_FIELD_TEXT_DISABLED);
|
||||||
|
SCROLL_PANE_BACKGROUND = getLocalizedColor("background", SCROLL_PANE_BACKGROUND);
|
||||||
|
SCROLL_PANE_OVERLAY_TOP = getLocalizedColor("overlayTop", SCROLL_PANE_OVERLAY_TOP);
|
||||||
|
SCROLL_PANE_OVERLAY_BOTTOM = getLocalizedColor("overlayBottom", SCROLL_PANE_OVERLAY_BOTTOM);
|
||||||
|
SCROLL_PANE_OVERLAY_LEFT = getLocalizedColor("overlayLeft", SCROLL_PANE_OVERLAY_LEFT);
|
||||||
|
SCROLL_PANE_OVERLAY_RIGHT = getLocalizedColor("overlayRight", SCROLL_PANE_OVERLAY_RIGHT);
|
||||||
|
SCROLLBAR_CORNERS = getLocalizedColor("scrollbarCorners", SCROLLBAR_CORNERS);
|
||||||
|
SCROLLBAR_TOP_LEFT = getLocalizedColor("scrollbarTopLeft", SCROLLBAR_TOP_LEFT);
|
||||||
|
SCROLLBAR_BOTTOM_RIGHT = getLocalizedColor("scrollbarBottomRight", SCROLLBAR_BOTTOM_RIGHT);
|
||||||
|
SCROLLBAR_FILL = getLocalizedColor("scrollbarFill", SCROLLBAR_FILL);
|
||||||
|
SCROLLBAR_GUIDE = getLocalizedColor("scrollbarGuide", SCROLLBAR_GUIDE);
|
||||||
|
TOOLTIP_BG_START = getLocalizedColor("tooltipBgStart", TOOLTIP_BG_START);
|
||||||
|
TOOLTIP_BG_END = getLocalizedColor("tooltipBgEnd", TOOLTIP_BG_END);
|
||||||
|
TOOLTIP_BORDER_START = getLocalizedColor("tooltipBorderStart", TOOLTIP_BORDER_START);
|
||||||
|
TOOLTIP_BORDER_END = getLocalizedColor("tooltipBorderEnd", TOOLTIP_BORDER_END);
|
||||||
|
TOOLTIP_TEXT = getLocalizedColor("tooltipText", TOOLTIP_TEXT);
|
||||||
|
ITEM_QUANTITY_TEXT = getLocalizedColor("itemQuantityText", ITEM_QUANTITY_TEXT);
|
||||||
|
MOD_DESCRIPTION_TEXT = getLocalizedColor("modDescriptionText", MOD_DESCRIPTION_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a optional localized ARGB color from lang files. Expected value format: AARRGGBB (for example FF555555).
|
||||||
|
*/
|
||||||
|
private static int getLocalizedColor(String key, int defaultColor) {
|
||||||
|
String fullKey = KEY_PREFIX + key;
|
||||||
|
if (!StatCollector.canTranslate(fullKey)) {
|
||||||
|
return defaultColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
String raw = StatCollector.translateToLocal(fullKey);
|
||||||
|
String hex = raw.trim();
|
||||||
|
if (hex.startsWith("0x") || hex.startsWith("0X")) {
|
||||||
|
hex = hex.substring(2);
|
||||||
|
} else if (hex.startsWith("#")) {
|
||||||
|
hex = hex.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (int) Long.parseLong(hex, 16);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
return defaultColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ import org.lwjgl.input.Mouse;
|
|||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
import org.lwjgl.opengl.GL12;
|
import org.lwjgl.opengl.GL12;
|
||||||
|
|
||||||
|
import codechicken.lib.colour.LocalizedColours;
|
||||||
import codechicken.lib.math.MathHelper;
|
import codechicken.lib.math.MathHelper;
|
||||||
import codechicken.lib.render.CCRenderState;
|
import codechicken.lib.render.CCRenderState;
|
||||||
|
|
||||||
@@ -162,7 +163,15 @@ public class GuiDraw {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void drawMultilineTip(FontRenderer font, int x, int y, List<String> list) {
|
public static void drawMultilineTip(FontRenderer font, int x, int y, List<String> list) {
|
||||||
drawMultilineTip(font, x, y, list, 0xf0100010, 0xf0100010, 0x505000ff, 0x5028007F);
|
drawMultilineTip(
|
||||||
|
font,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
list,
|
||||||
|
LocalizedColours.TOOLTIP_BG_START,
|
||||||
|
LocalizedColours.TOOLTIP_BG_END,
|
||||||
|
LocalizedColours.TOOLTIP_BORDER_START,
|
||||||
|
LocalizedColours.TOOLTIP_BORDER_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawMultilineTip(FontRenderer font, int x, int y, List<String> list, int bgStart, int bgEnd,
|
public static void drawMultilineTip(FontRenderer font, int x, int y, List<String> list, int bgStart, int bgEnd,
|
||||||
@@ -201,7 +210,7 @@ public class GuiDraw {
|
|||||||
line.draw(x, y);
|
line.draw(x, y);
|
||||||
y += line.getSize().height;
|
y += line.getSize().height;
|
||||||
} else {
|
} else {
|
||||||
font.drawStringWithShadow(s, x, y, -1);
|
font.drawStringWithShadow(s, x, y, LocalizedColours.TOOLTIP_TEXT);
|
||||||
y += s.endsWith(TOOLTIP_LINESPACE) ? 12 : 10;
|
y += s.endsWith(TOOLTIP_LINESPACE) ? 12 : 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +224,15 @@ public class GuiDraw {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void drawTooltipBox(int x, int y, int w, int h) {
|
public static void drawTooltipBox(int x, int y, int w, int h) {
|
||||||
drawTooltipBox(x, y, w, h, 0xf0100010, 0xf0100010, 0x505000ff, 0x5028007F);
|
drawTooltipBox(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
LocalizedColours.TOOLTIP_BG_START,
|
||||||
|
LocalizedColours.TOOLTIP_BG_END,
|
||||||
|
LocalizedColours.TOOLTIP_BORDER_START,
|
||||||
|
LocalizedColours.TOOLTIP_BORDER_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawTooltipBox(int x, int y, int w, int h, int bgStart, int bgEnd, int borderStart,
|
public static void drawTooltipBox(int x, int y, int w, int h, int bgStart, int bgEnd, int borderStart,
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ public class LightModel implements CCRenderState.IVertexOperation {
|
|||||||
public boolean load(CCRenderState state) {
|
public boolean load(CCRenderState state) {
|
||||||
if (!state.computeLighting) return false;
|
if (!state.computeLighting) return false;
|
||||||
|
|
||||||
state.pipeline.addDependency(CCRenderState.normalAttrib);
|
state.pipeline.addDependency(CCRenderState.normalAttrib());
|
||||||
state.pipeline.addDependency(CCRenderState.colourAttrib);
|
state.pipeline.addDependency(CCRenderState.colourAttrib());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class PlanarLightMatrix extends PlanarLightModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean load(CCRenderState state) {
|
public boolean load(CCRenderState state) {
|
||||||
state.pipeline.addDependency(CCRenderState.sideAttrib);
|
state.pipeline.addDependency(CCRenderState.sideAttrib());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ public class PlanarLightModel implements CCRenderState.IVertexOperation {
|
|||||||
public boolean load(CCRenderState state) {
|
public boolean load(CCRenderState state) {
|
||||||
if (!state.computeLighting) return false;
|
if (!state.computeLighting) return false;
|
||||||
|
|
||||||
state.pipeline.addDependency(CCRenderState.sideAttrib);
|
state.pipeline.addDependency(CCRenderState.sideAttrib());
|
||||||
state.pipeline.addDependency(CCRenderState.colourAttrib);
|
state.pipeline.addDependency(CCRenderState.colourAttrib());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,12 @@ import codechicken.lib.vec.BlockCoord;
|
|||||||
public class SimpleBrightnessModel implements CCRenderState.IVertexOperation {
|
public class SimpleBrightnessModel implements CCRenderState.IVertexOperation {
|
||||||
|
|
||||||
public static final int operationIndex = CCRenderState.registerOperation();
|
public static final int operationIndex = CCRenderState.registerOperation();
|
||||||
public static SimpleBrightnessModel instance = new SimpleBrightnessModel();
|
private static final ThreadLocal<SimpleBrightnessModel> instances = ThreadLocal
|
||||||
|
.withInitial(SimpleBrightnessModel::new);
|
||||||
|
|
||||||
|
public static SimpleBrightnessModel instance() {
|
||||||
|
return instances.get();
|
||||||
|
}
|
||||||
|
|
||||||
public IBlockAccess access;
|
public IBlockAccess access;
|
||||||
public BlockCoord pos = new BlockCoord();
|
public BlockCoord pos = new BlockCoord();
|
||||||
@@ -40,7 +45,7 @@ public class SimpleBrightnessModel implements CCRenderState.IVertexOperation {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean load(CCRenderState state) {
|
public boolean load(CCRenderState state) {
|
||||||
state.pipeline.addDependency(CCRenderState.sideAttrib);
|
state.pipeline.addDependency(CCRenderState.sideAttrib());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package codechicken.lib.packet;
|
|||||||
|
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
|
|
||||||
@@ -50,6 +51,8 @@ import io.netty.util.AttributeKey;
|
|||||||
|
|
||||||
public final class PacketCustom implements MCDataInput, MCDataOutput {
|
public final class PacketCustom implements MCDataInput, MCDataOutput {
|
||||||
|
|
||||||
|
private static final int MAX_DECOMPRESSED_SIZE = 2 * 1024 * 1024;
|
||||||
|
|
||||||
public static interface ICustomPacketHandler {
|
public static interface ICustomPacketHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +193,7 @@ public final class PacketCustom implements MCDataInput, MCDataOutput {
|
|||||||
byteBuf = payload;
|
byteBuf = payload;
|
||||||
|
|
||||||
type = byteBuf.readUnsignedByte();
|
type = byteBuf.readUnsignedByte();
|
||||||
if (type > 0x80) decompress();
|
if (type > 0x80) decompressPayload();
|
||||||
type &= 0x7F;
|
type &= 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,44 +207,61 @@ public final class PacketCustom implements MCDataInput, MCDataOutput {
|
|||||||
byteBuf.writeByte(type);
|
byteBuf.writeByte(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void decompressPayload() {
|
||||||
* Decompresses the remaining ByteBuf (after type has been read) using Snappy
|
if (byteBuf.readableBytes() < 4) throw new IllegalArgumentException("Missing compressed packet length");
|
||||||
*/
|
int declaredLength = byteBuf.readInt();
|
||||||
private void decompress() {
|
if (declaredLength < 0 || declaredLength > MAX_DECOMPRESSED_SIZE)
|
||||||
|
throw new IllegalArgumentException("Invalid decompressed packet length: " + declaredLength);
|
||||||
|
|
||||||
Inflater inflater = new Inflater();
|
Inflater inflater = new Inflater();
|
||||||
|
ByteBuf decodedPayload = null;
|
||||||
try {
|
try {
|
||||||
int len = byteBuf.readInt();
|
byte[] compressedInput = new byte[byteBuf.readableBytes()];
|
||||||
ByteBuf out = Unpooled.buffer(len);
|
byteBuf.readBytes(compressedInput);
|
||||||
inflater.setInput(byteBuf.array(), byteBuf.readerIndex(), byteBuf.readableBytes());
|
inflater.setInput(compressedInput);
|
||||||
inflater.inflate(out.array());
|
decodedPayload = Unpooled.buffer(Math.min(declaredLength, 8192), declaredLength);
|
||||||
out.writerIndex(len);
|
byte[] inflatedChunk = new byte[Math.min(declaredLength + 1, 8192)];
|
||||||
byteBuf = out;
|
while (!inflater.finished()) {
|
||||||
} catch (Exception e) {
|
int inflatedBytes = inflater.inflate(inflatedChunk);
|
||||||
throw new RuntimeException(e);
|
if (inflatedBytes > declaredLength - decodedPayload.writerIndex())
|
||||||
|
throw new IllegalArgumentException("Decompressed packet exceeds declared length");
|
||||||
|
if (inflatedBytes == 0 && !inflater.finished())
|
||||||
|
throw new IllegalArgumentException("Incomplete or dictionary-dependent compressed packet");
|
||||||
|
decodedPayload.writeBytes(inflatedChunk, 0, inflatedBytes);
|
||||||
|
}
|
||||||
|
if (decodedPayload.writerIndex() != declaredLength || inflater.getRemaining() != 0)
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Compressed packet does not match declared length or has trailing data");
|
||||||
|
byteBuf = decodedPayload;
|
||||||
|
decodedPayload = null;
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid compressed packet", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
if (decodedPayload != null) decodedPayload.release();
|
||||||
inflater.end();
|
inflater.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void compressPayload() {
|
||||||
* Compresses the payload ByteBuf after the type byte
|
if ((byteBuf.getUnsignedByte(0) & 0x80) != 0) return;
|
||||||
*/
|
|
||||||
private void do_compress() {
|
int payloadLength = byteBuf.writerIndex() - 1;
|
||||||
|
if (payloadLength > MAX_DECOMPRESSED_SIZE)
|
||||||
|
throw new IllegalArgumentException("Packet payload exceeds 2 MiB decompressed limit: " + payloadLength);
|
||||||
|
|
||||||
Deflater deflater = new Deflater();
|
Deflater deflater = new Deflater();
|
||||||
try {
|
try {
|
||||||
byteBuf.readerIndex(1);
|
byteBuf.readerIndex(1);
|
||||||
int len = byteBuf.readableBytes();
|
deflater.setInput(byteBuf.array(), byteBuf.readerIndex(), payloadLength);
|
||||||
deflater.setInput(byteBuf.array(), byteBuf.readerIndex(), len);
|
|
||||||
deflater.finish();
|
deflater.finish();
|
||||||
ByteBuf out = Unpooled.buffer(len + 5);
|
ByteBuf compressedPayload = Unpooled.buffer(payloadLength + 5);
|
||||||
int clen = deflater.deflate(out.array(), 5, len);
|
int compressedLength = deflater.deflate(compressedPayload.array(), 5, payloadLength);
|
||||||
if (clen >= len - 5 || !deflater.finished()) // not worth compressing, gets larger
|
if (compressedLength >= payloadLength - 5 || !deflater.finished()) return;
|
||||||
return;
|
|
||||||
|
|
||||||
out.setByte(0, type | 0x80);
|
compressedPayload.setByte(0, type | 0x80);
|
||||||
out.setInt(1, len);
|
compressedPayload.setInt(1, payloadLength);
|
||||||
out.writerIndex(clen + 5);
|
compressedPayload.writerIndex(compressedLength + 5);
|
||||||
byteBuf = out;
|
byteBuf = compressedPayload;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -466,7 +486,7 @@ public final class PacketCustom implements MCDataInput, MCDataOutput {
|
|||||||
|
|
||||||
public FluidStack readFluidStack() {
|
public FluidStack readFluidStack() {
|
||||||
Fluid fluid = FluidRegistry.getFluid(readShort());
|
Fluid fluid = FluidRegistry.getFluid(readShort());
|
||||||
if (fluid == null) fluid = FluidRegistry.WATER;
|
if (fluid == null) return null;
|
||||||
|
|
||||||
return new FluidStack(fluid, readVarInt(), readNBTTagCompound());
|
return new FluidStack(fluid, readVarInt(), readNBTTagCompound());
|
||||||
}
|
}
|
||||||
@@ -474,7 +494,7 @@ public final class PacketCustom implements MCDataInput, MCDataOutput {
|
|||||||
public FMLProxyPacket toPacket() {
|
public FMLProxyPacket toPacket() {
|
||||||
if (incoming()) throw new IllegalStateException("Tried to write an incoming packet");
|
if (incoming()) throw new IllegalStateException("Tried to write an incoming packet");
|
||||||
|
|
||||||
if (byteBuf.readableBytes() > 32000 || (type & 0x80) != 0) do_compress();
|
if (byteBuf.readableBytes() > 32000 || (type & 0x80) != 0) compressPayload();
|
||||||
|
|
||||||
// FML packet impl returns the whole of the backing array, copy used portion of array to another ByteBuf
|
// FML packet impl returns the whole of the backing array, copy used portion of array to another ByteBuf
|
||||||
return new FMLProxyPacket(byteBuf.copy(), channel);
|
return new FMLProxyPacket(byteBuf.copy(), channel);
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ public class BlockRenderer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T getAttributes(CCRenderState.VertexAttribute<T> attr) {
|
public <T> T getAttributes(CCRenderState.VertexAttribute<T> attr) {
|
||||||
return attr == CCRenderState.lightCoordAttrib && lcComputed ? (T) lightCoords : null;
|
return attr == CCRenderState.lightCoordAttrib() && lcComputed ? (T) lightCoords : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasAttribute(CCRenderState.VertexAttribute<?> attr) {
|
public boolean hasAttribute(CCRenderState.VertexAttribute<?> attr) {
|
||||||
return attr == CCRenderState.sideAttrib || attr == CCRenderState.lightCoordAttrib && lcComputed;
|
return attr == CCRenderState.sideAttrib() || attr == CCRenderState.lightCoordAttrib() && lcComputed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -136,12 +136,12 @@ public class BlockRenderer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T getAttributes(VertexAttribute<T> attr) {
|
public <T> T getAttributes(VertexAttribute<T> attr) {
|
||||||
return attr == CCRenderState.lightCoordAttrib ? (T) lightCoords : null;
|
return attr == CCRenderState.lightCoordAttrib() ? (T) lightCoords : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasAttribute(VertexAttribute<?> attr) {
|
public boolean hasAttribute(VertexAttribute<?> attr) {
|
||||||
return attr == CCRenderState.sideAttrib || attr == CCRenderState.lightCoordAttrib;
|
return attr == CCRenderState.sideAttrib() || attr == CCRenderState.lightCoordAttrib();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -164,7 +164,7 @@ public class BlockRenderer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders faces of a block-like model based on a sideMask. Eg for side 2, verts 8-11 will be rendered
|
* Renders faces of a block-like model based on a sideMask. Eg for side 2, verts 8-11 will be rendered
|
||||||
*
|
*
|
||||||
* @param sideMask A mask of faces not to render
|
* @param sideMask A mask of faces not to render
|
||||||
*/
|
*/
|
||||||
// public static void renderFaces(int sideMask) {
|
// public static void renderFaces(int sideMask) {
|
||||||
@@ -184,7 +184,7 @@ public class BlockRenderer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders faces of a cuboid with texture coordinates mapped to match a standard minecraft block
|
* Renders faces of a cuboid with texture coordinates mapped to match a standard minecraft block
|
||||||
*
|
*
|
||||||
* @param bounds The bounding cuboid to render
|
* @param bounds The bounding cuboid to render
|
||||||
* @param sideMask A mask of faces not to render
|
* @param sideMask A mask of faces not to render
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Vector3[] normals() {
|
public Vector3[] normals() {
|
||||||
return getAttributes(CCRenderState.normalAttrib);
|
return getAttributes(CCRenderState.normalAttrib());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -102,7 +102,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Each pixel corresponds to one unit of position when generating the model
|
* Each pixel corresponds to one unit of position when generating the model
|
||||||
*
|
*
|
||||||
* @param i Vertex index to start generating at
|
* @param i Vertex index to start generating at
|
||||||
* @param x1 The minX bound of the box
|
* @param x1 The minX bound of the box
|
||||||
* @param y1 The minY bound of the box
|
* @param y1 The minY bound of the box
|
||||||
@@ -195,7 +195,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a box, uv mapped to be the same as a minecraft block with the same bounds
|
* Generates a box, uv mapped to be the same as a minecraft block with the same bounds
|
||||||
*
|
*
|
||||||
* @param i The vertex index to start generating at
|
* @param i The vertex index to start generating at
|
||||||
* @param bounds The bounds of the block, 0 to 1
|
* @param bounds The bounds of the block, 0 to 1
|
||||||
* @return The generated model. When rendering an icon will need to be supplied for the UV transformation.
|
* @return The generated model. When rendering an icon will need to be supplied for the UV transformation.
|
||||||
@@ -222,7 +222,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a box, uv mapped to be the same as a minecraft block with the same bounds
|
* Generates a box, uv mapped to be the same as a minecraft block with the same bounds
|
||||||
*
|
*
|
||||||
* @param i The vertex index to start generating at
|
* @param i The vertex index to start generating at
|
||||||
* @param x1 minX
|
* @param x1 minX
|
||||||
* @param y1 minY
|
* @param y1 minY
|
||||||
@@ -311,7 +311,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the normals of all faces in the model. Uses the cross product of the vectors along 2 sides of the face
|
* Computes the normals of all faces in the model. Uses the cross product of the vectors along 2 sides of the face
|
||||||
*
|
*
|
||||||
* @param start The first vertex to generate normals for
|
* @param start The first vertex to generate normals for
|
||||||
* @param length The number of vertices to generate normals for. Note this must be a multiple of 3 for triangles or
|
* @param length The number of vertices to generate normals for. Note this must be a multiple of 3 for triangles or
|
||||||
* 4 for quads
|
* 4 for quads
|
||||||
@@ -321,7 +321,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
if (length % vp != 0 || start % vp != 0)
|
if (length % vp != 0 || start % vp != 0)
|
||||||
throw new IllegalArgumentException("Cannot generate normals across polygons");
|
throw new IllegalArgumentException("Cannot generate normals across polygons");
|
||||||
|
|
||||||
Vector3[] normals = getOrAllocate(CCRenderState.normalAttrib);
|
Vector3[] normals = getOrAllocate(CCRenderState.normalAttrib());
|
||||||
for (int k = 0; k < length; k += vp) {
|
for (int k = 0; k < length; k += vp) {
|
||||||
int i = k + start;
|
int i = k + start;
|
||||||
Vector3 diff1 = verts[i + 1].vec.copy().subtract(verts[i].vec);
|
Vector3 diff1 = verts[i + 1].vec.copy().subtract(verts[i].vec);
|
||||||
@@ -336,14 +336,14 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
/**
|
/**
|
||||||
* Computes lighting using the normals add a light model If the model is rotated, the lighting will no longer be
|
* Computes lighting using the normals add a light model If the model is rotated, the lighting will no longer be
|
||||||
* valid
|
* valid
|
||||||
*
|
*
|
||||||
* @return The model
|
* @return The model
|
||||||
*/
|
*/
|
||||||
public CCModel computeLighting(LightModel light) {
|
public CCModel computeLighting(LightModel light) {
|
||||||
Vector3[] normals = normals();
|
Vector3[] normals = normals();
|
||||||
int[] colours = getAttributes(CCRenderState.lightingAttrib);
|
int[] colours = getAttributes(CCRenderState.lightingAttrib());
|
||||||
if (colours == null) {
|
if (colours == null) {
|
||||||
colours = getOrAllocate(CCRenderState.lightingAttrib);
|
colours = getOrAllocate(CCRenderState.lightingAttrib());
|
||||||
Arrays.fill(colours, -1);
|
Arrays.fill(colours, -1);
|
||||||
}
|
}
|
||||||
for (int k = 0; k < verts.length; k++) colours[k] = light.apply(colours[k], normals[k]);
|
for (int k = 0; k < verts.length; k++) colours[k] = light.apply(colours[k], normals[k]);
|
||||||
@@ -351,18 +351,18 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CCModel setColour(int c) {
|
public CCModel setColour(int c) {
|
||||||
int[] colours = getOrAllocate(CCRenderState.colourAttrib);
|
int[] colours = getOrAllocate(CCRenderState.colourAttrib());
|
||||||
Arrays.fill(colours, c);
|
Arrays.fill(colours, c);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the minecraft lighting coordinates for use with a LightMatrix
|
* Computes the minecraft lighting coordinates for use with a LightMatrix
|
||||||
*
|
*
|
||||||
* @return The model
|
* @return The model
|
||||||
*/
|
*/
|
||||||
public CCModel computeLightCoords() {
|
public CCModel computeLightCoords() {
|
||||||
LC[] lcs = getOrAllocate(CCRenderState.lightCoordAttrib);
|
LC[] lcs = getOrAllocate(CCRenderState.lightCoordAttrib());
|
||||||
Vector3[] normals = normals();
|
Vector3[] normals = normals();
|
||||||
for (int i = 0; i < verts.length; i++) lcs[i] = new LC().compute(verts[i].vec, normals[i]);
|
for (int i = 0; i < verts.length; i++) lcs[i] = new LC().compute(verts[i].vec, normals[i]);
|
||||||
return this;
|
return this;
|
||||||
@@ -370,7 +370,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Averages all normals at the same position to produce a smooth lighting effect.
|
* Averages all normals at the same position to produce a smooth lighting effect.
|
||||||
*
|
*
|
||||||
* @return The model
|
* @return The model
|
||||||
*/
|
*/
|
||||||
public CCModel smoothNormals() {
|
public CCModel smoothNormals() {
|
||||||
@@ -461,7 +461,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders vertices start through start+length-1 of the model
|
* Renders vertices start through start+length-1 of the model
|
||||||
*
|
*
|
||||||
* @param start The first vertex index to render
|
* @param start The first vertex index to render
|
||||||
* @param end The vertex index to render until
|
* @param end The vertex index to render until
|
||||||
* @param ops Operations to apply
|
* @param ops Operations to apply
|
||||||
@@ -520,7 +520,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
||||||
*
|
*
|
||||||
* @param input An input stream to a obj file
|
* @param input An input stream to a obj file
|
||||||
* @param vertexMode The vertex mode to create the model for (GL_TRIANGLES or GL_QUADS)
|
* @param vertexMode The vertex mode to create the model for (GL_TRIANGLES or GL_QUADS)
|
||||||
* @param coordSystem The cooridnate system transformation to apply
|
* @param coordSystem The cooridnate system transformation to apply
|
||||||
@@ -624,7 +624,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
||||||
*
|
*
|
||||||
* @param res The resource for the obj file
|
* @param res The resource for the obj file
|
||||||
* @return A map of group names to models
|
* @return A map of group names to models
|
||||||
*/
|
*/
|
||||||
@@ -634,7 +634,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
||||||
*
|
*
|
||||||
* @param res The resource for the obj file
|
* @param res The resource for the obj file
|
||||||
* @param coordSystem The cooridnate system transformation to apply
|
* @param coordSystem The cooridnate system transformation to apply
|
||||||
* @return A map of group names to models
|
* @return A map of group names to models
|
||||||
@@ -652,7 +652,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
* Parses vertices, texture coords, normals and polygons from a WaveFront Obj file
|
||||||
*
|
*
|
||||||
* @param res The resource for the obj file
|
* @param res The resource for the obj file
|
||||||
* @param vertexMode The vertex mode to create the model for (GL_TRIANGLES or GL_QUADS)
|
* @param vertexMode The vertex mode to create the model for (GL_TRIANGLES or GL_QUADS)
|
||||||
* @param coordSystem The cooridnate system transformation to apply
|
* @param coordSystem The cooridnate system transformation to apply
|
||||||
@@ -678,7 +678,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
boolean hasNormals = polys.get(0)[2] > 0;
|
boolean hasNormals = polys.get(0)[2] > 0;
|
||||||
CCModel model = CCModel.newModel(vertexMode, polys.size());
|
CCModel model = CCModel.newModel(vertexMode, polys.size());
|
||||||
if (hasNormals) model.getOrAllocate(CCRenderState.normalAttrib);
|
if (hasNormals) model.getOrAllocate(CCRenderState.normalAttrib());
|
||||||
|
|
||||||
for (int i = 0; i < polys.size(); i++) {
|
for (int i = 0; i < polys.size(); i++) {
|
||||||
int[] ai = polys.get(i);
|
int[] ai = polys.get(i);
|
||||||
@@ -807,7 +807,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate models rotated to the other 5 sides of the block
|
* Generate models rotated to the other 5 sides of the block
|
||||||
*
|
*
|
||||||
* @param models An array of 6 models
|
* @param models An array of 6 models
|
||||||
* @param side The side of this model
|
* @param side The side of this model
|
||||||
* @param point The rotation point
|
* @param point The rotation point
|
||||||
@@ -822,7 +822,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate models rotated to the other 3 horizontal of the block
|
* Generate models rotated to the other 3 horizontal of the block
|
||||||
*
|
*
|
||||||
* @param models An array of 4 models
|
* @param models An array of 4 models
|
||||||
* @param side The side of this model
|
* @param side The side of this model
|
||||||
* @param point The rotation point
|
* @param point The rotation point
|
||||||
@@ -841,7 +841,7 @@ public class CCModel implements CCRenderState.IVertexSource, Copyable<CCModel> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates copies of faces with clockwise vertices
|
* Generates copies of faces with clockwise vertices
|
||||||
*
|
*
|
||||||
* @return The model
|
* @return The model
|
||||||
*/
|
*/
|
||||||
public static CCModel generateBackface(CCModel src, int srcpos, CCModel dst, int destpos, int length) {
|
public static CCModel generateBackface(CCModel src, int srcpos, CCModel dst, int destpos, int length) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package codechicken.lib.render;
|
package codechicken.lib.render;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.OpenGlHelper;
|
import net.minecraft.client.renderer.OpenGlHelper;
|
||||||
@@ -38,9 +39,9 @@ public class CCRenderState {
|
|||||||
return instances.get();
|
return instances.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int nextOperationIndex;
|
private static volatile int nextOperationIndex;
|
||||||
|
|
||||||
public static int registerOperation() {
|
public static synchronized int registerOperation() {
|
||||||
return nextOperationIndex++;
|
return nextOperationIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,15 +88,52 @@ public class CCRenderState {
|
|||||||
int operationID();
|
int operationID();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayList<VertexAttribute<?>> vertexAttributes = new ArrayList<>();
|
public static final class AttributeKey<T> {
|
||||||
|
|
||||||
private static int registerVertexAttribute(VertexAttribute<?> attr) {
|
private static final HashMap<String, AttributeKey<?>> nameMap = new HashMap<>();
|
||||||
vertexAttributes.add(attr);
|
private static final ArrayList<AttributeKey<?>> attributeKeys = new ArrayList<>();
|
||||||
return vertexAttributes.size() - 1;
|
private static int nextLegacyId;
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final int attributeKeyIndex;
|
||||||
|
public final int operationIndex;
|
||||||
|
private VertexAttribute<T> canonical;
|
||||||
|
|
||||||
|
private AttributeKey(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.attributeKeyIndex = attributeKeys.size();
|
||||||
|
this.operationIndex = registerOperation();
|
||||||
|
attributeKeys.add(this);
|
||||||
|
nameMap.put(name, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized <T> AttributeKey<T> create(String name) {
|
||||||
|
if (nameMap.containsKey(name))
|
||||||
|
throw new IllegalArgumentException("Duplicate registration of attribute with name: " + name);
|
||||||
|
return new AttributeKey<>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static synchronized <T> AttributeKey<T> createLegacy() {
|
||||||
|
return new AttributeKey<>("legacy#" + nextLegacyId++);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setCanonical(VertexAttribute<T> attr) {
|
||||||
|
if (canonical == null) canonical = attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static synchronized AttributeKey<?> get(int index) {
|
||||||
|
return attributeKeys.get(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final AttributeKey<Vector3[]> NORMAL_KEY = AttributeKey.create("normal");
|
||||||
|
private static final AttributeKey<int[]> COLOUR_KEY = AttributeKey.create("colour");
|
||||||
|
private static final AttributeKey<int[]> LIGHTING_KEY = AttributeKey.create("lighting");
|
||||||
|
private static final AttributeKey<int[]> SIDE_KEY = AttributeKey.create("side");
|
||||||
|
private static final AttributeKey<LC[]> LC_KEY = AttributeKey.create("lc");
|
||||||
|
|
||||||
public static VertexAttribute<?> getAttribute(int index) {
|
public static VertexAttribute<?> getAttribute(int index) {
|
||||||
return vertexAttributes.get(index);
|
return AttributeKey.get(index).canonical;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,14 +144,26 @@ public class CCRenderState {
|
|||||||
*/
|
*/
|
||||||
public abstract static class VertexAttribute<T> implements IVertexOperation {
|
public abstract static class VertexAttribute<T> implements IVertexOperation {
|
||||||
|
|
||||||
public final int attributeIndex = registerVertexAttribute(this);
|
public final int attributeIndex;
|
||||||
private final int operationIndex = registerOperation();
|
private final int operationIndex;
|
||||||
/**
|
/**
|
||||||
* Set to true when the attrute is part of the pipeline. Should only be managed by CCRenderState when
|
* Set to true when the attrute is part of the pipeline. Should only be managed by CCRenderState when
|
||||||
* constructing the pipeline
|
* constructing the pipeline
|
||||||
*/
|
*/
|
||||||
public boolean active = false;
|
public boolean active = false;
|
||||||
|
|
||||||
|
protected VertexAttribute(AttributeKey<T> key) {
|
||||||
|
attributeIndex = key.attributeKeyIndex;
|
||||||
|
operationIndex = key.operationIndex;
|
||||||
|
key.setCanonical(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @deprecated keyless attributes get a per-construction index that is threadsafe */
|
||||||
|
@Deprecated
|
||||||
|
protected VertexAttribute() {
|
||||||
|
this(AttributeKey.createLegacy());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new array for storage of vertex attrutes in a model
|
* Construct a new array for storage of vertex attrutes in a model
|
||||||
*/
|
*/
|
||||||
@@ -169,7 +219,27 @@ public class CCRenderState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VertexAttribute<Vector3[]> normalAttrib = new VertexAttribute<>() {
|
public static VertexAttribute<Vector3[]> normalAttrib() {
|
||||||
|
return instances.get().normalAttrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VertexAttribute<int[]> colourAttrib() {
|
||||||
|
return instances.get().colourAttrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VertexAttribute<LC[]> lightCoordAttrib() {
|
||||||
|
return instances.get().lightCoordAttrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VertexAttribute<int[]> sideAttrib() {
|
||||||
|
return instances.get().sideAttrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VertexAttribute<int[]> lightingAttrib() {
|
||||||
|
return instances.get().lightingAttrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VertexAttribute<Vector3[]> normalAttrib = new VertexAttribute<>(NORMAL_KEY) {
|
||||||
|
|
||||||
private Vector3[] normalRef;
|
private Vector3[] normalRef;
|
||||||
|
|
||||||
@@ -197,7 +267,7 @@ public class CCRenderState {
|
|||||||
else state.setNormalInstance(Rotation.axes[state.side]);
|
else state.setNormalInstance(Rotation.axes[state.side]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static VertexAttribute<int[]> colourAttrib = new VertexAttribute<>() {
|
public VertexAttribute<int[]> colourAttrib = new VertexAttribute<>(COLOUR_KEY) {
|
||||||
|
|
||||||
private int[] colourRef;
|
private int[] colourRef;
|
||||||
|
|
||||||
@@ -219,7 +289,7 @@ public class CCRenderState {
|
|||||||
else state.setColourInstance(state.baseColour);
|
else state.setColourInstance(state.baseColour);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static VertexAttribute<int[]> lightingAttrib = new VertexAttribute<>() {
|
public VertexAttribute<int[]> lightingAttrib = new VertexAttribute<>(LIGHTING_KEY) {
|
||||||
|
|
||||||
private int[] colourRef;
|
private int[] colourRef;
|
||||||
|
|
||||||
@@ -245,7 +315,7 @@ public class CCRenderState {
|
|||||||
state.setColourInstance(ColourRGBA.multiply(state.colour, colourRef[state.vertexIndex]));
|
state.setColourInstance(ColourRGBA.multiply(state.colour, colourRef[state.vertexIndex]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static VertexAttribute<int[]> sideAttrib = new VertexAttribute<>() {
|
public VertexAttribute<int[]> sideAttrib = new VertexAttribute<>(SIDE_KEY) {
|
||||||
|
|
||||||
private int[] sideRef;
|
private int[] sideRef;
|
||||||
|
|
||||||
@@ -272,7 +342,7 @@ public class CCRenderState {
|
|||||||
/**
|
/**
|
||||||
* Uses the position of the lightmatrix to compute LC if not provided
|
* Uses the position of the lightmatrix to compute LC if not provided
|
||||||
*/
|
*/
|
||||||
public static VertexAttribute<LC[]> lightCoordAttrib = new VertexAttribute<>() {
|
public VertexAttribute<LC[]> lightCoordAttrib = new VertexAttribute<>(LC_KEY) {
|
||||||
|
|
||||||
private LC[] lcRef;
|
private LC[] lcRef;
|
||||||
private final Vector3 vec = new Vector3(); // for computation
|
private final Vector3 vec = new Vector3(); // for computation
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package codechicken.lib.render;
|
package codechicken.lib.render;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import net.minecraft.client.particle.EffectRenderer;
|
import net.minecraft.client.particle.EffectRenderer;
|
||||||
import net.minecraft.client.particle.EntityFX;
|
import net.minecraft.client.particle.EntityFX;
|
||||||
import net.minecraft.client.renderer.Tessellator;
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
@@ -11,6 +13,9 @@ import codechicken.lib.vec.Vector3;
|
|||||||
|
|
||||||
public class EntityDigIconFX extends EntityFX {
|
public class EntityDigIconFX extends EntityFX {
|
||||||
|
|
||||||
|
/** Tint that leaves the particle colour untouched, for materials that don't colour their texture. */
|
||||||
|
public static final int NO_TINT = 0xFFFFFF;
|
||||||
|
|
||||||
public EntityDigIconFX(World world, double x, double y, double z, double dx, double dy, double dz, IIcon icon) {
|
public EntityDigIconFX(World world, double x, double y, double z, double dx, double dy, double dz, IIcon icon) {
|
||||||
super(world, x, y, z, dx, dy, dz);
|
super(world, x, y, z, dx, dy, dz);
|
||||||
particleIcon = icon;
|
particleIcon = icon;
|
||||||
@@ -19,6 +24,18 @@ public class EntityDigIconFX extends EntityFX {
|
|||||||
particleScale /= 2.0F;
|
particleScale /= 2.0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies the particle colour by an 0xRRGGBB tint, the equivalent of vanilla
|
||||||
|
* EntityDiggingFX.applyColourMultiplier. Materials that draw a greyscale texture and colour it at render time
|
||||||
|
* (leaves, grass tops) need this, or their particles come out flat grey.
|
||||||
|
*/
|
||||||
|
public EntityDigIconFX applyColourMultiplier(int colour) {
|
||||||
|
particleRed *= (colour >> 16 & 255) / 255F;
|
||||||
|
particleGreen *= (colour >> 8 & 255) / 255F;
|
||||||
|
particleBlue *= (colour & 255) / 255F;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFXLayer() {
|
public int getFXLayer() {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -90,8 +107,24 @@ public class EntityDigIconFX extends EntityFX {
|
|||||||
f9);
|
f9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated the particle is never tinted, so a material that colours a greyscale texture at render time (leaves,
|
||||||
|
* grass tops) breaks into grey particles. Use
|
||||||
|
* {@link #addBlockHitEffects(World, Cuboid6, int, IIcon, int, EffectRenderer)}, passing
|
||||||
|
* {@link #NO_TINT} for materials whose texture is already coloured.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static void addBlockHitEffects(World world, Cuboid6 bounds, int side, IIcon icon,
|
public static void addBlockHitEffects(World world, Cuboid6 bounds, int side, IIcon icon,
|
||||||
EffectRenderer effectRenderer) {
|
EffectRenderer effectRenderer) {
|
||||||
|
addBlockHitEffects(world, bounds, side, icon, NO_TINT, effectRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawns a hit particle on side of bounds, tinted by colour (0xRRGGBB, {@link #NO_TINT} for none). The caller
|
||||||
|
* resolves the tint for the side it hit, so per-face materials like grass can tint only the faces that need it.
|
||||||
|
*/
|
||||||
|
public static void addBlockHitEffects(World world, Cuboid6 bounds, int side, IIcon icon, int colour,
|
||||||
|
EffectRenderer effectRenderer) {
|
||||||
float border = 0.1F;
|
float border = 0.1F;
|
||||||
Vector3 diff = bounds.max.copy().subtract(bounds.min).add(-2 * border);
|
Vector3 diff = bounds.max.copy().subtract(bounds.min).add(-2 * border);
|
||||||
diff.x *= world.rand.nextDouble();
|
diff.x *= world.rand.nextDouble();
|
||||||
@@ -106,13 +139,34 @@ public class EntityDigIconFX extends EntityFX {
|
|||||||
if (side == 4) diff.x = bounds.min.x - border;
|
if (side == 4) diff.x = bounds.min.x - border;
|
||||||
if (side == 5) diff.x = bounds.max.x + border;
|
if (side == 5) diff.x = bounds.max.x + border;
|
||||||
|
|
||||||
effectRenderer.addEffect(
|
EntityDigIconFX fx = new EntityDigIconFX(world, pos.x, pos.y, pos.z, 0, 0, 0, icon);
|
||||||
new EntityDigIconFX(world, pos.x, pos.y, pos.z, 0, 0, 0, icon).multiplyVelocity(0.2F)
|
effectRenderer.addEffect(fx.applyColourMultiplier(colour).multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F));
|
||||||
.multipleParticleScaleBy(0.6F));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated the particles are never tinted, so a material that colours a greyscale texture at render time
|
||||||
|
* (leaves, grass tops) breaks into grey particles. Use
|
||||||
|
* {@link #addBlockDestroyEffects(World, Cuboid6, IIcon[], int[], EffectRenderer)}, passing
|
||||||
|
* {@link #NO_TINT} for the faces whose texture is already coloured.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static void addBlockDestroyEffects(World world, Cuboid6 bounds, IIcon[] icons,
|
public static void addBlockDestroyEffects(World world, Cuboid6 bounds, IIcon[] icons,
|
||||||
EffectRenderer effectRenderer) {
|
EffectRenderer effectRenderer) {
|
||||||
|
int[] colours = new int[icons.length];
|
||||||
|
Arrays.fill(colours, NO_TINT);
|
||||||
|
addBlockDestroyEffects(world, bounds, icons, colours, effectRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawns break particles filling bounds, each drawn from a random face. colours holds the 0xRRGGBB tint for the
|
||||||
|
* matching entry of icons ({@link #NO_TINT} for none) and must be the same length, so a particle is tinted by the
|
||||||
|
* face it was taken from.
|
||||||
|
*/
|
||||||
|
public static void addBlockDestroyEffects(World world, Cuboid6 bounds, IIcon[] icons, int[] colours,
|
||||||
|
EffectRenderer effectRenderer) {
|
||||||
|
if (icons.length != colours.length)
|
||||||
|
throw new IllegalArgumentException("icons and colours must have the same length");
|
||||||
|
|
||||||
Vector3 diff = bounds.max.copy().subtract(bounds.min);
|
Vector3 diff = bounds.max.copy().subtract(bounds.min);
|
||||||
Vector3 center = bounds.min.copy().add(bounds.max).multiply(0.5);
|
Vector3 center = bounds.min.copy().add(bounds.max).multiply(0.5);
|
||||||
Vector3 density = diff.copy().multiply(4);
|
Vector3 density = diff.copy().multiply(4);
|
||||||
@@ -121,19 +175,20 @@ public class EntityDigIconFX extends EntityFX {
|
|||||||
density.z = Math.ceil(density.z);
|
density.z = Math.ceil(density.z);
|
||||||
|
|
||||||
for (int i = 0; i < density.x; ++i) for (int j = 0; j < density.y; ++j) for (int k = 0; k < density.z; ++k) {
|
for (int i = 0; i < density.x; ++i) for (int j = 0; j < density.y; ++j) for (int k = 0; k < density.z; ++k) {
|
||||||
double x = bounds.min.x + (i + 0.5) * diff.x / density.x;
|
double px = bounds.min.x + (i + 0.5) * diff.x / density.x;
|
||||||
double y = bounds.min.y + (j + 0.5) * diff.y / density.y;
|
double py = bounds.min.y + (j + 0.5) * diff.y / density.y;
|
||||||
double z = bounds.min.z + (k + 0.5) * diff.z / density.z;
|
double pz = bounds.min.z + (k + 0.5) * diff.z / density.z;
|
||||||
effectRenderer.addEffect(
|
int iconSide = world.rand.nextInt(icons.length);
|
||||||
new EntityDigIconFX(
|
EntityDigIconFX fx = new EntityDigIconFX(
|
||||||
world,
|
world,
|
||||||
x,
|
px,
|
||||||
y,
|
py,
|
||||||
z,
|
pz,
|
||||||
x - center.x,
|
px - center.x,
|
||||||
y - center.y,
|
py - center.y,
|
||||||
z - center.z,
|
pz - center.z,
|
||||||
icons[world.rand.nextInt(icons.length)]));
|
icons[iconSide]);
|
||||||
|
effectRenderer.addEffect(fx.applyColourMultiplier(colours[iconSide]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,8 @@ import net.minecraft.item.ItemStack;
|
|||||||
|
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import codechicken.lib.colour.LocalizedColours;
|
||||||
|
|
||||||
public class FontUtils {
|
public class FontUtils {
|
||||||
|
|
||||||
public static FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
|
public static FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
|
||||||
@@ -53,7 +55,7 @@ public class FontUtils {
|
|||||||
GL11.glPushMatrix();
|
GL11.glPushMatrix();
|
||||||
GL11.glTranslated(x + 16 - swidth, y + 16 - sheight, 0);
|
GL11.glTranslated(x + 16 - swidth, y + 16 - sheight, 0);
|
||||||
GL11.glScaled(scale, scale, 1);
|
GL11.glScaled(scale, scale, 1);
|
||||||
fontRenderer.drawStringWithShadow(quantity, 0, 0, 0xFFFFFF);
|
fontRenderer.drawStringWithShadow(quantity, 0, 0, LocalizedColours.ITEM_QUANTITY_TEXT);
|
||||||
GL11.glPopMatrix();
|
GL11.glPopMatrix();
|
||||||
GL11.glEnable(GL11.GL_LIGHTING);
|
GL11.glEnable(GL11.GL_LIGHTING);
|
||||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ public abstract class Transformation extends ITransformation<Vector3, Transforma
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies this transformation to a normal (doesn't translate)
|
* Applies this transformation to a normal (doesn't translate)
|
||||||
*
|
*
|
||||||
* @param normal The normal to transform
|
* @param normal The normal to transform
|
||||||
*/
|
*/
|
||||||
public abstract void applyN(Vector3 normal);
|
public abstract void applyN(Vector3 normal);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies this transformation to a matrix as a multiplication on the right hand side.
|
* Applies this transformation to a matrix as a multiplication on the right hand side.
|
||||||
*
|
*
|
||||||
* @param mat The matrix to combine this transformation with
|
* @param mat The matrix to combine this transformation with
|
||||||
*/
|
*/
|
||||||
public abstract void apply(Matrix4 mat);
|
public abstract void apply(Matrix4 mat);
|
||||||
@@ -39,14 +39,14 @@ public abstract class Transformation extends ITransformation<Vector3, Transforma
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean load(CCRenderState state) {
|
public boolean load(CCRenderState state) {
|
||||||
state.pipeline.addRequirement(CCRenderState.normalAttrib.operationID());
|
state.pipeline.addRequirement(CCRenderState.normalAttrib().operationID());
|
||||||
return !isRedundant();
|
return !isRedundant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void operate(CCRenderState state) {
|
public void operate(CCRenderState state) {
|
||||||
apply(state.vert.vec);
|
apply(state.vert.vec);
|
||||||
if (CCRenderState.normalAttrib.active) applyN(state.normal);
|
if (CCRenderState.normalAttrib().active) applyN(state.normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ public class WorldExtensionManager {
|
|||||||
public void onChunkUnLoad(ChunkEvent.Unload event) {
|
public void onChunkUnLoad(ChunkEvent.Unload event) {
|
||||||
if (event.getChunk() instanceof EmptyChunk) return;
|
if (event.getChunk() instanceof EmptyChunk) return;
|
||||||
|
|
||||||
for (WorldExtension extension : worldMap.get(event.world)) extension.unloadChunk(event.getChunk());
|
WorldExtension[] extensions = worldMap.get(event.world);
|
||||||
|
if (extensions == null) return;
|
||||||
|
|
||||||
|
for (WorldExtension extension : extensions) extension.unloadChunk(event.getChunk());
|
||||||
|
|
||||||
if (event.world.isRemote) removeChunk(event.world, event.getChunk());
|
if (event.world.isRemote) removeChunk(event.world, event.getChunk());
|
||||||
}
|
}
|
||||||
@@ -79,17 +82,25 @@ public class WorldExtensionManager {
|
|||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onChunkWatch(Watch event) {
|
public void onChunkWatch(Watch event) {
|
||||||
Chunk chunk = event.player.worldObj.getChunkFromChunkCoords(event.chunk.chunkXPos, event.chunk.chunkZPos);
|
WorldExtension[] extensions = worldMap.get(event.player.worldObj);
|
||||||
for (WorldExtension extension : worldMap.get(event.player.worldObj))
|
|
||||||
extension.watchChunk(chunk, event.player);
|
if (extensions != null) {
|
||||||
|
Chunk chunk = event.player.worldObj
|
||||||
|
.getChunkFromChunkCoords(event.chunk.chunkXPos, event.chunk.chunkZPos);
|
||||||
|
for (WorldExtension extension : extensions) extension.watchChunk(chunk, event.player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
public void onChunkUnWatch(UnWatch event) {
|
public void onChunkUnWatch(UnWatch event) {
|
||||||
Chunk chunk = event.player.worldObj.getChunkFromChunkCoords(event.chunk.chunkXPos, event.chunk.chunkZPos);
|
WorldExtension[] extensions = worldMap.get(event.player.worldObj);
|
||||||
for (WorldExtension extension : worldMap.get(event.player.worldObj))
|
|
||||||
extension.unwatchChunk(chunk, event.player);
|
if (extensions != null) {
|
||||||
|
Chunk chunk = event.player.worldObj
|
||||||
|
.getChunkFromChunkCoords(event.chunk.chunkXPos, event.chunk.chunkZPos);
|
||||||
|
for (WorldExtension extension : extensions) extension.unwatchChunk(chunk, event.player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
@@ -110,7 +121,7 @@ public class WorldExtensionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean initialised;
|
private static boolean initialised;
|
||||||
private static ArrayList<WorldExtensionInstantiator> extensionIntialisers = new ArrayList<WorldExtensionInstantiator>();
|
private static ArrayList<WorldExtensionInstantiator> extensionIntialisers = new ArrayList<>();
|
||||||
|
|
||||||
public static void registerWorldExtension(WorldExtensionInstantiator init) {
|
public static void registerWorldExtension(WorldExtensionInstantiator init) {
|
||||||
if (!initialised) init();
|
if (!initialised) init();
|
||||||
@@ -125,7 +136,7 @@ public class WorldExtensionManager {
|
|||||||
FMLCommonHandler.instance().bus().register(new WorldExtensionEventHandler());
|
FMLCommonHandler.instance().bus().register(new WorldExtensionEventHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashMap<World, WorldExtension[]> worldMap = new HashMap<World, WorldExtension[]>();
|
private static HashMap<World, WorldExtension[]> worldMap = new HashMap<>();
|
||||||
|
|
||||||
private static void onWorldLoad(World world) {
|
private static void onWorldLoad(World world) {
|
||||||
WorldExtension[] extensions = new WorldExtension[extensionIntialisers.size()];
|
WorldExtension[] extensions = new WorldExtension[extensionIntialisers.size()];
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ import java.io.BufferedReader;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.commons.RemappingClassAdapter;
|
import org.objectweb.asm.commons.Remapper;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
@@ -181,7 +183,40 @@ public class ObfuscationRun implements ILogStreams {
|
|||||||
|
|
||||||
public void remap(ClassNode cnode, ClassVisitor cv) {
|
public void remap(ClassNode cnode, ClassVisitor cv) {
|
||||||
cstMappper.transform(cnode);
|
cstMappper.transform(cnode);
|
||||||
cnode.accept(new RemappingClassAdapter(cv, obfMapper));
|
cnode.accept(newRemapper(cv, obfMapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClassVisitor newRemapper(ClassVisitor visitor, Remapper remapper) {
|
||||||
|
try {
|
||||||
|
return theConstructor.newInstance(visitor, remapper);
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Constructor<? extends ClassVisitor> theConstructor;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Class<? extends ClassVisitor> remapperClass;
|
||||||
|
try {
|
||||||
|
// noinspection unchecked
|
||||||
|
remapperClass = (Class<? extends ClassVisitor>) Class.forName("org.objectweb.asm.commons.ClassRemapper");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
try {
|
||||||
|
// noinspection unchecked
|
||||||
|
remapperClass = (Class<? extends ClassVisitor>) Class
|
||||||
|
.forName("org.objectweb.asm.commons.RemappingClassAdapter");
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
RuntimeException err = new RuntimeException(ex);
|
||||||
|
err.addSuppressed(e);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
theConstructor = remapperClass.getConstructor(ClassVisitor.class, Remapper.class);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> getParents(ClassNode cnode) {
|
public static List<String> getParents(ClassNode cnode) {
|
||||||
|
|||||||
@@ -1 +1,26 @@
|
|||||||
codechickencore.update=Version %s of %s is available
|
codechickencore.update=Version %s of %s is available
|
||||||
|
|
||||||
|
codechickencore.color.buttonTextDisabled=FFA0A0A0
|
||||||
|
codechickencore.color.buttonTextHover=FFFFFFA0
|
||||||
|
codechickencore.color.buttonText=FFE0E0E0
|
||||||
|
codechickencore.color.textFieldBorder=FFA0A0A0
|
||||||
|
codechickencore.color.textFieldBackground=FF000000
|
||||||
|
codechickencore.color.textFieldText=E0E0E0
|
||||||
|
codechickencore.color.textFieldTextDisabled=707070
|
||||||
|
codechickencore.color.background=FF000000
|
||||||
|
codechickencore.color.overlayTop=FFA0A0A0
|
||||||
|
codechickencore.color.overlayBottom=FFA0A0A0
|
||||||
|
codechickencore.color.overlayLeft=FFA0A0A0
|
||||||
|
codechickencore.color.overlayRight=FFA0A0A0
|
||||||
|
codechickencore.color.scrollbarCorners=FF8B8B8B
|
||||||
|
codechickencore.color.scrollbarTopLeft=FFF0F0F0
|
||||||
|
codechickencore.color.scrollbarBottomRight=FF555555
|
||||||
|
codechickencore.color.scrollbarFill=FFC6C6C6
|
||||||
|
codechickencore.color.scrollbarGuide=FF808080
|
||||||
|
codechickencore.color.tooltipBgStart=F0100010
|
||||||
|
codechickencore.color.tooltipBgEnd=F0100010
|
||||||
|
codechickencore.color.tooltipBorderStart=505000FF
|
||||||
|
codechickencore.color.tooltipBorderEnd=5028007F
|
||||||
|
codechickencore.color.tooltipText=FFFFFFFF
|
||||||
|
codechickencore.color.itemQuantityText=FFFFFF
|
||||||
|
codechickencore.color.modDescriptionText=DDDDDD
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
codechickencore.update=Доступна версія %s для %s
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
package codechicken.lib.packet;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
|
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
public class PacketCustomTest {
|
||||||
|
|
||||||
|
private static final int MAX_DECOMPRESSED_SIZE = 2 * 1024 * 1024;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsLargeDeclarationWithoutCompressedData() {
|
||||||
|
assertRejected(Unpooled.buffer(5).writeByte(0x81).writeInt(8 * 1024 * 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(ints = { -1, Integer.MIN_VALUE, MAX_DECOMPRESSED_SIZE + 1, Integer.MAX_VALUE })
|
||||||
|
public void rejectsInvalidDeclaredLengths(int length) {
|
||||||
|
assertRejected(Unpooled.buffer(5).writeByte(0x81).writeInt(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsMissingCompressedDataWithinLimit() {
|
||||||
|
assertRejected(Unpooled.buffer(5).writeByte(0x81).writeInt(MAX_DECOMPRESSED_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsCompleteStreamAboveDecodeLimit() {
|
||||||
|
assertRejected(compressed(new byte[MAX_DECOMPRESSED_SIZE + 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsTruncatedLengthHeader() {
|
||||||
|
assertRejected(Unpooled.buffer(4).writeByte(0x81).writeMedium(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsMismatchedInflatedLengths() {
|
||||||
|
byte[] data = new byte[16384];
|
||||||
|
assertRejected(compressed(data).setInt(1, data.length - 1));
|
||||||
|
assertRejected(compressed(data).setInt(1, data.length + 1));
|
||||||
|
assertRejected(compressed(data).setInt(1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsTruncatedStreamEvenWhenAllOutputWasProduced() {
|
||||||
|
ByteBuf payload = compressed(new byte[16384]);
|
||||||
|
payload.writerIndex(payload.writerIndex() - 1);
|
||||||
|
assertRejected(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsCorruptStream() {
|
||||||
|
ByteBuf payload = compressed(new byte[16384]);
|
||||||
|
payload.setByte(payload.writerIndex() - 1, payload.getByte(payload.writerIndex() - 1) ^ 1);
|
||||||
|
assertRejected(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsDictionaryDependentStream() {
|
||||||
|
assertRejected(compressed(new byte[16384], new byte[] { 1, 2, 3 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsTrailingCompressedData() {
|
||||||
|
assertRejected(compressed(new byte[16384]).writeByte(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(ints = { 0, 1, 8192, 8193, MAX_DECOMPRESSED_SIZE })
|
||||||
|
public void decodesCompleteStreams(int length) {
|
||||||
|
byte[] data = new byte[length];
|
||||||
|
Arrays.fill(data, (byte) 42);
|
||||||
|
assertDecoded(compressed(data), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void decodesSlicedAndDirectBuffers() {
|
||||||
|
byte[] data = new byte[16384];
|
||||||
|
Arrays.fill(data, (byte) 42);
|
||||||
|
ByteBuf payload = compressed(data);
|
||||||
|
ByteBuf prefixed = Unpooled.buffer().writeLong(-1).writeBytes(payload, 0, payload.readableBytes());
|
||||||
|
ByteBuf direct = Unpooled.directBuffer().writeBytes(payload);
|
||||||
|
payload.release();
|
||||||
|
try {
|
||||||
|
assertDecoded(prefixed.slice(8, prefixed.readableBytes() - 8).retain(), data);
|
||||||
|
assertDecoded(direct, data);
|
||||||
|
} finally {
|
||||||
|
prefixed.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void preservesUncompressedPackets() {
|
||||||
|
ByteBuf payload = Unpooled.buffer().writeByte(7).writeInt(42);
|
||||||
|
try {
|
||||||
|
PacketCustom packet = new PacketCustom(payload);
|
||||||
|
assertEquals(7, packet.getType());
|
||||||
|
assertEquals(42, packet.readInt());
|
||||||
|
assertEquals(0, packet.getByteBuf().readableBytes());
|
||||||
|
} finally {
|
||||||
|
payload.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundTripsOutgoingCompression() {
|
||||||
|
for (int length : new int[] { 16, 64, 40000, MAX_DECOMPRESSED_SIZE }) {
|
||||||
|
byte[] data = new byte[length];
|
||||||
|
Arrays.fill(data, (byte) 42);
|
||||||
|
PacketCustom outgoing = new PacketCustom("PacketTest", 7);
|
||||||
|
FMLProxyPacket wire = null;
|
||||||
|
try {
|
||||||
|
outgoing.writeByteArray(data);
|
||||||
|
if (length <= 64) outgoing.compress();
|
||||||
|
wire = outgoing.toPacket();
|
||||||
|
assertEquals(length == 16 ? 7 : 0x87, wire.payload().getUnsignedByte(0));
|
||||||
|
assertDecoded(wire.payload().retain(), data);
|
||||||
|
} finally {
|
||||||
|
if (wire != null) wire.payload().release();
|
||||||
|
outgoing.getByteBuf().release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(booleans = { false, true })
|
||||||
|
public void repeatedSerializationPreservesCompressedPayload(boolean forceCompression) {
|
||||||
|
byte[] data = new byte[40000];
|
||||||
|
Arrays.fill(data, (byte) 42);
|
||||||
|
PacketCustom outgoing = new PacketCustom("PacketTest", 7).writeByteArray(data);
|
||||||
|
if (forceCompression) outgoing.compress();
|
||||||
|
try {
|
||||||
|
for (int serialization = 0; serialization < 3; serialization++) {
|
||||||
|
FMLProxyPacket wire = outgoing.toPacket();
|
||||||
|
try {
|
||||||
|
assertEquals(0x87, wire.payload().getUnsignedByte(0));
|
||||||
|
assertDecoded(wire.payload().retain(), data);
|
||||||
|
} finally {
|
||||||
|
wire.payload().release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
outgoing.getByteBuf().release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsOutgoingPayloadAboveDecodeLimit() {
|
||||||
|
PacketCustom outgoing = new PacketCustom("PacketTest", 7);
|
||||||
|
try {
|
||||||
|
outgoing.getByteBuf().writeZero(MAX_DECOMPRESSED_SIZE + 1);
|
||||||
|
assertThrows(IllegalArgumentException.class, outgoing::toPacket);
|
||||||
|
} finally {
|
||||||
|
outgoing.getByteBuf().release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteBuf compressed(byte[] data) {
|
||||||
|
return compressed(data, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteBuf compressed(byte[] data, byte[] dictionary) {
|
||||||
|
Deflater deflater = new Deflater();
|
||||||
|
try {
|
||||||
|
if (dictionary != null) deflater.setDictionary(dictionary);
|
||||||
|
deflater.setInput(data);
|
||||||
|
deflater.finish();
|
||||||
|
ByteArrayOutputStream compressed = new ByteArrayOutputStream();
|
||||||
|
byte[] scratch = new byte[8192];
|
||||||
|
while (!deflater.finished()) {
|
||||||
|
int count = deflater.deflate(scratch);
|
||||||
|
compressed.write(scratch, 0, count);
|
||||||
|
}
|
||||||
|
return Unpooled.buffer().writeByte(0x87).writeInt(data.length).writeBytes(compressed.toByteArray());
|
||||||
|
} finally {
|
||||||
|
deflater.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertDecoded(ByteBuf payload, byte[] expected) {
|
||||||
|
PacketCustom packet = null;
|
||||||
|
try {
|
||||||
|
packet = new PacketCustom(payload);
|
||||||
|
assertEquals(7, packet.getType());
|
||||||
|
assertEquals(expected.length, packet.getByteBuf().readableBytes());
|
||||||
|
byte[] actual = new byte[expected.length];
|
||||||
|
packet.getByteBuf().readBytes(actual);
|
||||||
|
assertArrayEquals(expected, actual);
|
||||||
|
} finally {
|
||||||
|
if (packet != null && packet.getByteBuf() != payload) packet.getByteBuf().release();
|
||||||
|
payload.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertRejected(ByteBuf payload) {
|
||||||
|
try {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
PacketCustom packet = new PacketCustom(payload);
|
||||||
|
if (packet.getByteBuf() != payload) packet.getByteBuf().release();
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
payload.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package codechicken.lib.render;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CyclicBarrier;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import codechicken.lib.vec.Vector3;
|
||||||
|
|
||||||
|
public class CCRenderStateThreadingTest {
|
||||||
|
|
||||||
|
private static int[] attribIndices() {
|
||||||
|
return new int[] { CCRenderState.normalAttrib().attributeIndex, CCRenderState.colourAttrib().attributeIndex,
|
||||||
|
CCRenderState.lightingAttrib().attributeIndex, CCRenderState.sideAttrib().attributeIndex,
|
||||||
|
CCRenderState.lightCoordAttrib().attributeIndex };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void attributeIndicesStableAcrossThreads() throws Exception {
|
||||||
|
int[] main = attribIndices();
|
||||||
|
assertEquals(5, Arrays.stream(main).distinct().count());
|
||||||
|
|
||||||
|
ExecutorService pool = Executors.newFixedThreadPool(8);
|
||||||
|
try {
|
||||||
|
List<Future<int[]>> futures = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 8; i++) futures.add(pool.submit(CCRenderStateThreadingTest::attribIndices));
|
||||||
|
for (Future<int[]> f : futures) assertArrayEquals(main, f.get(10, TimeUnit.SECONDS));
|
||||||
|
} finally {
|
||||||
|
pool.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void modelBakedOnOneThreadIsReadableOnAnother() throws Exception {
|
||||||
|
ExecutorService bakeThread = Executors.newSingleThreadExecutor();
|
||||||
|
ExecutorService renderThread = Executors.newSingleThreadExecutor();
|
||||||
|
try {
|
||||||
|
CCModel model = bakeThread.submit(() -> {
|
||||||
|
CCModel m = CCModel.quadModel(4);
|
||||||
|
m.verts[0] = new Vertex5(0, 1, 0, 0, 0);
|
||||||
|
m.verts[1] = new Vertex5(0, 1, 1, 0, 1);
|
||||||
|
m.verts[2] = new Vertex5(1, 1, 1, 1, 1);
|
||||||
|
m.verts[3] = new Vertex5(1, 1, 0, 1, 0);
|
||||||
|
return m.computeNormals();
|
||||||
|
}).get(10, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
int side = renderThread.submit(() -> {
|
||||||
|
assertTrue(
|
||||||
|
model.hasAttribute(CCRenderState.normalAttrib()),
|
||||||
|
"normals baked on another thread not visible under this thread's attributeIndex");
|
||||||
|
Vector3[] normals = model.getAttributes(CCRenderState.normalAttrib());
|
||||||
|
assertNotNull(normals);
|
||||||
|
return CCModel.findSide(normals[0]);
|
||||||
|
}).get(10, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
assertEquals(1, side);
|
||||||
|
assertEquals(1, CCModel.findSide(model.getAttributes(CCRenderState.normalAttrib())[0]));
|
||||||
|
} finally {
|
||||||
|
bakeThread.shutdownNow();
|
||||||
|
renderThread.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void concurrentFirstUseKeepsIndicesConsistent() throws Exception {
|
||||||
|
int threads = 16;
|
||||||
|
CyclicBarrier barrier = new CyclicBarrier(threads);
|
||||||
|
ExecutorService pool = Executors.newFixedThreadPool(threads);
|
||||||
|
try {
|
||||||
|
List<Future<int[]>> futures = new ArrayList<>();
|
||||||
|
for (int i = 0; i < threads; i++) futures.add(pool.submit(() -> {
|
||||||
|
barrier.await(10, TimeUnit.SECONDS);
|
||||||
|
return attribIndices();
|
||||||
|
}));
|
||||||
|
int[] expected = attribIndices();
|
||||||
|
for (Future<int[]> f : futures) assertArrayEquals(expected, f.get(10, TimeUnit.SECONDS));
|
||||||
|
} finally {
|
||||||
|
pool.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAttributeReturnsCanonicalForIndex() {
|
||||||
|
int normalIndex = CCRenderState.normalAttrib().attributeIndex;
|
||||||
|
CCRenderState.VertexAttribute<?> canonical = CCRenderState.getAttribute(normalIndex);
|
||||||
|
assertNotNull(canonical);
|
||||||
|
assertEquals(normalIndex, canonical.attributeIndex);
|
||||||
|
assertSame(canonical, CCRenderState.getAttribute(normalIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package codechicken.lib.render;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import net.minecraft.util.IIcon;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class EntityDigIconFXTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsMismatchedIconAndColourCountsBeforeSpawning() {
|
||||||
|
IllegalArgumentException exception = assertThrows(
|
||||||
|
IllegalArgumentException.class,
|
||||||
|
() -> EntityDigIconFX.addBlockDestroyEffects(null, null, new IIcon[1], new int[0], null));
|
||||||
|
|
||||||
|
assertEquals("icons and colours must have the same length", exception.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user