diff --git a/build.gradle b/build.gradle index 58fcd863..04c82f90 100644 --- a/build.gradle +++ b/build.gradle @@ -1,40 +1,38 @@ -buildscript { - repositories { - maven { url = 'https://files.minecraftforge.net/maven' } - maven { url = 'https://repo.spongepowered.org/maven' } - } - dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' - classpath 'org.spongepowered:mixingradle:0.6-SNAPSHOT' - } +import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar +import org.jetbrains.gradle.ext.Gradle + +plugins { + id 'java' + id 'java-library' + id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7' + id 'com.gtnewhorizons.retrofuturagradle' version '1.3.9' + id 'com.matthewprenger.cursegradle' version '1.4.0' } -apply plugin: 'net.minecraftforge.gradle.forge' -apply plugin: 'org.spongepowered.mixin' - -version = "5.6" -group = "mirror.normalasm" -archivesBaseName = "normalasm" +version = project.mod_version +group = project.maven_group +archivesBaseName = project.archives_base_name -sourceCompatibility = targetCompatibility = '1.8' -compileJava { - sourceCompatibility = targetCompatibility = '1.8' +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(8)) + vendor.set(org.gradle.jvm.toolchain.JvmVendorSpec.AZUL) + } + // Generate sources and javadocs jars when building and publishing + withSourcesJar() + // withJavadocJar() } minecraft { - version = "1.12.2-14.23.5.2847" - runDir = "run" - mappings = "stable_39" + mcVersion = '1.12.2' def args = [ + "-ea:${project.group}", '-Dfml.coreMods.load=mirror.normalasm.core.NormalLoadingPlugin', '-Dmixin.hotSwap=true', '-Dmixin.checks.interfaces=true', - '-Dmixin.debug.export=true' + '-Dmixin.debug.export=true' ] - clientJvmArgs.addAll(args) - serverJvmArgs.addAll(args) - useDepAts = true - makeObfSourceJar = false + extraRunJvmArguments.addAll(args) } configurations { @@ -44,112 +42,161 @@ configurations { repositories { jcenter() + maven { + url 'https://repo.spongepowered.org/maven' + } maven { - url "https://maven.cleanroommc.com" + url 'https://maven.cleanroommc.com' } maven { - url "http://chickenbones.net/maven" + url 'http://chickenbones.net/maven' + allowInsecureProtocol = true } maven { - url "http://maven.covers1624.net" + url 'http://maven.covers1624.net' + allowInsecureProtocol = true } maven { - url "https://www.cursemaven.com" + url 'https://www.cursemaven.com' } maven { - url "https://dvs1.progwml6.com/files/maven/" + url 'https://dvs1.progwml6.com/files/maven/' } maven { - url "https://modmaven.k-4u.nl/" + url 'https://modmaven.k-4u.nl/' } maven { - url "https://maven.blamejared.com" + url 'https://maven.blamejared.com' } maven { - url "https://maven.thiakil.com" + url 'https://maven.thiakil.com' } maven { - url "https://repo.codemc.io/repository/maven-public/" + url 'https://repo.codemc.io/repository/maven-public/' } maven { - url "http://maven.tterrag.com" + url 'http://maven.tterrag.com' + allowInsecureProtocol = true } // maven { - // url = "http://maven.bluexin.be/repository/snapshots/" + // url = 'http://maven.bluexin.be/repository/snapshots/' // } } dependencies { - embed "me.nallar.whocalled:WhoCalled:1.1" - deobfProvided "com.enderio.core:EnderCore:1.12.2-+" - deobfProvided ("com.enderio:EnderIO:1.12.2-+") { + embed 'me.nallar.whocalled:WhoCalled:1.1' + implementation 'zone.rong:mixinbooter:7.1' + implementation files('./etc/spark-forge-deobf.jar') + + compileOnly 'com.enderio.core:EnderCore:1.12.2-+' + compileOnly ('com.enderio:EnderIO:1.12.2-+') { + transitive = false + } + compileOnly 'codechicken:ChickenASM:1.12-1.0.2.9' + compileOnly 'epicsquid.mysticallib:mysticallib:1.12.2-+' + compileOnly 'mezz.jei:jei_1.12.2:4.15.0.293' + compileOnly 'slimeknights.mantle:Mantle:1.12-1.3.3.55' + compileOnly 'slimeknights:TConstruct:1.12.2-2.13.0.183' + compileOnly 'betterwithmods:BetterWithMods:1.12-2.3.20-1030' + + compileOnly rfg.deobf('codechicken:CodeChickenLib:1.12.2-3.2.3.358:universal') + compileOnly rfg.deobf('com.azanor.baubles:Baubles:1.12-1.5.2') + compileOnly rfg.deobf('blusunrize:ImmersiveEngineering:0.12-92-+') + + compileOnly rfg.deobf('curse.maven:astral-sorcery-241721:3044416') + compileOnly rfg.deobf('curse.maven:tfcraft-302973:3268988') + compileOnly rfg.deobf('curse.maven:foamfix-optimization-mod-278494:3327893') + compileOnly rfg.deobf('curse.maven:electroblobs-wizardry-265642:3189062') + // deobfCompile 'curse.maven:qmd-362056:3474533' + // deobfCompile 'cofh:CoFHCore:1.12.2-+:universal' + // compile 'com.teamwizardry.librarianlib:librarianlib-1.12:4.0-SNAPSHOT:deobf' + compileOnly rfg.deobf('curse.maven:extra-utilities-225561:2678374') + compileOnly rfg.deobf('curse.maven:gottschcore-272450:3748293') + compileOnly rfg.deobf('curse.maven:treasure2-289760:3758107') + compileOnly rfg.deobf('curse.maven:time-speed-mod-221053:2991593') + compileOnly rfg.deobf('curse.maven:gregtech-ce-unofficial-557242:3745499') + + api ('org.spongepowered:mixin:0.8.3') { + transitive = false + } + annotationProcessor 'org.ow2.asm:asm-debug-all:5.2' + annotationProcessor 'com.google.guava:guava:24.1.1-jre' + annotationProcessor 'com.google.code.gson:gson:2.8.6' + annotationProcessor ('org.spongepowered:mixin:0.8.3') { transitive = false } - compile "codechicken:ChickenASM:1.12-1.0.2.9" - provided "epicsquid.mysticallib:mysticallib:1.12.2-+" - compile "mezz.jei:jei_1.12.2:4.15.0.293" - compile "zone.rong:mixinbooter:4.2" - // compile files("./etc/spark-forge-deobf.jar", "./etc/preview_OptiFine_1.12.2_HD_U_G6_pre1-deobf.jar") - compile files("./etc/spark-forge-deobf.jar") - - deobfCompile 'slimeknights.mantle:Mantle:1.12-1.3.3.55+' - deobfCompile 'slimeknights:TConstruct:1.12.2-2.13.0.183+' - - deobfProvided "betterwithmods:BetterWithMods:1.12-2.3.20-1030" - - deobfCompile "codechicken:CodeChickenLib:1.12.2-3.2.3.358:universal" - deobfProvided "com.azanor.baubles:Baubles:1.12-1.5.2" - deobfProvided "blusunrize:ImmersiveEngineering:0.12-92-+" - deobfProvided "curse.maven:astral-sorcery-241721:3044416" - deobfProvided "curse.maven:tfcraft-302973:3268988" - deobfProvided "curse.maven:foamfix-optimization-mod-278494:3327893" - deobfProvided "curse.maven:electroblobs-wizardry-265642:3189062" - // deobfCompile "curse.maven:qmd-362056:3474533" - // deobfCompile "cofh:CoFHCore:1.12.2-+:universal" - // compile "com.teamwizardry.librarianlib:librarianlib-1.12:4.0-SNAPSHOT:deobf" - deobfProvided "curse.maven:extra-utilities-225561:2678374" - deobfProvided "curse.maven:gottschcore-272450:3748293" - deobfProvided "curse.maven:treasure2-289760:3758107" - deobfProvided "curse.maven:time-speed-mod-221053:2991593" - deobfCompile "curse.maven:gregtech-ce-unofficial-557242:3745499" } -processResources { - // this will ensure that this task is redone when the versions change. - inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version - - // replace stuff in mcmod.info, nothing else - from(sourceSets.main.resources.srcDirs) { - include 'mcmod.info' +def mixinConfigRefMap = 'mixins.' + project.archives_base_name + '.refmap.json' +def mixinTmpDir = buildDir.path + File.separator + 'tmp' + File.separator + 'mixins' +def refMap = "${mixinTmpDir}" + File.separator + mixinConfigRefMap +def mixinSrg = "${mixinTmpDir}" + File.separator + 'mixins.srg' - // replace version and mcversion - expand 'version':project.version, 'mcversion':project.minecraft.version - } +tasks.named('reobfJar', ReobfuscatedJar).configure { + extraSrgFiles.from(mixinSrg) +} - // copy everything else except the mcmod.info - from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' +tasks.named('compileJava', JavaCompile).configure { + doFirst { + new File(mixinTmpDir).mkdirs() } + options.compilerArgs += ["-AreobfSrgFile=${tasks.reobfJar.srg.get().asFile}", "-AoutSrgFile=${mixinSrg}", "-AoutRefMapFile=${refMap}",] } -sourceSets { - main { - ext.refMap = "mixins.normalasm.refmap.json" +processResources { + inputs.property 'version', project.version + inputs.property 'mcversion', project.minecraft.version + + filesMatching('mcmod.info') { fcd -> + include 'mcmod.info' + // replace version and mcversion + fcd.expand ('version': project.version, 'mcversion': project.minecraft.version) } + + from refMap + dependsOn 'compileJava' } jar { - from (configurations.embed.collect { it.isDirectory() ? it : zipTree(it) }) { - exclude 'LICENSE.txt', 'META-INF/MANIFSET.MF', 'META-INF/maven/**', 'META-INF/*.RSA', 'META-INF/*.SF' + from provider { + configurations.embed.collect {it.isDirectory() ? it : zipTree(it)} } manifest { attributes([ - "FMLCorePluginContainsFMLMod": true, - "FMLCorePlugin": 'mirror.normalasm.core.NormalLoadingPlugin', - "ForceLoadAsMod": project.gradle.startParameter.taskNames[0] == "build", - "TweakClass": 'org.spongepowered.asm.launch.MixinTweaker', - "FMLAT": "normalasm_at.cfg" + 'FMLCorePluginContainsFMLMod': true, + 'FMLCorePlugin': 'mirror.normalasm.core.NormalLoadingPlugin', + 'ForceLoadAsMod': project.gradle.startParameter.taskNames[0] == 'build', + 'FMLAT': 'normalasm_at.cfg' ]) } } + +idea { + module { + inheritOutputDirs = true + } + project { + settings { + runConfigurations { + '1. Run Client'(Gradle) { + taskNames = ['runClient'] + } + '2. Run Server'(Gradle) { + taskNames = ['runServer'] + } + '3. Run Obfuscated Client'(Gradle) { + taskNames = ['runObfClient'] + } + '4. Run Obfuscated Server'(Gradle) { + taskNames = ['runObfServer'] + } + } + compiler.javac { + afterEvaluate { + javacAdditionalOptions = '-encoding utf8' + moduleJavacAdditionalOptions = [(project.name + '.main'): tasks.compileJava.options.compilerArgs.collect { '"' + it + '"' }.join(' ')] + } + } + } + } +} diff --git a/gradle.properties b/gradle.properties index e9b9fd5a..7af215a3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,6 @@ -# Sets default memory used for gradle commands. Can be overridden by user or command line properties. -# This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs=-Xmx3G +org.gradle.jvmargs = -Xmx3G + +# Mod Information +mod_version = 5.23 +maven_group = mirror.normalasm +archives_base_name = normalasm diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6b071a78..d8d24753 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..3f05c79d --- /dev/null +++ b/settings.gradle @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + maven { + // RetroFuturaGradle + name = 'GTNH Maven' + url = uri 'http://jenkins.usrv.eu:8081/nexus/content/groups/public/' + allowInsecureProtocol = true + mavenContent { + includeGroup 'com.gtnewhorizons' + includeGroup 'com.gtnewhorizons.retrofuturagradle' + } + } + gradlePluginPortal() + mavenCentral() + mavenLocal() + } +} + +plugins { + // Automatic toolchain provisioning + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0' +} + +rootProject.name = 'NormalASM' diff --git a/src/main/java/mirror/normalasm/NormalReflector.java b/src/main/java/mirror/normalasm/NormalReflector.java index 3a7e06e9..803dbc1d 100644 --- a/src/main/java/mirror/normalasm/NormalReflector.java +++ b/src/main/java/mirror/normalasm/NormalReflector.java @@ -214,6 +214,13 @@ public static boolean doesTweakExist(String tweakName) { return ((List) Launch.blackboard.get("TweakClasses")).contains(tweakName); } + public static Class getNullableClass(String className) { + try { + return Class.forName(className); + } catch (ClassNotFoundException ignored) { } + return null; + } + public static Optional> getClass(String className) { try { return Optional.of(Class.forName(className)); diff --git a/src/main/java/mirror/normalasm/api/datastructures/NormalTagMap.java b/src/main/java/mirror/normalasm/api/datastructures/NormalTagMap.java new file mode 100644 index 00000000..3982b555 --- /dev/null +++ b/src/main/java/mirror/normalasm/api/datastructures/NormalTagMap.java @@ -0,0 +1,132 @@ +package mirror.normalasm.api.datastructures; + +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mirror.normalasm.api.datastructures.canonical.AutoCanonizingArrayMap; +import mirror.normalasm.api.datastructures.canonical.AutoCanonizingHashMap; +import mirror.normalasm.config.NormalConfig; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +public class NormalTagMap implements Map { + + private Map map; + private final int threshold; + + public NormalTagMap() { + this(NormalConfig.instance.optimizeNBTTagCompoundMapThreshold, NormalConfig.instance.nbtBackingMapStringCanonicalization, NormalConfig.instance.optimizeNBTTagCompoundBackingMap); + } + + public NormalTagMap(int threshold, boolean canonicalizeString, boolean optimizeMap) { + this.threshold = optimizeMap ? threshold : -1; + if (canonicalizeString) { + this.map = optimizeMap ? new AutoCanonizingArrayMap<>() : new AutoCanonizingHashMap<>(); + } else { + this.map = optimizeMap ? new Object2ObjectArrayMap<>() : new Object2ObjectOpenHashMap<>(); + } + } + + @Override + public int size() { + return this.map.size(); + } + + @Override + public boolean isEmpty() { + return this.map.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return this.map.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return this.map.containsValue(value); + } + + @Override + public V get(Object key) { + return this.map.get(key); + } + + @Override + public V put(K key, V value) { + if (this.size() == this.threshold) { + this.map = this.map instanceof AutoCanonizingArrayMap ? new AutoCanonizingHashMap<>(this.map) : new Object2ObjectOpenHashMap<>(this.map); + } + return this.map.put(key, value); + } + + @Override + public V remove(Object key) { + return this.map.remove(key); + } + + @Override + public void putAll(Map m) { + m.forEach(this::put); + } + + @Override + public void clear() { + if (this.threshold != -1) { + if (this.map instanceof AutoCanonizingHashMap) { + this.map = new AutoCanonizingArrayMap<>(); + } else if (this.map instanceof Object2ObjectOpenHashMap) { + this.map = new Object2ObjectArrayMap<>(); + } else { + this.map.clear(); + } + } else { + this.map.clear(); + } + } + + @Nonnull + @Override + public Set keySet() { + return this.map.keySet(); + } + + @Nonnull + @Override + public Collection values() { + return this.map.values(); + } + + @Override + public Set> entrySet() { + return this.map.entrySet(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Map)) { + return false; + } + Map o = (Map) obj; + if (o.size() != this.size()) { + return false; + } + return this.entrySet().containsAll(o.entrySet()); + } + + @Override + public int hashCode() { + return this.map.hashCode(); + } + + @Override + public String toString() { + return this.map.toString(); + } + +} \ No newline at end of file diff --git a/src/main/java/mirror/normalasm/api/datastructures/canonical/AutoCanonizingHashMap.java b/src/main/java/mirror/normalasm/api/datastructures/canonical/AutoCanonizingHashMap.java new file mode 100644 index 00000000..675c3644 --- /dev/null +++ b/src/main/java/mirror/normalasm/api/datastructures/canonical/AutoCanonizingHashMap.java @@ -0,0 +1,28 @@ +package mirror.normalasm.api.datastructures.canonical; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mirror.normalasm.api.NormalStringPool; + +import java.util.Map; + +public class AutoCanonizingHashMap extends Object2ObjectOpenHashMap { + + public AutoCanonizingHashMap() { + super(); + } + + public AutoCanonizingHashMap(Map map) { + super(map); + } + + @Override + public V put(K k, V v) { + if (k instanceof String) { + k = (K) NormalStringPool.canonicalize((String) k); + } + if (v instanceof String) { + v = (V) NormalStringPool.canonicalize((String) v); + } + return super.put(k, v); + } +} diff --git a/src/main/java/mirror/normalasm/bakedquad/SupportingBakedQuad.java b/src/main/java/mirror/normalasm/bakedquad/SupportingBakedQuad.java index 4febebcf..3a3db9a0 100644 --- a/src/main/java/mirror/normalasm/bakedquad/SupportingBakedQuad.java +++ b/src/main/java/mirror/normalasm/bakedquad/SupportingBakedQuad.java @@ -33,7 +33,7 @@ public SupportingBakedQuad(int[] vertexDataIn, int tintIndexIn, EnumFacing faceI @Override public EnumFacing getFace() { - return face; + return face != null ? face : EnumFacing.DOWN; } @Override diff --git a/src/main/java/mirror/normalasm/client/mcfixes/SkinDataReleaser.java b/src/main/java/mirror/normalasm/client/mcfixes/mixins/mc186052/MinecraftMixin.java similarity index 55% rename from src/main/java/mirror/normalasm/client/mcfixes/SkinDataReleaser.java rename to src/main/java/mirror/normalasm/client/mcfixes/mixins/mc186052/MinecraftMixin.java index b712ed9c..1ef6ee23 100644 --- a/src/main/java/mirror/normalasm/client/mcfixes/SkinDataReleaser.java +++ b/src/main/java/mirror/normalasm/client/mcfixes/mixins/mc186052/MinecraftMixin.java @@ -1,24 +1,31 @@ -package mirror.normalasm.client.mcfixes; +package mirror.normalasm.client.mcfixes.mixins.mc186052; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.ThreadDownloadImageData; import net.minecraft.client.renderer.texture.ITextureObject; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.network.FMLNetworkEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import mirror.normalasm.NormalLogger; -import mirror.normalasm.common.internal.mixins.TextureManagerAccessor; +import mirror.normalasm.config.NormalConfig; +import javax.annotation.Nullable; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; -public class SkinDataReleaser { +@Mixin(Minecraft.class) +public class MinecraftMixin { - @SubscribeEvent - public static void onClientDisconnect(FMLNetworkEvent.ClientDisconnectionFromServerEvent event) { - Minecraft.getMinecraft().addScheduledTask(() -> { - Map textureObjects = ((TextureManagerAccessor) Minecraft.getMinecraft().getTextureManager()).getMapTextureObjects(); + @Inject(method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/client/FMLClientHandler;handleClientWorldClosing(Lnet/minecraft/client/multiplayer/WorldClient;)V", + remap = false)) + private void injectLoadWorld(@Nullable WorldClient worldClientIn, String loadingMessage, CallbackInfo ci) { + if (NormalConfig.instance.fixMC186052) { + Map textureObjects = ((TextureManagerExpansion) Minecraft.getMinecraft().getTextureManager()).getMapTextureObjects(); if (textureObjects != null) { int count = 0; Iterator> entryIter = textureObjects.entrySet().iterator(); @@ -35,7 +42,7 @@ public static void onClientDisconnect(FMLNetworkEvent.ClientDisconnectionFromSer } NormalLogger.instance.info("Released {} skin textures", count); } - }); + } } -} +} \ No newline at end of file diff --git a/src/main/java/mirror/normalasm/client/mcfixes/mixins/mc186052/TextureManagerExpansion.java b/src/main/java/mirror/normalasm/client/mcfixes/mixins/mc186052/TextureManagerExpansion.java new file mode 100644 index 00000000..706cbb8c --- /dev/null +++ b/src/main/java/mirror/normalasm/client/mcfixes/mixins/mc186052/TextureManagerExpansion.java @@ -0,0 +1,17 @@ +package mirror.normalasm.client.mcfixes.mixins.mc186052; + +import net.minecraft.client.renderer.texture.ITextureObject; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(TextureManager.class) +public interface TextureManagerExpansion { + + @Accessor(value = "mapTextureObjects") + Map getMapTextureObjects(); + +} diff --git a/src/main/java/mirror/normalasm/client/searchtree/mixins/vanilla/MinecraftMixin.java b/src/main/java/mirror/normalasm/client/searchtree/mixins/vanilla/MinecraftMixin.java index 2fd8d5c0..c671dab5 100644 --- a/src/main/java/mirror/normalasm/client/searchtree/mixins/vanilla/MinecraftMixin.java +++ b/src/main/java/mirror/normalasm/client/searchtree/mixins/vanilla/MinecraftMixin.java @@ -9,9 +9,12 @@ import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.common.Loader; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import mirror.normalasm.client.searchtree.JEIRedirectSearchTree; +import mirror.normalasm.config.NormalConfig; import java.util.Collections; import java.util.Objects; @@ -22,36 +25,35 @@ public class MinecraftMixin { @Shadow private SearchTreeManager searchTreeManager; - /** - * @author Rongmario - * @reason Use JEIRedirectSearchTree - */ - @Overwrite - public void populateSearchTreeManager() { - final SearchTree recipeSearchTree = new SearchTree<>( - rl -> () -> rl.getRecipes().stream() - .flatMap((r) -> r.getRecipeOutput().getTooltip(null, TooltipFlags.NORMAL).stream()) - .map(TextFormatting::getTextWithoutFormattingCodes) - .filter(Objects::nonNull) - .map(String::trim) - .filter(tooltip -> !tooltip.isEmpty()) - .iterator(), - rl -> () -> rl.getRecipes().stream() - .map((r) -> r.getRecipeOutput().getItem().getRegistryName()) - .iterator() - ); - final SearchTree itemSearchTree = Loader.isModLoaded("jei") ? - new JEIRedirectSearchTree() : - new SearchTree<>(stack -> - stack.getTooltip(null, TooltipFlags.NORMAL) - .stream() + @Inject(method = "populateSearchTreeManager", at = @At("HEAD"), cancellable = true) + private void redirectToJeiSearchTree(CallbackInfo ci) { + if (NormalConfig.instance.replaceSearchTreeWithJEISearching && Loader.isModLoaded("jei")) { + final SearchTree recipeSearchTree = new SearchTree<>( + rl -> () -> rl.getRecipes().stream() + .flatMap((r) -> r.getRecipeOutput().getTooltip(null, TooltipFlags.NORMAL).stream()) .map(TextFormatting::getTextWithoutFormattingCodes) + .filter(Objects::nonNull) .map(String::trim) .filter(tooltip -> !tooltip.isEmpty()) - .collect(Collectors.toList()), - stack -> Collections.singleton(stack.getItem().getRegistryName())); - this.searchTreeManager.register(SearchTreeManager.RECIPES, recipeSearchTree); - this.searchTreeManager.register(SearchTreeManager.ITEMS, itemSearchTree); + .iterator(), + rl -> () -> rl.getRecipes().stream() + .map((r) -> r.getRecipeOutput().getItem().getRegistryName()) + .iterator() + ); + final SearchTree itemSearchTree = Loader.isModLoaded("jei") ? + new JEIRedirectSearchTree() : + new SearchTree<>(stack -> + stack.getTooltip(null, TooltipFlags.NORMAL) + .stream() + .map(TextFormatting::getTextWithoutFormattingCodes) + .map(String::trim) + .filter(tooltip -> !tooltip.isEmpty()) + .collect(Collectors.toList()), + stack -> Collections.singleton(stack.getItem().getRegistryName())); + this.searchTreeManager.register(SearchTreeManager.RECIPES, recipeSearchTree); + this.searchTreeManager.register(SearchTreeManager.ITEMS, itemSearchTree); + ci.cancel(); + } } } diff --git a/src/main/java/mirror/normalasm/client/sprite/FramesTextureData.java b/src/main/java/mirror/normalasm/client/sprite/FramesTextureData.java index 7d1fbcfe..03cab184 100644 --- a/src/main/java/mirror/normalasm/client/sprite/FramesTextureData.java +++ b/src/main/java/mirror/normalasm/client/sprite/FramesTextureData.java @@ -1,92 +1,181 @@ package mirror.normalasm.client.sprite; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.client.resources.IReloadableResourceManager; import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResourceManager; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.ColorHandlerEvent; +import net.minecraftforge.client.resource.ISelectiveResourceReloadListener; +import net.minecraftforge.client.resource.VanillaResourceType; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import mirror.normalasm.NormalLogger; -import mirror.normalasm.proxy.ClientProxy; +import mirror.normalasm.NormalReflector; +import mirror.normalasm.common.internal.mixins.TextureMapAccessor; import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; public class FramesTextureData extends ArrayList { - private static final Set scheduledToReleaseCache = Collections.newSetFromMap(new WeakHashMap<>()); + private static final Class FOAMFIX_SPRITE = NormalReflector.getNullableClass("pl.asie.foamfix.client.FastTextureAtlasSprite"); + private static final int INACTIVITY_THRESHOLD = 20; + + private static boolean canReload = true; + + private static final Set tickingSpritesSet = new ReferenceLinkedOpenHashSet<>(); + + @SubscribeEvent + public static void registerEvictionListener(ColorHandlerEvent.Block event) { + ((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener((ISelectiveResourceReloadListener) (manager, predicate) -> { + if (predicate.test(VanillaResourceType.MODELS)) { + canReload = false; + int count = 0; + Set> skippedSpriteClasses = new ObjectOpenHashSet<>(); + try { + synchronized (tickingSpritesSet) { + tickingSpritesSet.clear(); + } + for (TextureAtlasSprite sprite : ((TextureMapAccessor) Minecraft.getMinecraft().getTextureMapBlocks()).getMapRegisteredSprites().values()) { + if (!sprite.hasAnimationMetadata()) { + if (sprite.getClass() == FOAMFIX_SPRITE || sprite.getClass() == TextureAtlasSprite.class) { + count++; + sprite.setFramesTextureData(new FramesTextureData(sprite)); + } else { + skippedSpriteClasses.add(sprite.getClass()); + } + } + } + } catch (Throwable t) { + t.printStackTrace(); + } + NormalLogger.instance.info("Evicted {} sprites' frame texture data", count); + NormalLogger.instance.debug("While evicting sprites' frame texture data, the following classes were skipped: [{}]", skippedSpriteClasses.stream().map(Class::getName).collect(Collectors.joining(", "))); + canReload = true; + } + }); + } @SubscribeEvent public static void onClientTick(TickEvent.ClientTickEvent event) { - if (event.phase == TickEvent.Phase.END && !FramesTextureData.scheduledToReleaseCache.isEmpty()) { - for (Iterator iter = scheduledToReleaseCache.iterator(); iter.hasNext();) { - TextureAtlasSprite sprite = iter.next(); - if (sprite != null) { - try { - sprite.clearFramesTextureData(); - } catch (NullPointerException e) { - NormalLogger.instance.error("NullPointerException: Trying to clear {}'s FramesTextureData but unable to!", sprite.getIconName()); + if (event.phase == TickEvent.Phase.END) { + List toTick; + synchronized (tickingSpritesSet) { + toTick = new ArrayList<>(tickingSpritesSet); + } + for(FramesTextureData data : toTick) { + if(data.tick()) { + synchronized (tickingSpritesSet) { + tickingSpritesSet.remove(data); } } - iter.remove(); } } } private final TextureAtlasSprite sprite; + private int ticksInactive; + public FramesTextureData(TextureAtlasSprite sprite) { super(); this.sprite = sprite; + this.ticksInactive = INACTIVITY_THRESHOLD + 1; + } + + public boolean tick() { + synchronized (this) { + this.ticksInactive++; + if (this.ticksInactive == INACTIVITY_THRESHOLD) { + this.clear(); + return true; + } + return false; + } + } + + private void markActive() { + this.ticksInactive = 0; + synchronized (tickingSpritesSet) { + tickingSpritesSet.add(this); + } } @Override public int[][] get(int index) { - if (ClientProxy.canReload && super.isEmpty()) { - load(); - Minecraft.getMinecraft().addScheduledTask(() -> scheduledToReleaseCache.add(sprite)); + synchronized (this) { + if (canReload && super.isEmpty()) { + load(); + } + markActive(); + return super.get(index); } - return super.get(index); } @Override public int size() { - if (ClientProxy.canReload && super.isEmpty()) { - load(); - Minecraft.getMinecraft().addScheduledTask(() -> scheduledToReleaseCache.add(sprite)); + synchronized (this) { + if (canReload && super.isEmpty()) { + load(); + } + markActive(); + return super.size(); } - return super.size(); } @Override public boolean isEmpty() { - if (ClientProxy.canReload && super.isEmpty()) { - load(); - Minecraft.getMinecraft().addScheduledTask(() -> scheduledToReleaseCache.add(sprite)); + synchronized (this) { + if (canReload && super.isEmpty()) { + load(); + } + markActive(); + return super.isEmpty(); } - return super.isEmpty(); } @Override public void clear() { - super.clear(); - trimToSize(); + synchronized (this) { + super.clear(); + trimToSize(); + } } private void load() { - ResourceLocation location = getLocation(); - IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager(); - TextureMap textureMap = Minecraft.getMinecraft().getTextureMapBlocks(); - if (sprite.hasCustomLoader(resourceManager, location)) { - sprite.load(resourceManager, location, rl -> textureMap.getAtlasSprite(rl.toString())); - } else { - try (IResource resource = resourceManager.getResource(location)) { - sprite.loadSpriteFrames(resource, 1); - } catch (IOException e) { - e.printStackTrace(); + // Prevent recursive loads + boolean oldReload = canReload; + canReload = false; + try { + ResourceLocation location = getLocation(); + IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager(); + TextureMap textureMap = Minecraft.getMinecraft().getTextureMapBlocks(); + if (sprite.hasCustomLoader(resourceManager, location)) { + sprite.load(resourceManager, location, rl -> textureMap.getAtlasSprite(rl.toString())); + } else { + int mipLevels = Minecraft.getMinecraft().gameSettings.mipmapLevels; + try (IResource resource = resourceManager.getResource(location)) { + sprite.loadSpriteFrames(resource, mipLevels + 1); + } catch (IOException e) { + e.printStackTrace(); + } + /* generate mipmaps, as loadSpriteFrames doesn't actually fill them in */ + for (int i = 0; i < this.size(); i++) { + int[][] aint = this.get(i); + if (aint != null) { + this.set(i, TextureUtil.generateMipmapData(mipLevels, sprite.getIconWidth(), aint)); + } + } } + } finally { + canReload = oldReload; } } diff --git a/src/main/java/mirror/normalasm/client/sprite/ondemand/IBufferPrimerConfigurator.java b/src/main/java/mirror/normalasm/client/sprite/ondemand/IBufferPrimerConfigurator.java index 40c871d2..5ef89f55 100644 --- a/src/main/java/mirror/normalasm/client/sprite/ondemand/IBufferPrimerConfigurator.java +++ b/src/main/java/mirror/normalasm/client/sprite/ondemand/IBufferPrimerConfigurator.java @@ -4,4 +4,6 @@ public interface IBufferPrimerConfigurator { void setPrimer(IAnimatedSpritePrimer primer); + void hookTexture(float u, float v); + } diff --git a/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/BufferBuilderMixin.java b/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/BufferBuilderMixin.java index 7254da45..321ad58b 100644 --- a/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/BufferBuilderMixin.java +++ b/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/BufferBuilderMixin.java @@ -51,20 +51,7 @@ public BufferBuilder tex(double u, double v) { float fv = (float) v; this.byteBuffer.putFloat(i, fu); this.byteBuffer.putFloat(i + 4, fv); - if (primer != null && drawMode == GL11.GL_QUADS && IAnimatedSpritePrimer.PRIMED.get()) { - if (++vertexCountOfQuad == 4) { - vertexCountOfQuad = 0; - primer.addAnimatedSprite(minUOfQuad, minVOfQuad); - minUOfQuad = Float.MAX_VALUE; - minVOfQuad = Float.MAX_VALUE; - } - if (minUOfQuad > fu) { - minUOfQuad = fu; - } - if (minVOfQuad > fv) { - minVOfQuad = fv; - } - } + hookTexture(fu, fv); break; case UINT: case INT: @@ -103,4 +90,21 @@ public void finishDrawing() { } } + @Override + public void hookTexture(float fu, float fv) { + if (primer != null && drawMode == GL11.GL_QUADS && IAnimatedSpritePrimer.PRIMED.get()) { + if (++vertexCountOfQuad == 4) { + vertexCountOfQuad = 0; + primer.addAnimatedSprite(minUOfQuad, minVOfQuad); + minUOfQuad = Float.MAX_VALUE; + minVOfQuad = Float.MAX_VALUE; + } + if (minUOfQuad > fu) { + minUOfQuad = fu; + } + if (minVOfQuad > fv) { + minVOfQuad = fv; + } + } + } } diff --git a/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/TextureMapMixin.java b/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/TextureMapMixin.java index f3ca2271..fb9453b8 100644 --- a/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/TextureMapMixin.java +++ b/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/TextureMapMixin.java @@ -1,6 +1,6 @@ package mirror.normalasm.client.sprite.ondemand.mixins; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; @@ -18,10 +18,10 @@ @Mixin(TextureMap.class) public abstract class TextureMapMixin extends AbstractTexture implements IAnimatedSpritePrimer { - @Shadow @Final public Map mapUploadedSprites; + @Shadow @Final private List listAnimatedSprites; @Unique private final FloorUVTree animatedSpritesUVRanges = new FloorUVTree(); - @Unique private final Set queuedUVCoords = new ObjectOpenHashSet<>(8); + @Unique private final Set queuedUVCoords = new ObjectLinkedOpenHashSet<>(8); @Override public void registerUVRanges(float minU, float minV, TextureAtlasSprite sprite) { @@ -49,7 +49,7 @@ private void afterInit(String basePathIn, ITextureMapPopulator iconCreatorIn, bo private boolean populateUVRanges(List list, Object object) { TextureAtlasSprite sprite = (TextureAtlasSprite) object; registerUVRanges(sprite.getMinU(), sprite.getMinV(), sprite); - return false; + return listAnimatedSprites.add(sprite); } /** @@ -68,18 +68,17 @@ public void updateAnimations() { } // Mark all captured sprites - Iterator iter = this.queuedUVCoords.iterator(); - while (iter.hasNext()) { - TextureAtlasSprite sprite = this.animatedSpritesUVRanges.getNearestFloorSprite(iter.next()); + for (FloorUV queuedUVCoord : this.queuedUVCoords) { + TextureAtlasSprite sprite = this.animatedSpritesUVRanges.getNearestFloorSprite(queuedUVCoord); if (sprite != null && sprite.hasAnimationMetadata()) { // Only activate animated sprites ((IAnimatedSpriteActivator) sprite).setActive(true); } - iter.remove(); // Pop off queue } + this.queuedUVCoords.clear(); GlStateManager.bindTexture(this.getGlTextureId()); // Bind TextureMap texture - for (TextureAtlasSprite sprite : this.mapUploadedSprites.values()) { + for (TextureAtlasSprite sprite : this.listAnimatedSprites) { if (((IAnimatedSpriteActivator) sprite).isActive()) { sprite.updateAnimation(); // Update Animation ((IAnimatedSpriteActivator) sprite).setActive(false); // Unactivated diff --git a/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/VertexLighterFlatMixin.java b/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/VertexLighterFlatMixin.java index e9a39322..727ed29c 100644 --- a/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/VertexLighterFlatMixin.java +++ b/src/main/java/mirror/normalasm/client/sprite/ondemand/mixins/VertexLighterFlatMixin.java @@ -10,6 +10,8 @@ import mirror.normalasm.client.sprite.ondemand.ICompiledChunkExpander; import mirror.normalasm.client.sprite.ondemand.IVertexLighterExpander; +import java.util.Objects; + @Mixin(VertexLighterFlat.class) public abstract class VertexLighterFlatMixin extends QuadGatheringTransformer implements IVertexLighterExpander { @@ -23,7 +25,7 @@ public Object primeForDispatch() { @Override public void setTexture(TextureAtlasSprite texture) { - if (this.primedForDispatch && texture.hasAnimationMetadata()) { + if (this.primedForDispatch && Objects.nonNull(texture) && texture.hasAnimationMetadata()) { CompiledChunk chunk = IAnimatedSpritePrimer.CURRENT_COMPILED_CHUNK.get(); if (chunk != null) { ((ICompiledChunkExpander) chunk).resolve(texture); diff --git a/src/main/java/mirror/normalasm/common/crashes/CrashUtils.java b/src/main/java/mirror/normalasm/common/crashes/CrashUtils.java index 3180ef98..7d8543e6 100644 --- a/src/main/java/mirror/normalasm/common/crashes/CrashUtils.java +++ b/src/main/java/mirror/normalasm/common/crashes/CrashUtils.java @@ -12,6 +12,8 @@ public final class CrashUtils { + public static final ThreadLocal WRITING_DETAIL = ThreadLocal.withInitial(() -> false); + public static void crash(CrashReport report) { throw new ReportedException(report); } diff --git a/src/main/java/mirror/normalasm/common/crashes/mixins/CrashReportMixin.java b/src/main/java/mirror/normalasm/common/crashes/mixins/CrashReportMixin.java index 9e8f7ca8..07c14e75 100644 --- a/src/main/java/mirror/normalasm/common/crashes/mixins/CrashReportMixin.java +++ b/src/main/java/mirror/normalasm/common/crashes/mixins/CrashReportMixin.java @@ -33,6 +33,8 @@ public abstract class CrashReportMixin implements ICrashReportSuspectGetter { throw new AssertionError(); } + @Shadow public abstract String getCauseStackTraceOrString(); + @Unique private Set suspectedMods; @Override @@ -84,7 +86,7 @@ public String getCompleteReport() { .append("Time: ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(new Date())).append("\n") .append("Description: ").append(description) .append("\n\n") - .append(stacktraceToString(cause).replace("\t", " ")) + .append(this.getCauseStackTraceOrString()) .append("\n\nA detailed walkthrough of the error, its code path and all known details is as follows:\n"); for (int i = 0; i < 87; i++) { builder.append("-"); @@ -94,13 +96,6 @@ public String getCompleteReport() { return builder.toString().replace("\t", " "); } - private static String stacktraceToString(Throwable cause) { - StringWriter writer = new StringWriter(); - cause.printStackTrace(new PrintWriter(writer)); - return writer.toString(); - } - - /** * @author VanillFix * @reason Improve report formatting, add blame comment diff --git a/src/main/java/mirror/normalasm/common/crashes/mixins/EntityMixin.java b/src/main/java/mirror/normalasm/common/crashes/mixins/EntityMixin.java index 44e3b939..57b83b61 100644 --- a/src/main/java/mirror/normalasm/common/crashes/mixins/EntityMixin.java +++ b/src/main/java/mirror/normalasm/common/crashes/mixins/EntityMixin.java @@ -7,13 +7,18 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import mirror.normalasm.common.crashes.CrashUtils; @Mixin(Entity.class) public class EntityMixin { @Inject(method = "addEntityCrashInfo", at = @At("TAIL")) private void onAddEntityCrashInfo(CrashReportCategory category, CallbackInfo ci) { - category.addDetail("Entity NBT", () -> ((Entity) (Object) this).writeToNBT(new NBTTagCompound()).toString()); + if (!CrashUtils.WRITING_DETAIL.get()) { + CrashUtils.WRITING_DETAIL.set(true); + category.addDetail("Entity NBT", () -> ((Entity) (Object) this).writeToNBT(new NBTTagCompound()).toString()); + CrashUtils.WRITING_DETAIL.set(false); + } } } diff --git a/src/main/java/mirror/normalasm/common/crashes/mixins/TileEntityMixin.java b/src/main/java/mirror/normalasm/common/crashes/mixins/TileEntityMixin.java index 20a3ba17..e364098e 100644 --- a/src/main/java/mirror/normalasm/common/crashes/mixins/TileEntityMixin.java +++ b/src/main/java/mirror/normalasm/common/crashes/mixins/TileEntityMixin.java @@ -7,14 +7,18 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import mirror.normalasm.common.crashes.CrashUtils; @Mixin(TileEntity.class) public class TileEntityMixin { - // "Block Entity" to stay consistent with vanilla strings @Inject(method = "addInfoToCrashReport", at = @At("TAIL")) private void onAddEntityCrashInfo(CrashReportCategory category, CallbackInfo ci) { - category.addDetail("Block Entity NBT", () -> ((TileEntity) (Object) this).writeToNBT(new NBTTagCompound()).toString()); + if (!CrashUtils.WRITING_DETAIL.get()) { + CrashUtils.WRITING_DETAIL.set(true); + category.addDetail("NBT", () -> ((TileEntity) (Object) this).writeToNBT(new NBTTagCompound()).toString()); + CrashUtils.WRITING_DETAIL.set(false); + } } } diff --git a/src/main/java/mirror/normalasm/common/internal/mixins/TextureAtlasSpriteAccessor.java b/src/main/java/mirror/normalasm/common/internal/mixins/TextureAtlasSpriteAccessor.java new file mode 100644 index 00000000..ef96dc41 --- /dev/null +++ b/src/main/java/mirror/normalasm/common/internal/mixins/TextureAtlasSpriteAccessor.java @@ -0,0 +1,14 @@ +package mirror.normalasm.common.internal.mixins; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(TextureAtlasSprite.class) +public interface TextureAtlasSpriteAccessor { + + @Accessor("framesTextureData") + List normal$getTextureData(); +} diff --git a/src/main/java/mirror/normalasm/common/internal/mixins/TextureMapAccessor.java b/src/main/java/mirror/normalasm/common/internal/mixins/TextureMapAccessor.java new file mode 100644 index 00000000..fff0c2ed --- /dev/null +++ b/src/main/java/mirror/normalasm/common/internal/mixins/TextureMapAccessor.java @@ -0,0 +1,16 @@ +package mirror.normalasm.common.internal.mixins; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(TextureMap.class) +public interface TextureMapAccessor { + + @Accessor("mapRegisteredSprites") + Map getMapRegisteredSprites(); + +} diff --git a/src/main/java/mirror/normalasm/common/modfixes/xu2/mixins/TileCrafterMixin.java b/src/main/java/mirror/normalasm/common/modfixes/xu2/mixins/TileCrafterMixin.java index 86413715..a33f296a 100644 --- a/src/main/java/mirror/normalasm/common/modfixes/xu2/mixins/TileCrafterMixin.java +++ b/src/main/java/mirror/normalasm/common/modfixes/xu2/mixins/TileCrafterMixin.java @@ -73,14 +73,15 @@ public void renderAlt(double x, double y, double z) { GlStateManager.disableCull(); GlStateManager.pushAttrib(); GlStateManager.pushMatrix(); - RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); + Minecraft mc = Minecraft.getMinecraft(); + RenderItem renderItem = mc.getRenderItem(); IBakedModel model = renderItem.getItemModelWithOverrides(stack, null, null); GlStateManager.translate(0.5F, model.isGui3d() ? 1.05F : 1.15F, 0.5F); GlStateManager.translate(x, y, z); GlStateManager.scale(0.9F, 0.9F, 0.9F); GlStateManager.rotate((MCTimer.renderTimer / 64) * (180F / (float)Math.PI), 0.0F, 1.0F, 0.0F); - renderItem.textureManager.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); - renderItem.textureManager.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).setBlurMipmap(false, false); + mc.getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + mc.getTextureManager().getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).setBlurMipmap(false, false); GlStateManager.pushMatrix(); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); GlStateManager.color(1, 1, 1, 0.4F); @@ -105,8 +106,8 @@ public void renderAlt(double x, double y, double z) { GlStateManager.popAttrib(); GlStateManager.color(1, 1, 1, 1); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - renderItem.textureManager.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); - renderItem.textureManager.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).restoreLastBlurMipmap(); + mc.getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + mc.getTextureManager().getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).restoreLastBlurMipmap(); RenderHelper.enableStandardItemLighting(); } diff --git a/src/main/java/mirror/normalasm/common/priorities/mixins/MinecraftServerMixin.java b/src/main/java/mirror/normalasm/common/priorities/mixins/MinecraftServerMixin.java new file mode 100644 index 00000000..a56fb929 --- /dev/null +++ b/src/main/java/mirror/normalasm/common/priorities/mixins/MinecraftServerMixin.java @@ -0,0 +1,22 @@ +package mirror.normalasm.common.priorities.mixins; + +import net.minecraft.server.MinecraftServer; +import org.apache.logging.log4j.Logger; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin { + + @Shadow @Final private static Logger LOGGER; + + @Redirect(method = "startServerThread", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;start()V"), require = 0) + private void setPriorityAndStart(Thread serverThread) { + serverThread.setPriority(Thread.MIN_PRIORITY + 2); + serverThread.start(); + LOGGER.debug("NormalASM: Started server thread, with {} priority", serverThread.getPriority()); + } +} \ No newline at end of file diff --git a/src/main/java/mirror/normalasm/common/priorities/mixins/client/ChunkRenderDispatcherMixin.java b/src/main/java/mirror/normalasm/common/priorities/mixins/client/ChunkRenderDispatcherMixin.java new file mode 100644 index 00000000..9598ce2c --- /dev/null +++ b/src/main/java/mirror/normalasm/common/priorities/mixins/client/ChunkRenderDispatcherMixin.java @@ -0,0 +1,48 @@ +package mirror.normalasm.common.priorities.mixins.client; + +import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; +import net.minecraft.util.math.MathHelper; +import org.apache.logging.log4j.Logger; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ChunkRenderDispatcher.class) +public class ChunkRenderDispatcherMixin { + @Shadow @Final @Mutable + private int countRenderBuilders; + + @Shadow @Final private static Logger LOGGER; + + private int getRenderBuilderCount() { + int processors = Runtime.getRuntime().availableProcessors(); + boolean allowSingleThread = Runtime.getRuntime().availableProcessors() < 2; + return MathHelper.clamp(Math.max(processors / 3, processors - 6), allowSingleThread ? 1 : 2, 10); + } + + @ModifyVariable(method = "(I)V", at = @At("STORE"), index = 3, ordinal = 2) + private int setBuilders(int original) { + return getRenderBuilderCount(); + } + + @Redirect(method = "(I)V", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher;countRenderBuilders:I")) + private void setBuilders(ChunkRenderDispatcher dispatcher, int original) { + int memoryClampMagicValue = Math.max(1, (int)((double)Runtime.getRuntime().maxMemory() * 0.3D) / 10485760); + int nThreads = MathHelper.clamp(getRenderBuilderCount(), 1, memoryClampMagicValue / 5); + /* we need more builder objects in the queue than number of threads, because threads don't free them immediately */ + this.countRenderBuilders = MathHelper.clamp(nThreads * 10, 1, memoryClampMagicValue); + LOGGER.info("Creating {} chunk builders", nThreads); + } + + @Redirect(method = "(I)V", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;start()V")) + private void setPriorityAndStart(Thread workerThread) { + workerThread.setPriority(Thread.MIN_PRIORITY + 1); + workerThread.start(); + } +} \ No newline at end of file diff --git a/src/main/java/mirror/normalasm/common/singletonevents/IRefreshEvent.java b/src/main/java/mirror/normalasm/common/singletonevents/IRefreshEvent.java index 3f60e37b..1c6757df 100644 --- a/src/main/java/mirror/normalasm/common/singletonevents/IRefreshEvent.java +++ b/src/main/java/mirror/normalasm/common/singletonevents/IRefreshEvent.java @@ -35,23 +35,7 @@ default void beforeAttachCapabilities(Object data) { } - default void afterAttachCapabilities() { - - } - - default void beforeBlockEvent(World world, BlockPos pos, IBlockState state) { - - } - - default void afterBlockEvent() { - - } - - default void beforeNeighborNotify(EnumSet notifiedSides, boolean forceRedstoneUpdate) { - - } - - default void afterNeighborNotify() { + default void beforeNeighborNotify(World world, BlockPos pos, IBlockState state, EnumSet notifiedSides, boolean forceRedstoneUpdate) { } @@ -64,6 +48,7 @@ default void beforeWorldTick(World world) { } + // TODO: determine if this avoiding this will memory leak default void afterWorldTick() { } @@ -72,6 +57,7 @@ default void beforePlayerTick(EntityPlayer player) { } + // TODO: determine if this avoiding this will memory leak default void afterPlayerTick() { } diff --git a/src/main/java/mirror/normalasm/common/singletonevents/mixins/ForgeEventFactoryMixin.java b/src/main/java/mirror/normalasm/common/singletonevents/mixins/ForgeEventFactoryMixin.java index 09f21fa9..d3a3529c 100644 --- a/src/main/java/mirror/normalasm/common/singletonevents/mixins/ForgeEventFactoryMixin.java +++ b/src/main/java/mirror/normalasm/common/singletonevents/mixins/ForgeEventFactoryMixin.java @@ -5,6 +5,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; @@ -22,6 +23,7 @@ import javax.annotation.Nullable; import java.util.EnumSet; +import java.util.Map; @Mixin(value = ForgeEventFactory.class, remap = false) public abstract class ForgeEventFactoryMixin { @@ -42,7 +44,7 @@ private static CapabilityDispatcher gatherCapabilities(AttachCapabilitiesEvent caps = TE_ATTACH_CAPABILITIES_EVENT.getCapabilities(); + return !caps.isEmpty() ? new CapabilityDispatcher(caps, null) : null; } /** @@ -72,8 +74,8 @@ public static CapabilityDispatcher gatherCapabilities(TileEntity tileEntity) { public static CapabilityDispatcher gatherCapabilities(Entity entity) { ENTITY_ATTACH_CAPABILITIES_EVENT_CASTED.beforeAttachCapabilities(entity); MinecraftForge.EVENT_BUS.post(ENTITY_ATTACH_CAPABILITIES_EVENT); - ENTITY_ATTACH_CAPABILITIES_EVENT_CASTED.afterAttachCapabilities(); - return !ENTITY_ATTACH_CAPABILITIES_EVENT.getCapabilities().isEmpty() ? new CapabilityDispatcher(ENTITY_ATTACH_CAPABILITIES_EVENT.getCapabilities(), null) : null; + Map caps = ENTITY_ATTACH_CAPABILITIES_EVENT.getCapabilities(); + return !caps.isEmpty() ? new CapabilityDispatcher(caps, null) : null; } /** @@ -85,8 +87,8 @@ public static CapabilityDispatcher gatherCapabilities(Entity entity) { public static CapabilityDispatcher gatherCapabilities(ItemStack stack, ICapabilityProvider parent) { ITEM_STACK_ATTACH_CAPABILITIES_EVENT_CASTED.beforeAttachCapabilities(stack); MinecraftForge.EVENT_BUS.post(ITEM_STACK_ATTACH_CAPABILITIES_EVENT); - ITEM_STACK_ATTACH_CAPABILITIES_EVENT_CASTED.afterAttachCapabilities(); - return parent != null || !ITEM_STACK_ATTACH_CAPABILITIES_EVENT.getCapabilities().isEmpty() ? new CapabilityDispatcher(ITEM_STACK_ATTACH_CAPABILITIES_EVENT.getCapabilities(), parent) : null; + Map caps = ITEM_STACK_ATTACH_CAPABILITIES_EVENT.getCapabilities(); + return parent != null || !caps.isEmpty() ? new CapabilityDispatcher(caps, parent) : null; } /** @@ -98,8 +100,8 @@ public static CapabilityDispatcher gatherCapabilities(ItemStack stack, ICapabili public static CapabilityDispatcher gatherCapabilities(Chunk chunk) { CHUNK_ATTACH_CAPABILITIES_EVENT_CASTED.beforeAttachCapabilities(chunk); MinecraftForge.EVENT_BUS.post(CHUNK_ATTACH_CAPABILITIES_EVENT); - CHUNK_ATTACH_CAPABILITIES_EVENT_CASTED.afterAttachCapabilities(); - return !CHUNK_ATTACH_CAPABILITIES_EVENT.getCapabilities().isEmpty() ? new CapabilityDispatcher(CHUNK_ATTACH_CAPABILITIES_EVENT.getCapabilities(), null) : null; + Map caps = CHUNK_ATTACH_CAPABILITIES_EVENT.getCapabilities(); + return !caps.isEmpty() ? new CapabilityDispatcher(caps, null) : null; } /** @@ -109,11 +111,8 @@ public static CapabilityDispatcher gatherCapabilities(Chunk chunk) { @Nullable @Overwrite public static NeighborNotifyEvent onNeighborNotify(World world, BlockPos pos, IBlockState state, EnumSet notifiedSides, boolean forceRedstoneUpdate) { - NEIGHBOR_NOTIFY_EVENT_CASTED.beforeBlockEvent(world, pos, state); - NEIGHBOR_NOTIFY_EVENT_CASTED.beforeNeighborNotify(notifiedSides, forceRedstoneUpdate); + NEIGHBOR_NOTIFY_EVENT_CASTED.beforeNeighborNotify(world, pos, state, notifiedSides, forceRedstoneUpdate); MinecraftForge.EVENT_BUS.post(NEIGHBOR_NOTIFY_EVENT); - NEIGHBOR_NOTIFY_EVENT_CASTED.afterBlockEvent(); - NEIGHBOR_NOTIFY_EVENT_CASTED.afterNeighborNotify(); return NEIGHBOR_NOTIFY_EVENT; } diff --git a/src/main/java/mirror/normalasm/common/singletonevents/mixins/blocks/BlockEventMixin.java b/src/main/java/mirror/normalasm/common/singletonevents/mixins/blocks/BlockEventMixin.java deleted file mode 100644 index ab815434..00000000 --- a/src/main/java/mirror/normalasm/common/singletonevents/mixins/blocks/BlockEventMixin.java +++ /dev/null @@ -1,32 +0,0 @@ -package mirror.normalasm.common.singletonevents.mixins.blocks; - -import net.minecraft.block.state.IBlockState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraftforge.event.world.BlockEvent; -import net.minecraftforge.fml.common.eventhandler.Event; -import org.spongepowered.asm.mixin.*; -import mirror.normalasm.common.singletonevents.IRefreshEvent; - -@Mixin(value = BlockEvent.class, remap = false) -public class BlockEventMixin extends Event implements IRefreshEvent { - - @Shadow @Final @Mutable private World world; - @Shadow @Final @Mutable private BlockPos pos; - @Shadow @Final @Mutable private IBlockState state; - - @Override - public void beforeBlockEvent(World world, BlockPos pos, IBlockState state) { - this.world = world; - this.pos = pos; - this.state = state; - } - - @Override - public void afterBlockEvent() { - this.world = null; - this.pos = null; - this.state = null; - } - -} diff --git a/src/main/java/mirror/normalasm/common/singletonevents/mixins/blocks/NeighborNotifyEventMixin.java b/src/main/java/mirror/normalasm/common/singletonevents/mixins/blocks/NeighborNotifyEventMixin.java index ce127fb2..1de901cd 100644 --- a/src/main/java/mirror/normalasm/common/singletonevents/mixins/blocks/NeighborNotifyEventMixin.java +++ b/src/main/java/mirror/normalasm/common/singletonevents/mixins/blocks/NeighborNotifyEventMixin.java @@ -1,33 +1,58 @@ package mirror.normalasm.common.singletonevents.mixins.blocks; +import net.minecraft.block.state.IBlockState; import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.world.BlockEvent.NeighborNotifyEvent; -import net.minecraftforge.fml.common.eventhandler.Event; import net.minecraftforge.fml.common.eventhandler.EventPriority; import org.spongepowered.asm.mixin.*; import mirror.normalasm.common.singletonevents.IRefreshEvent; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.lang.ref.WeakReference; import java.util.EnumSet; @Mixin(NeighborNotifyEvent.class) -public class NeighborNotifyEventMixin extends Event implements IRefreshEvent { +public class NeighborNotifyEventMixin extends BlockEvent implements IRefreshEvent { @Shadow @Final @Mutable private EnumSet notifiedSides; @Shadow @Final @Mutable private boolean forceRedstoneUpdate; - @Unique private EventPriority normalPriority = null; + @Unique private EventPriority normalPriority; + @Unique private WeakReference normalWorldRef; + @Unique private BlockPos normalPos; + @Unique private IBlockState normalState; + + NeighborNotifyEventMixin(World world, BlockPos pos, IBlockState state) { + super(world, pos, state); + throw new AssertionError(); + } @Override - public void beforeNeighborNotify(EnumSet notifiedSides, boolean forceRedstoneUpdate) { - this.notifiedSides = notifiedSides; - this.forceRedstoneUpdate = forceRedstoneUpdate; + public World getWorld() { + return this.normalWorldRef.get(); + } + + @Override + public BlockPos getPos() { + return normalPos; + } + + @Override + public IBlockState getState() { + return normalState; } @Override - public void afterNeighborNotify() { - this.notifiedSides = null; + public void beforeNeighborNotify(World world, BlockPos pos, IBlockState state, EnumSet notifiedSides, boolean forceRedstoneUpdate) { + this.normalWorldRef = new WeakReference<>(world); + this.normalPos = pos; + this.normalState = state; + this.notifiedSides = notifiedSides; + this.forceRedstoneUpdate = forceRedstoneUpdate; } @Nullable diff --git a/src/main/java/mirror/normalasm/common/singletonevents/mixins/capabilities/AttachCapabilitiesEventMixin.java b/src/main/java/mirror/normalasm/common/singletonevents/mixins/capabilities/AttachCapabilitiesEventMixin.java index 443b9ef6..a2ba7707 100644 --- a/src/main/java/mirror/normalasm/common/singletonevents/mixins/capabilities/AttachCapabilitiesEventMixin.java +++ b/src/main/java/mirror/normalasm/common/singletonevents/mixins/capabilities/AttachCapabilitiesEventMixin.java @@ -24,13 +24,7 @@ public class AttachCapabilitiesEventMixin extends Event implements IRefreshEv @Override public void beforeAttachCapabilities(Object data) { this.obj = (T) data; - } - - @Override - public void afterAttachCapabilities() { - this.obj = null; this.caps.clear(); - this.normalPriority = null; } @Nullable diff --git a/src/main/java/mirror/normalasm/config/NormalConfig.java b/src/main/java/mirror/normalasm/config/NormalConfig.java index da799483..a01ffd3c 100644 --- a/src/main/java/mirror/normalasm/config/NormalConfig.java +++ b/src/main/java/mirror/normalasm/config/NormalConfig.java @@ -67,9 +67,10 @@ public boolean shouldSkipClass(Class clazz) { public boolean resourceLocationCanonicalization, modelConditionCanonicalization, nbtTagStringBackingStringCanonicalization, nbtBackingMapStringCanonicalization, packageStringCanonicalization, lockCodeCanonicalization, spriteNameCanonicalization, asmDataStringCanonicalization, vertexDataCanonicalization, filePermissionsCacheCanonicalization; public boolean optimizeFMLRemapper; public boolean optimizeRegistries, optimizeNBTTagCompoundBackingMap, optimizeFurnaceRecipeStore, stripNearUselessItemStackFields, moreModelManagerCleanup, efficientHashing, replaceSearchTreeWithJEISearching; + public int optimizeNBTTagCompoundMapThreshold; public boolean releaseSpriteFramesCache, onDemandAnimatedTextures; public boolean optimizeSomeRendering, stripUnnecessaryLocalsInRenderHelper; - public boolean quickerEnableUniversalBucketCheck, stripInstancedRandomFromSoundEventAccessor, classCaching, copyScreenshotToClipboard, releaseScreenshotCache, asyncScreenshot, removeExcessiveGCCalls, smoothDimensionChange; + public boolean quickerEnableUniversalBucketCheck, stripInstancedRandomFromSoundEventAccessor, classCaching, copyScreenshotToClipboard, releaseScreenshotCache, asyncScreenshot, removeExcessiveGCCalls, smoothDimensionChange, threadPriorityFix, outdatedCaCertsFix; public boolean fixBlockIEBaseArrayIndexOutOfBoundsException, cleanupChickenASMClassHierarchyManager, optimizeAmuletRelatedFunctions, labelCanonicalization, skipCraftTweakerRecalculatingSearchTrees, bwmBlastingOilOptimization, optimizeQMDBeamRenderer, repairEvilCraftEIOCompat, optimizeArcaneLockRendering, fixXU2CrafterCrash, disableXU2CrafterRendering, fixTFCFallingBlockFalseStartingTEPos; public boolean fixAmuletHolderCapability, delayItemStackCapabilityInit; public boolean fixFillBucketEventNullPointerException, fixTileEntityOnLoadCME, removeForgeSecurityManager, fasterEntitySpawnPreparation, fixDimensionTypesInliningCrash; @@ -117,6 +118,7 @@ public void load() { // optimizeDataStructures = getBoolean("optimizeDataStructures", "datastructures", "Optimizes various data structures around Minecraft", true); optimizeRegistries = getBoolean("optimizeRegistries", "datastructures", "Optimizes registries", true); optimizeNBTTagCompoundBackingMap = getBoolean("optimizeNBTTagCompoundBackingMap", "datastructures", "Optimize NBTTagCompound's backing map structure", true); + optimizeNBTTagCompoundMapThreshold = getInteger("optimizeNBTTagCompoundMapThreshold", "datastructures", "Max size NBTTagCompounds backing map can get before it gets changed to HashMap from ArrayMap", 5); optimizeFurnaceRecipeStore = getBoolean("optimizeFurnaceRecipeStore", "datastructures", "Optimizing FurnaceRecipes. FastFurnace will see very little benefit when this option is turned on", true); stripNearUselessItemStackFields = getBoolean("stripNearUselessItemStackFields", "datastructures", "EXPERIMENTAL: Strips ItemStack of some of its fields as it stores some near-useless references", true); moreModelManagerCleanup = getBoolean("moreModelManagerCleanup", "datastructures", "Clears and trims ModelManager data structures after models are loaded and baked", true); @@ -137,6 +139,8 @@ public void load() { asyncScreenshot = getBoolean("asyncScreenshot", "misc", "Process screenshots and print to chat asynchronously", true); removeExcessiveGCCalls = getBoolean("removeExcessiveGCCalls", "misc", "Removes forced garbage collection calls, inspired by VanillaFix, can make world loading faster", true); smoothDimensionChange = getBoolean("smoothDimensionChange", "misc", "Allows changing of dimensions to be smooth and nearly instantaneous, inspired by VanillaFix", true); + threadPriorityFix = getBoolean("threadPriorityFix", "misc", "Adjust thread priorities to improve performance on systems with few cores", true); + outdatedCaCertsFix = getBoolean("outdatedCaCertsFix", "misc", "Use updated CA Certs that was included in 8u311. This most notably fixes 8u51 certs issues", true); fixBlockIEBaseArrayIndexOutOfBoundsException = getBoolean("fixBlockIEBaseArrayIndexOutOfBoundsException", "modfixes", "When Immersive Engineering is installed, sometimes it or it's addons can induce an ArrayIndexOutOfBoundsException in BlockIEBase#getPushReaction. This option will be ignored when IE isn't installed", true); cleanupChickenASMClassHierarchyManager = getBoolean("cleanupChickenASMClassHierarchyManager", "modfixes", "EXPERIMENTAL: When ChickenASM (Library of CodeChickenLib and co.) is installed, ClassHierarchyManager can cache a lot of Strings and seem to be unused in any transformation purposes. This clears ClassHierarchyManager of those redundant strings. This option will be ignored when ChickenASM isn't installed", true); @@ -241,6 +245,16 @@ private boolean getBoolean(String name, String category, String description, boo return prop.getBoolean(defaultValue); } + private int getInteger(String name, String category, String description, int defaultValue) { + Property prop = configuration.get(category, name, defaultValue); + prop.setDefaultValue(defaultValue); + prop.setComment(description + " - "); + prop.setRequiresMcRestart(true); + prop.setShowInGui(true); + prop.setLanguageKey("normalasm.config." + name); + return prop.getInt(defaultValue); + } + private String[] getStringArray(String name, String category, String description, String... defaultValue) { Property prop = configuration.get(category, name, defaultValue); prop.setDefaultValues(defaultValue); diff --git a/src/main/java/mirror/normalasm/core/NormalHooks.java b/src/main/java/mirror/normalasm/core/NormalHooks.java index cac6e513..245a5f03 100644 --- a/src/main/java/mirror/normalasm/core/NormalHooks.java +++ b/src/main/java/mirror/normalasm/core/NormalHooks.java @@ -84,5 +84,4 @@ public static void inform(Class clazz) { public static String nbtTagString$override$ctor(String data) { return NormalStringPool.canonicalize(data); } - } diff --git a/src/main/java/mirror/normalasm/core/NormalLoadingPlugin.java b/src/main/java/mirror/normalasm/core/NormalLoadingPlugin.java index 17971fdd..76faf1ae 100644 --- a/src/main/java/mirror/normalasm/core/NormalLoadingPlugin.java +++ b/src/main/java/mirror/normalasm/core/NormalLoadingPlugin.java @@ -5,6 +5,7 @@ import net.minecraftforge.fml.relauncher.FMLLaunchHandler; import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; import net.minecraftforge.fml.relauncher.Side; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.SystemUtils; import mirror.normalasm.UnsafeNormal; import mirror.normalasm.config.NormalConfig; @@ -16,6 +17,7 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.lang.management.ManagementFactory; import java.net.MalformedURLException; import java.util.Arrays; @@ -29,7 +31,7 @@ @IFMLLoadingPlugin.MCVersion(ForgeVersion.mcVersion) public class NormalLoadingPlugin implements IFMLLoadingPlugin, IEarlyMixinLoader { - public static final String VERSION = "5.6"; + public static final String VERSION = "5.23"; public static final boolean isDeobf = FMLLaunchHandler.isDeobfuscatedEnvironment(); @@ -72,6 +74,17 @@ public NormalLoadingPlugin() { if (NormalConfig.instance.sparkProfileEntireGameLoad) { NormalSparker.start("game"); } + if (NormalConfig.instance.outdatedCaCertsFix) { + try (InputStream is = this.getClass().getResource("/cacerts").openStream()) { + File cacertsCopy = File.createTempFile("cacerts", ""); + cacertsCopy.deleteOnExit(); + FileUtils.copyInputStreamToFile(is, cacertsCopy); + System.setProperty("javax.net.ssl.trustStore", cacertsCopy.getAbsolutePath()); + NormalLogger.instance.warn("Replacing CA Certs with an updated one..."); + } catch (Exception e) { + NormalLogger.instance.warn("Unable to replace CA Certs.", e); + } + } if (NormalConfig.instance.removeForgeSecurityManager) { UnsafeNormal.removeFMLSecurityManager(); } @@ -158,13 +171,15 @@ public List getMixinConfigs() { "mixins.crashes.json", "mixins.fix_mc129057.json", "mixins.bucket.json", + "mixins.priorities.json", "mixins.rendering.json", "mixins.datastructures_modelmanager.json", "mixins.screenshot.json", "mixins.ondemand_sprites.json", "mixins.searchtree_vanilla.json", "mixins.resolve_mc2071.json", - "mixins.fix_mc_skindownloading.json") : + "mixins.fix_mc_skindownloading.json", + "mixins.fix_mc186052.json") : Arrays.asList( "mixins.devenv.json", "mixins.vfix_bugfixes.json", @@ -179,6 +194,7 @@ public List getMixinConfigs() { "mixins.capability.json", "mixins.singletonevents.json", "mixins.efficienthashing.json", + "mixins.priorities.json", "mixins.crashes.json", "mixins.fix_mc129057.json"); } @@ -198,10 +214,6 @@ public boolean shouldMixinConfigQueue(String mixinConfig) { return NormalConfig.instance.moreModelManagerCleanup; case "mixins.screenshot.json": return NormalConfig.instance.releaseScreenshotCache || NormalConfig.instance.asyncScreenshot; - case "mixins.ondemand_sprites.json": - return NormalConfig.instance.onDemandAnimatedTextures; - case "mixins.searchtree_vanilla.json": - return NormalConfig.instance.replaceSearchTreeWithJEISearching; case "mixins.resolve_mc2071.json": return NormalConfig.instance.resolveMC2071; case "mixins.fix_mc_skindownloading.json": @@ -231,6 +243,8 @@ public boolean shouldMixinConfigQueue(String mixinConfig) { return NormalConfig.instance.crashReportImprovements; case "mixins.fix_mc129057.json": return NormalConfig.instance.fixMC129057; + case "mixins.priorities.json": + return NormalConfig.instance.threadPriorityFix; } return true; } diff --git a/src/main/java/mirror/normalasm/core/NormalSpriteMixinPlugin.java b/src/main/java/mirror/normalasm/core/NormalSpriteMixinPlugin.java new file mode 100644 index 00000000..9ab6b1cc --- /dev/null +++ b/src/main/java/mirror/normalasm/core/NormalSpriteMixinPlugin.java @@ -0,0 +1,47 @@ +package mirror.normalasm.core; + +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; +import mirror.normalasm.NormalLogger; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class NormalSpriteMixinPlugin implements IMixinConfigPlugin { + + static boolean logged = false; + + @Override + public void onLoad(String s) { } + + @Override + public String getRefMapperConfig() { + return ""; + } + + @Override + public boolean shouldApplyMixin(String s, String s1) { + if (!logged) { + NormalLogger.instance.error("Optifine is installed. On demand sprites won't be activated as Optifine already has Smart Animations."); + logged = true; + } + return !NormalTransformer.isOptifineInstalled; + } + + @Override + public void acceptTargets(Set set, Set set1) { } + + @Override + public List getMixins() { + return Collections.emptyList(); + } + + @Override + public void preApply(String s, ClassNode classNode, String s1, IMixinInfo iMixinInfo) { } + + @Override + public void postApply(String s, ClassNode classNode, String s1, IMixinInfo iMixinInfo) { } + +} diff --git a/src/main/java/mirror/normalasm/core/NormalTransformer.java b/src/main/java/mirror/normalasm/core/NormalTransformer.java index f6b90558..ed119fa0 100644 --- a/src/main/java/mirror/normalasm/core/NormalTransformer.java +++ b/src/main/java/mirror/normalasm/core/NormalTransformer.java @@ -22,7 +22,7 @@ public class NormalTransformer implements IClassTransformer { - public static boolean isOptifineInstalled; + public static boolean isOptifineInstalled, isSodiumPortInstalled; public static boolean squashBakedQuads = NormalConfig.instance.squashBakedQuads; Multimap> transformations; @@ -30,9 +30,15 @@ public class NormalTransformer implements IClassTransformer { public NormalTransformer() { NormalLogger.instance.info("NormalASM is now preparing to bytecode manipulate your game."); isOptifineInstalled = NormalReflector.doesClassExist("optifine.OptiFineForgeTweaker"); - if (squashBakedQuads && isOptifineInstalled) { - squashBakedQuads = false; - NormalLogger.instance.info("Optifine is installed. BakedQuads won't be squashed as it is incompatible with OptiFine."); + isSodiumPortInstalled = NormalReflector.doesClassExist("me.jellysquid.mods.sodium.client.SodiumMixinTweaker"); + if (squashBakedQuads) { + if (isOptifineInstalled) { + squashBakedQuads = false; + NormalLogger.instance.info("Optifine is installed. BakedQuads won't be squashed as it is incompatible with OptiFine."); + } else if (isSodiumPortInstalled) { + squashBakedQuads = false; + NormalLogger.instance.info("A sodium port is installed. BakedQuads won't be squashed as it is incompatible with Sodium."); + } } transformations = MultimapBuilder.hashKeys(30).arrayListValues(1).build(); if (NormalLoadingPlugin.isClient) { @@ -137,7 +143,7 @@ public NormalTransformer() { if (NormalConfig.instance.fixMC31681) { addTransformation("net.minecraft.client.renderer.EntityRenderer", this::fixMC31681); } - addTransformation("net.minecraft.nbt.NBTTagCompound", bytes -> nbtTagCompound$replaceDefaultHashMap(bytes, NormalConfig.instance.optimizeNBTTagCompoundBackingMap, NormalConfig.instance.nbtBackingMapStringCanonicalization)); + addTransformation("net.minecraft.nbt.NBTTagCompound", bytes -> nbtTagCompound$replaceDefaultHashMap(bytes, NormalConfig.instance.optimizeNBTTagCompoundBackingMap, NormalConfig.instance.optimizeNBTTagCompoundMapThreshold, NormalConfig.instance.nbtBackingMapStringCanonicalization)); } public void addTransformation(String key, Function value) { @@ -462,29 +468,28 @@ private byte[] removeInstancedRandom(byte[] bytes) { return writer.toByteArray(); } - private byte[] nbtTagCompound$replaceDefaultHashMap(byte[] bytes, boolean optimizeMap, boolean canonicalizeString) { - if (!optimizeMap && !canonicalizeString) { + private byte[] nbtTagCompound$replaceDefaultHashMap(byte[] bytes, boolean optimizeMap, int mapThreshold, boolean canonicalizeString) { + if ((!optimizeMap || mapThreshold == 0) && !canonicalizeString) { return bytes; } ClassReader reader = new ClassReader(bytes); ClassNode node = new ClassNode(); reader.accept(node, 0); - for (MethodNode method : node.methods) { if (method.name.equals("")) { ListIterator iter = method.instructions.iterator(); while (iter.hasNext()) { AbstractInsnNode instruction = iter.next(); if (instruction.getOpcode() == INVOKESTATIC) { - iter.set(new TypeInsnNode(NEW, canonicalizeString ? "mirror/normalasm/api/datastructures/canonical/AutoCanonizingArrayMap" : "it/unimi/dsi/fastutil/objects/Object2ObjectArrayMap")); + iter.set(new TypeInsnNode(NEW, "mirror/normalasm/api/datastructures/NormalTagMap")); iter.add(new InsnNode(DUP)); - iter.add(new MethodInsnNode(INVOKESPECIAL, canonicalizeString ? "mirror/normalasm/api/datastructures/canonical/AutoCanonizingArrayMap" : "it/unimi/dsi/fastutil/objects/Object2ObjectArrayMap", "", "()V", false)); + iter.add(new MethodInsnNode(INVOKESPECIAL, "mirror/normalasm/api/datastructures/NormalTagMap", "", "()V", false)); break; } } + break; } } - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES); node.accept(writer); return writer.toByteArray(); diff --git a/src/main/java/mirror/normalasm/proxy/ClientProxy.java b/src/main/java/mirror/normalasm/proxy/ClientProxy.java index 085da25c..e37ed309 100644 --- a/src/main/java/mirror/normalasm/proxy/ClientProxy.java +++ b/src/main/java/mirror/normalasm/proxy/ClientProxy.java @@ -1,10 +1,6 @@ package mirror.normalasm.proxy; -import mirror.normalasm.bakedquad.NormalVertexDataPool; -import mirror.normalasm.core.NormalTransformer; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.resources.IReloadableResourceManager; import net.minecraftforge.client.resource.ISelectiveResourceReloadListener; import net.minecraftforge.client.resource.VanillaResourceType; @@ -15,38 +11,23 @@ import net.minecraftforge.fml.common.event.FMLLoadCompleteEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.relauncher.Side; -import pl.asie.foamfix.shared.FoamFixShared; -import slimeknights.tconstruct.library.client.texture.AbstractColoredTexture; import mirror.normalasm.NormalLogger; -import mirror.normalasm.NormalReflector; -import mirror.normalasm.client.mcfixes.SkinDataReleaser; +import mirror.normalasm.bakedquad.NormalVertexDataPool; import mirror.normalasm.client.models.bucket.NormalBakedDynBucket; import mirror.normalasm.client.screenshot.ScreenshotListener; import mirror.normalasm.client.sprite.FramesTextureData; import mirror.normalasm.common.modfixes.qmd.QMDEventHandler; import mirror.normalasm.config.NormalConfig; +import mirror.normalasm.core.NormalTransformer; import java.util.ArrayList; import java.util.List; -import java.util.Map; + @Mod.EventBusSubscriber(modid = "normalasm", value = Side.CLIENT) public class ClientProxy extends CommonProxy { public static final List refreshAfterModels = new ArrayList<>(); - public static final boolean flushTinkerSpriteFrameTextureData; - - static { - boolean static$flushTinkerSpriteFrameTextureData = true; - if (Loader.isModLoaded("tconstruct") && Loader.isModLoaded("foamfix")) { - if (FoamFixShared.config.clDynamicItemModels) { - static$flushTinkerSpriteFrameTextureData = false; - } - } - flushTinkerSpriteFrameTextureData = static$flushTinkerSpriteFrameTextureData; - } - - public static boolean canReload = true; @Override public void preInit(FMLPreInitializationEvent event) { @@ -60,9 +41,6 @@ public void preInit(FMLPreInitializationEvent event) { if (NormalConfig.instance.copyScreenshotToClipboard) { MinecraftForge.EVENT_BUS.register(ScreenshotListener.class); } - if (NormalConfig.instance.fixMC186052) { - MinecraftForge.EVENT_BUS.register(SkinDataReleaser.class); - } } @Override @@ -95,22 +73,6 @@ private void releaseSpriteFramesCache() { NormalBakedDynBucket.coverQuads.clear(); NormalBakedDynBucket.flippedCoverQuads.clear(); } - if (NormalConfig.instance.releaseSpriteFramesCache) { - canReload = false; - try { - for (TextureAtlasSprite sprite : ((Map) NormalReflector.resolveFieldGetter(TextureMap.class, "mapRegisteredSprites", "field_110574_e").invoke(Minecraft.getMinecraft().getTextureMapBlocks())).values()) { - if (!sprite.hasAnimationMetadata()) { - if (!flushTinkerSpriteFrameTextureData && sprite instanceof AbstractColoredTexture) { - continue; - } - sprite.setFramesTextureData(new FramesTextureData(sprite)); - } - } - } catch (Throwable e) { - e.printStackTrace(); - } - canReload = true; - } if (!NormalTransformer.isOptifineInstalled && NormalConfig.instance.vertexDataCanonicalization) { NormalVertexDataPool.invalidate(); } diff --git a/src/main/java/mirror/normalasm/proxy/CommonProxy.java b/src/main/java/mirror/normalasm/proxy/CommonProxy.java index 2a14535f..b829fae9 100644 --- a/src/main/java/mirror/normalasm/proxy/CommonProxy.java +++ b/src/main/java/mirror/normalasm/proxy/CommonProxy.java @@ -56,6 +56,8 @@ public void construct(FMLConstructionEvent event) { if (NormalConfig.instance.cleanupLaunchClassLoaderEarly) { cleanupLaunchClassLoader(); } + if (NormalConfig.instance.threadPriorityFix) + Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 2); } public void preInit(FMLPreInitializationEvent event) { } diff --git a/src/main/java/mirror/normalasm/vanillafix/bugfixes/mixins/MixinEntityPlayerMP.java b/src/main/java/mirror/normalasm/vanillafix/bugfixes/mixins/MixinEntityPlayerMP.java index 401212d9..77ea0a10 100644 --- a/src/main/java/mirror/normalasm/vanillafix/bugfixes/mixins/MixinEntityPlayerMP.java +++ b/src/main/java/mirror/normalasm/vanillafix/bugfixes/mixins/MixinEntityPlayerMP.java @@ -12,8 +12,8 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import zone.rong.mixinextras.injector.ModifyReturnValue; @Mixin(EntityPlayerMP.class) public abstract class MixinEntityPlayerMP extends EntityPlayer { @@ -27,9 +27,9 @@ public abstract class MixinEntityPlayerMP extends EntityPlayer { * teleporting the player again (in the other nether portal before the client had the * time to confirm the teleport). */ - @Redirect(method = "isEntityInvulnerable", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/EntityPlayer;isEntityInvulnerable(Lnet/minecraft/util/DamageSource;)Z")) - private boolean isEntityInvulnerable(EntityPlayer entityPlayer, DamageSource source) { - return false; + @ModifyReturnValue(method = "isEntityInvulnerable", at = @At(value = "RETURN")) + private boolean isEntityInvulnerable(boolean original, DamageSource source) { + return super.isEntityInvulnerable(source); } /** diff --git a/src/main/resources/META-INF/normalasm_at.cfg b/src/main/resources/META-INF/normalasm_at.cfg deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/resources/cacerts b/src/main/resources/cacerts new file mode 100644 index 00000000..54e56c27 Binary files /dev/null and b/src/main/resources/cacerts differ diff --git a/src/main/resources/mixins.fix_mc186052.json b/src/main/resources/mixins.fix_mc186052.json new file mode 100644 index 00000000..1d5d195b --- /dev/null +++ b/src/main/resources/mixins.fix_mc186052.json @@ -0,0 +1,11 @@ +{ + "package": "mirror.normalasm.client.mcfixes.mixins.mc186052", + "refmap": "mixins.normalasm.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "client": [ + "MinecraftMixin", + "TextureManagerExpansion" + ] +} \ No newline at end of file diff --git a/src/main/resources/mixins.internal.json b/src/main/resources/mixins.internal.json index 42ad670a..9b7a0aa2 100644 --- a/src/main/resources/mixins.internal.json +++ b/src/main/resources/mixins.internal.json @@ -10,6 +10,8 @@ "LoadControllerMixin" ], "client": [ + "TextureAtlasSpriteAccessor", + "TextureMapAccessor", "TextureManagerAccessor", "TileEntityMixin" ] diff --git a/src/main/resources/mixins.ondemand_sprites.json b/src/main/resources/mixins.ondemand_sprites.json index 8b9e477e..e49479a1 100644 --- a/src/main/resources/mixins.ondemand_sprites.json +++ b/src/main/resources/mixins.ondemand_sprites.json @@ -1,6 +1,6 @@ { "package": "mirror.normalasm.client.sprite.ondemand.mixins", - "plugin": "mirror.normalasm.core.NormalMixinPlugin", + "plugin": "mirror.normalasm.core.NormalSpriteMixinPlugin", "refmap": "mixins.normalasm.refmap.json", "target": "@env(DEFAULT)", "minVersion": "0.8", diff --git a/src/main/resources/mixins.priorities.json b/src/main/resources/mixins.priorities.json new file mode 100644 index 00000000..a775d374 --- /dev/null +++ b/src/main/resources/mixins.priorities.json @@ -0,0 +1,17 @@ +{ + "package": "mirror.normalasm.common.priorities.mixins", + "plugin": "mirror.normalasm.core.NormalMixinPlugin", + "refmap": "mixins.normalasm.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "MinecraftServerMixin" + ], + "client": [ + "client.ChunkRenderDispatcherMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/mixins.singletonevents.json b/src/main/resources/mixins.singletonevents.json index 2bafc154..a1e5f03a 100644 --- a/src/main/resources/mixins.singletonevents.json +++ b/src/main/resources/mixins.singletonevents.json @@ -7,7 +7,6 @@ "mixins": [ "FMLCommonHandlerMixin", "ForgeEventFactoryMixin", - "blocks.BlockEventMixin", "blocks.NeighborNotifyEventMixin", "capabilities.AttachCapabilitiesEventMixin", "gameevent.PlayerTickEventMixin",