Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vanilla Crash & Furnace Speedup #37

Merged
merged 4 commits into from
Dec 11, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ dependencies {
compileOnly("curse.maven:cofh-core-69162:2388751") {
transitive = false
}
compileOnly files("dependencies/Thermos-1.7.10-1614-stripped.jar")
}
Binary file added dependencies/Thermos-1.7.10-1614-stripped.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ public enum AsmTransformers {
),
FIX_POTION_EFFECT_RENDERING("Move vanilla potion effect status rendering before everything else",
() -> HodgepodgeMixinPlugin.config.fixPotionEffectRender,
Collections.singletonList("com.mitchej123.hodgepodge.asm.InventoryEffectRendererTransformer"))
Collections.singletonList("com.mitchej123.hodgepodge.asm.InventoryEffectRendererTransformer")),
THERMOS_SLEDGEHAMMER_FURNACE_FIX("Take a sledgehammer to CraftServer.resetRecipes() to prevent it from breaking our Furnace Fix",
()-> HodgepodgeMixinPlugin.thermosTainted && HodgepodgeMixinPlugin.config.speedupVanillaFurnace,
Collections.singletonList("com.mitchej123.hodgepodge.asm.ThermosFurnaceSledgeHammer")
)
;

private final String name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ public byte[] transform(String name, String transformedName, byte[] basicClass)
}
cn.accept(cw);
return cw.toByteArray();
} else {
}
else {
return basicClass;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.mitchej123.hodgepodge.asm;

import com.mitchej123.hodgepodge.core.HodgepodgeMixinPlugin;
import net.minecraft.launchwrapper.IClassTransformer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.MethodNode;

import static org.objectweb.asm.Opcodes.ASM5;

@SuppressWarnings("unused")
public class ThermosFurnaceSledgeHammer implements IClassTransformer {
private static final Logger LOGGER = LogManager.getLogger("ThermosFurnaceSledgeHammer");
@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
if (HodgepodgeMixinPlugin.config.thermosCraftServerClass.equals(transformedName)) {
LOGGER.info("Patching Thermos or derivative to not break our furnace fix");
final ClassReader cr = new ClassReader(basicClass);
final ClassWriter cw = new ClassWriter(0);

final ClassNode cn = new ClassNode(ASM5);
cr.accept(cn, ClassReader.EXPAND_FRAMES);
for (MethodNode m : cn.methods) {
if ("resetRecipes".equals(m.name)) {
LOGGER.info("Taking a sledgehammer to CraftServer.resetRecipes()");
//Replace the body with a RETURN opcode
InsnList insnList = new InsnList();
insnList.add(new InsnNode(Opcodes.RETURN));
m.instructions = insnList;
}
}
cn.accept(cw);
return cw.toByteArray();
}
else {
return basicClass;
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class HodgepodgeMixinPlugin implements IMixinConfigPlugin {
Class.forName("org.bukkit.World");
thermosTainted = true;
log.warn("Thermos/Bukkit detected; This is an unsupported configuration -- Things may not function properly.");
log.warn(" Using `{}` for CraftServer Package. If this is not correct, please update your config file!", config.thermosCraftServerClass);
} catch (ClassNotFoundException e) {
thermosTainted = false;
log.info("Thermos/Bukkit NOT detected :-D");
Expand Down Expand Up @@ -176,17 +177,23 @@ public enum MixinSets {
() -> config.fixHopperHitBox,
Collections.singletonList("fixHopperHitBox.MixinBlockHopper")),
FIX_GET_BLOCK_LIGHT_VALUE("Fix vanilla light value calculation NPE",
() -> config.fixGetBlockLightValue,
Collections.singletonList("fixGetBlockLightValue.MixinWorld")),
() -> config.fixGetBlockLightValue,
Collections.singletonList("fixGetBlockLightValue.MixinWorld")),
FIX_FIRE_SPREAD("Fix vanilla fire spread NPE",
() -> config.fixFireSpread,
Collections.singletonList("fixFireSpread.MixinBlockFire")),
() -> config.fixFireSpread,
Collections.singletonList("fixFireSpread.MixinBlockFire")),
TILE_RENDERER_PROFILER("Shows renderer's impact on FPS in vanilla lagometer",
() -> config.enableTileRendererProfiler,
Arrays.asList("profiler.TileEntityRendererDispatcherMixin", "profiler.MinecraftMixin")),
() -> config.enableTileRendererProfiler,
Arrays.asList("profiler.TileEntityRendererDispatcherMixin", "profiler.MinecraftMixin")),
ADD_CV_SUPPORT_TO_WAND_PEDESTAL("Add CV support to Thaumcraft wand recharge pedestal",
()->config.addCVSupportToWandPedestal,
Collections.singletonList("wandPedestalCV.MixinTileWandPedestal"))
()->config.addCVSupportToWandPedestal,
Collections.singletonList("wandPedestalCV.MixinTileWandPedestal")),
FIX_FORGE_URL_DETECTION("Fix URISyntaxException in Forge Chat",
() -> config.fixUrlDetection,
Collections.singletonList("fixUrlDetection.MixinForgeHooks")),
SPEEDUP_VANILLA_FURNACE("Speedup vanilla furnace recipe lookup",
() -> config.speedupVanillaFurnace,
Collections.singletonList("speedupVanillaFurnace.MixinFurnaceRecipes"))
;


Expand Down
13 changes: 11 additions & 2 deletions src/main/java/com/mitchej123/hodgepodge/core/LoadingConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ public class LoadingConfig {
public boolean fixPotionEffectRender;
public boolean addCVSupportToWandPedestal;
public boolean speedupProgressBar;
public boolean fixUrlDetection;
public boolean speedupVanillaFurnace;
// ASM
public boolean pollutionAsm;
public boolean cofhWorldTransformer;
public boolean enableTileRendererProfiler;

public String thermosCraftServerClass;


public static Configuration config;

Expand All @@ -63,6 +68,7 @@ public LoadingConfig(File file) {
fixHopperHitBox = config.get("fixes", "fixHopperHitBox", true, "Fix vanilla hopper hit box").getBoolean();
fixGetBlockLightValue = config.get("fixes", "fixGetBlockLightValue", true, "Fix vanilla light calculation sometimes cause NPE on thermos").getBoolean();
fixFireSpread = config.get("fixes", "fixFireSpread", true, "Fix vanilla fire spread sometimes cause NPE on thermos").getBoolean();
fixUrlDetection = config.get("fixes", "fixUrlDetection", true, "Fix URISyntaxException in forge.").getBoolean();

fixPotionEffectRender = config.get("tweaks", "fixPotionEffectRender", true, "Move vanilla potion effect status rendering before everything else").getBoolean();
installAnchorAlarm = config.get("tweaks", "installAnchorAlarm", true, "Wake up passive & personal anchors on player login").getBoolean();
Expand All @@ -75,19 +81,22 @@ public LoadingConfig(File file) {
ic2SeedMaxStackSize = config.get("tweaks", "ic2SeedMaxStackSize", 64, "IC2 seed max stack size").getInt();

speedupChunkCoordinatesHashCode = config.get("speedups", "speedupChunkCoordinatesHashCode", true, "Speedup ChunkCoordinates hashCode").getBoolean();
speedupVanillaFurnace = config.get("speedups", "speedupVanillaFurnace", true, "Speedup Vanilla Furnace recipe lookup").getBoolean();

speedupProgressBar = config.get("asm", "speedupProgressBar", true, "Speedup progressbar").getBoolean();
pollutionAsm = config.get("asm", "pollutionAsm", true, "Enable pollution rendering ASM").getBoolean();
cofhWorldTransformer = config.get("asm", "cofhWorldTransformer", true, "Enable Glease's ASM patch to disable unused CoFH tileentity cache").getBoolean();

thermosCraftServerClass = config.get("asm", "thermosCraftServerClass", "org.bukkit.craftbukkit.v1_7_R4.CraftServer", "If using Bukkit/Thermos, the CraftServer package.").getString();

if (config.hasChanged())
config.save();
}

public static void postInitClient() {
//need to be done later cause it initializes classes
// need to be done later cause it initializes classes
if (config == null) {
System.err.println("Didnt load HODGE");
System.err.println("Didn't load HODGEPODGE");
config = new Configuration(new File(Launch.minecraftHome, "config/hodgepodge.cfg"));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.mitchej123.hodgepodge.core.util;

import gnu.trove.strategy.HashingStrategy;
import net.minecraft.item.ItemStack;

/*
* Strategy to make ItemStacks Hashable
* - Taken from https://github.com/hilburn/AdvancedSystemsManager/blob/master/src/main/java/advancedsystemsmanager/flow/execution/buffers/maps/ItemStackHashingStrategy.java
* under the the DBaJ (Don't Be a Jerk) non-commercial care-free license.
* (c) hilburn
*/
public class ItemStackHashingStrategy implements HashingStrategy<ItemStack> {
public static final ItemStackHashingStrategy INSTANCE = new ItemStackHashingStrategy();

@Override
public int computeHashCode(ItemStack stack) {
return stack.getItem().hashCode() ^ stack.getItemDamage() ^ (stack.hasTagCompound() ? stack.stackTagCompound.hashCode() : 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it give better distribution if you e.g. multiply item damage by some large enough prime here? It's not that expensive

}

@Override
public boolean equals(ItemStack stack1, ItemStack stack2) {
return stack1 != null && stack1.isItemEqual(stack2) && ItemStack.areItemStackTagsEqual(stack1, stack2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.mitchej123.hodgepodge.mixins.fixUrlDetection;

import net.minecraft.event.ClickEvent;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.IChatComponent;
import net.minecraftforge.common.ForgeHooks;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Mixin(ForgeHooks.class)
public class MixinForgeHooks {
private static final Pattern URL_PATTERN = Pattern.compile(
// schema ipv4 OR namespace port path ends
// |-----------------| |-------------------------| |-------------------------| |---------| |--| |---------------|
"((?:[a-z0-9]{2,}:\\/\\/)?(?:(?:[0-9]{1,3}\\.){3}[0-9]{1,3}|(?:[-\\w_]{1,}\\.[a-z]{2,}?))(?::[0-9]{1,5})?.*?(?=[!\"\u00A7 \n]|$))",
Pattern.CASE_INSENSITIVE);

/**
* @author LexManos
* Backported from https://github.com/MinecraftForge/MinecraftForge/commit/5b28eb53e8623448b1c2bdb46b8924662e690995
*/
@Overwrite
public static IChatComponent newChatWithLinks(String string) {
// Includes ipv4 and domain pattern
// Matches an ip (xx.xxx.xx.xxx) or a domain (something.com) with or
// without a protocol or path.
IChatComponent ichat = new ChatComponentText("");
Matcher matcher = MixinForgeHooks.URL_PATTERN.matcher(string);
int lastEnd = 0;

// Find all urls
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();

// Append the previous left overs.
ichat.appendText(string.substring(lastEnd, start));
lastEnd = end;
String url = string.substring(start, end);
IChatComponent link = new ChatComponentText(url);

try {
// Add schema so client doesn't crash.
if ((new URI(url)).getScheme() == null)
url = "http://" + url;
}
catch (URISyntaxException e) {
// Bad syntax bail out!
ichat.appendText(url);
continue;
}

// Set the click event and append the link.
ClickEvent click = new ClickEvent(ClickEvent.Action.OPEN_URL, url);
link.getChatStyle().setChatClickEvent(click);
ichat.appendSibling(link);
}

// Append the rest of the message.
ichat.appendText(string.substring(lastEnd));
return ichat;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.mitchej123.hodgepodge.mixins.speedupVanillaFurnace;

import com.mitchej123.hodgepodge.core.HodgepodgeMixinPlugin;
import com.mitchej123.hodgepodge.core.util.ItemStackHashingStrategy;
import gnu.trove.map.hash.TCustomHashMap;
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.launchwrapper.Launch;
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.Redirect;

import java.lang.reflect.Field;
import java.util.Map;

@Mixin(FurnaceRecipes.class)
public abstract class MixinFurnaceRecipes {
/*
* Speed up FurnaceRecipes.getSmeltingResult by:
* 1) Hijacking the constructor here to recreate the lists with a replacement hash map and an ItemStack hashing strategy
* 2) No longer looping over every. single. recipe. in the list and using the .get()
*/
@Shadow private Map smeltingList;
@Shadow private Map experienceList;
@Shadow abstract boolean func_151397_a(ItemStack p_151397_1_, ItemStack p_151397_2_);

@Redirect(
at=@At(
value="INVOKE",
target="Lnet/minecraft/item/crafting/FurnaceRecipes;func_151393_a(Lnet/minecraft/block/Block;Lnet/minecraft/item/ItemStack;F)V",
ordinal = 0
),
method="Lnet/minecraft/item/crafting/FurnaceRecipes;<init>()V"
)
private void doStuff(FurnaceRecipes instance, Block p_151393_1_, ItemStack p_151393_2_, float p_151393_3_) throws NoSuchFieldException, IllegalAccessException {
HodgepodgeMixinPlugin.log.info("Swapping out smeltingList and experienceList in FurnaceRecipes");

// Hack into the first call in the constructor and replace the lists with a new hashmap that has an ItemStackMi hashing strategy
boolean devEnv = (Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment");
try {
Class<?> clazz = Class.forName("net.minecraft.item.crafting.FurnaceRecipes");

Field smeltingList = clazz.getDeclaredField(devEnv ? "smeltingList" : "field_77604_b");
smeltingList.setAccessible(true);
smeltingList.set(instance, new TCustomHashMap<ItemStack, ItemStack>(ItemStackHashingStrategy.INSTANCE));

Field experienceList = clazz.getDeclaredField(devEnv ? "experienceList" : "field_77605_c");
experienceList.setAccessible(true);
experienceList.set(instance, new TCustomHashMap<ItemStack, Float>(ItemStackHashingStrategy.INSTANCE));

HodgepodgeMixinPlugin.log.info("Successfully swapped the lists in FurnaceRecipes");

} catch (ClassNotFoundException | IllegalAccessException e) {
e.printStackTrace();
}
instance.func_151393_a(p_151393_1_, p_151393_2_, p_151393_3_);
}
/**
* @author mitchej123
* Inspired by later versions of forge
*/
@SuppressWarnings("unchecked")
@Overwrite(remap = false)
public void func_151394_a /* addSmeltingRecipe */ (ItemStack input, ItemStack stack, float experience) {
if (getSmeltingResult(input) != null) {
HodgepodgeMixinPlugin.log.info("Ignored smelting recipe with conflicting input: {} = {}", input, stack); return;
} else {
this.smeltingList.put(input, stack);
this.experienceList.put(stack, experience);
}
}

/**
* @author mitchej123
* Significantly Faster
*/
@Overwrite
public ItemStack getSmeltingResult(ItemStack stack) {
return (ItemStack) this.smeltingList.get(stack);
}

/**
* @author mitchej123
* Significantly Faster
*/
@Overwrite(remap = false)
public float func_151398_b /* getSmeltingExperience */ (ItemStack stack) {
float exp = stack.getItem().getSmeltingExperience(stack);
if (exp == -1) {
exp = (Float) (this.experienceList.get(stack));
}
return exp;
}

}