Skip to content

Commit

Permalink
Vanilla Crash & Furnace Speedup
Browse files Browse the repository at this point in the history
1) Backports a fix for URL parsing from MinecraftForge/MinecraftForge#1712
2) Makes FurnaceRecipe significantly faster by using a HashMap w/ ItemStackHashingStrategy
  • Loading branch information
mitchej123 committed Dec 11, 2021
1 parent eafe6b9 commit 38733dc
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,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
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ 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;
Expand Down Expand Up @@ -63,6 +65,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,6 +78,7 @@ 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();
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);
}

@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;
}

}

0 comments on commit 38733dc

Please sign in to comment.