Replace reflective registry replacement with minor mixined method (#24)

This commit is contained in:
ah-OOG-ah authored and GitHub committed 2025-04-30 08:12:47 +02:00
1 parent 63eb75461c
commit 73ff6ff8a5
16 files changed
+178 -133

No files matched your search

+1 -1
View File
@@ -68,7 +68,7 @@ The project is under the All Rights Reserved license, which means that redistrib
This rule only applies to the source code, assets are copyrighted and belong to their respective owners (music to qwertygiy, all other assets to me), and cannot be used in other projects without the owner's permission!
If you find a handy method or even an entire class (such as BlockReplaceHelper), I don't mind if you use it in your project (don't copy everything you see though, that's not how you learn to mod). Giving credit is only required if your project has publicly visible source, in that case use javadoc and link back to the original source.
If you find a handy method or even an entire class (such as ~~BlockReplaceHelper~~ NH deleted this class because it was an awful hack), I don't mind if you use it in your project (don't copy everything you see though, that's not how you learn to mod). Giving credit is only required if your project has publicly visible source, in that case use javadoc and link back to the original source.
### I want to modify something in HEE
-2
View File
@@ -1,5 +1,3 @@
//version: 1707058017
plugins {
id 'com.gtnewhorizons.gtnhconvention'
}
+2 -2
View File
@@ -1,8 +1,8 @@
// Add your dependencies here
dependencies {
implementation('com.github.GTNewHorizons:GTNHLib:0.6.15:dev')
implementation('com.github.GTNewHorizons:NotEnoughItems:2.7.30-GTNH:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.6.21:dev')
implementation('com.github.GTNewHorizons:NotEnoughItems:2.7.40-GTNH:dev')
compileOnly('thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev')
compileOnly('com.github.GTNewHorizons:Mobs-Info:0.5.2-GTNH:dev')
+6 -6
View File
@@ -14,7 +14,7 @@ modId = HardcoreEnderExpansion
modGroup = chylex.hee
# Whether to use modGroup as the maven publishing group.
# Due to a history of using JitPack, the default is com.github.GTNewHorizons for all mods.
# When false, com.github.GTNewHorizons is used.
useModGroupForPublishing = false
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
@@ -41,11 +41,11 @@ developmentEnvironmentUserName = "Developer"
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
# See https://github.com/bsideup/jabel for details on how this works.
enableModernJavaSyntax = false
enableModernJavaSyntax = true
# Enables injecting missing generics into the decompiled source code for a better coding experience.
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
enableGenericInjection = false
enableGenericInjection = true
# Generate a class with a String field for the mod version named as defined below.
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
@@ -83,7 +83,7 @@ apiPackage =
accessTransformersFile =
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
usesMixins = false
usesMixins = true
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
@@ -97,12 +97,12 @@ usesMixinDebug = false
mixinPlugin =
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
mixinsPackage =
mixinsPackage = mixins
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
# This parameter is for legacy compatibility only
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
coreModClass =
coreModClass = HEECore
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.37'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.38'
}
+47
View File
@@ -0,0 +1,47 @@
package chylex.hee;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.gtnewhorizon.gtnhlib.mixin.IMixins;
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
import chylex.hee.mixins.Mixins;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
public class HEECore implements IFMLLoadingPlugin, IEarlyMixinLoader {
@Override
public String getMixinConfig() {
return "mixins.HardcoreEnderExpansion.early.json";
}
@Override
public List<String> getMixins(Set<String> loadedCoreMods) {
return IMixins.getEarlyMixins(Mixins.class, loadedCoreMods);
}
@Override
public String[] getASMTransformerClass() {
return null;
}
@Override
public String getModContainerClass() {
return null;
}
@Override
public String getSetupClass() {
return null;
}
@Override
public void injectData(Map<String, Object> data) {}
@Override
public String getAccessTransformerClass() {
return null;
}
}
@@ -1,108 +0,0 @@
package chylex.hee.block;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.ObjectIntIdentityMap;
import com.gtnewhorizon.gtnhlib.reflect.Fields;
import chylex.hee.system.logging.Log;
import chylex.hee.system.logging.Stopwatch;
import chylex.hee.system.util.ReflectionUtils;
import cpw.mods.fml.common.registry.FMLControlledNamespacedRegistry;
import cpw.mods.fml.common.registry.GameData;
public class BlockReplaceHelper {
public static void replaceBlock(Block toReplace, Block replacement) {
Stopwatch.time("BlockReplace");
Class<?>[] classTest = new Class<?>[4];
Exception exception = null;
try {
final Fields.ClassFields blocksFields = Fields.ofClass(Blocks.class);
for (Field blockField : Blocks.class.getFields()) {
if (Block.class.isAssignableFrom(blockField.getType())) {
Block block = (Block) blockField.get(null);
if (block == toReplace) {
final Fields.ClassFields.Field fieldAccessor = blocksFields
.getUntypedField(Fields.LookupType.PUBLIC, blockField.getName());
String registryName = Block.blockRegistry.getNameForObject(block);
int id = Block.getIdFromBlock(block);
Log.debug("Replacing block - $0/$1", id, registryName);
ReflectionUtils.setFieldValue(
((ItemBlock) Item.getItemFromBlock(block)),
"field_150939_a",
replacement);
FMLControlledNamespacedRegistry<Block> registryBlocks = GameData.getBlockRegistry();
Log.debug("Got BlockRegistry.");
Map registryObjects = ReflectionUtils.getFieldValue(registryBlocks, "registryObjects");
Log.debug("Got registryObjects.");
ObjectIntIdentityMap underlyingIntegerMap = ReflectionUtils
.getFieldValue(registryBlocks, "underlyingIntegerMap");
Log.debug("Got underlyingIntegerMap.");
registryObjects.put(registryName, replacement);
Log.debug(
"Put " + replacement.getUnlocalizedName()
+ " in registryObjects with key: "
+ registryName);
underlyingIntegerMap.func_148746_a(replacement, id); // OBFUSCATED put object
Log.debug("OBFUSCATED put object - underlyingIntegerMap");
ReflectionUtils.setFieldValue(registryBlocks, "registryObjects", registryObjects);
Log.debug("Set new value for registryObjects: registryObjects. For object registryBlocks.");
ReflectionUtils.setFieldValue(registryBlocks, "underlyingIntegerMap", underlyingIntegerMap);
Log.debug(
"Set new value for underlyingIntegerMap: underlyingIntegerMap. For object registryBlocks.");
Log.debug("Made " + blockField.getName() + " accessible.");
fieldAccessor.setValue(null, replacement);
Log.debug("Set " + blockField.getName() + " to " + replacement.getUnlocalizedName() + ".");
Method delegateNameMethod = replacement.delegate.getClass()
.getDeclaredMethod("setName", String.class);
delegateNameMethod.setAccessible(true);
Log.debug("Made " + delegateNameMethod.getName() + " accessible.");
delegateNameMethod.invoke(replacement.delegate, toReplace.delegate.name());
Log.debug("Invoked " + delegateNameMethod.getName() + ".");
classTest[0] = blockField.get(null).getClass();
classTest[1] = Block.blockRegistry.getObjectById(id).getClass();
classTest[2] = ((ItemBlock) Item.getItemFromBlock(replacement)).field_150939_a.getClass();
}
}
}
} catch (Exception e) {
exception = e;
}
Stopwatch.finish("BlockReplace");
Log.debug("Check field: $0", classTest[0]);
Log.debug("Check block registry: $0", classTest[1]);
Log.debug("Check item: $0", classTest[2]);
if (classTest[0] != classTest[1] || classTest[0] != classTest[2] || classTest[0] == null) {
throw new RuntimeException(
"HardcoreEnderExpansion was unable to replace block " + toReplace.getUnlocalizedName()
+ "! Debug info to report: "
+ classTest[0]
+ ","
+ classTest[1]
+ ","
+ classTest[2],
exception);
}
}
}
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import net.minecraft.block.Block;
import net.minecraft.entity.item.EntityFallingBlock;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.world.World;
@@ -104,9 +105,9 @@ public class EntityBlockTempleDragonEgg extends EntityFallingBlock {
}
if (deltaY > 6D) {
for (EntityPlayerMP player : new ArrayList<EntityPlayerMP>(worldObj.playerEntities)) {
for (EntityPlayer player : new ArrayList<>(worldObj.playerEntities)) {
if (player.ridingEntity != null) player.mountEntity(null);
DragonUtil.teleportToOverworld(player);
DragonUtil.teleportToOverworld((EntityPlayerMP) player);
}
TempleEvents.destroyWorld();
@@ -16,7 +16,6 @@ import net.minecraft.entity.item.EntityTNTPrimed;
import net.minecraft.entity.monster.EntityEnderman;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
@@ -755,9 +754,9 @@ public class EntityMobHomelandEnderman extends EntityMob implements IEndermanRen
protected Entity findPlayerToAttack() {
if (worldObj.isRemote) return null;
List<EntityPlayerMP> players = worldObj.playerEntities;
List<EntityPlayer> players = worldObj.playerEntities;
for (EntityPlayerMP player : players) {
for (EntityPlayer player : players) {
if (!player.capabilities.disableDamage && getDistanceSqToEntity(player) <= 4096D) {
if (isPlayerStaringIntoEyes(player)) {
if (!shouldActHostile(player) && teleportRandomly(10D)) return null;
@@ -26,7 +26,6 @@ import chylex.hee.block.BlockCustomSpawner;
import chylex.hee.block.BlockDeathFlower;
import chylex.hee.block.BlockDeathFlowerPot;
import chylex.hee.block.BlockDecompositionTable;
import chylex.hee.block.BlockDragonEggCustom;
import chylex.hee.block.BlockDungeonPuzzle;
import chylex.hee.block.BlockEndPowderOre;
import chylex.hee.block.BlockEnderGoo;
@@ -48,7 +47,6 @@ import chylex.hee.block.BlockObsidianSpecial;
import chylex.hee.block.BlockPersegrit;
import chylex.hee.block.BlockRavagedBrick;
import chylex.hee.block.BlockRavagedBrickSmooth;
import chylex.hee.block.BlockReplaceHelper;
import chylex.hee.block.BlockSpecialEffects;
import chylex.hee.block.BlockSphalerite;
import chylex.hee.block.BlockSpookyLeaves;
@@ -426,8 +424,6 @@ public final class BlockList {
}
public static void registerBlocks() {
BlockReplaceHelper.replaceBlock(Blocks.dragon_egg, new BlockDragonEggCustom());
for (Entry<String, Block> entry : BlockList.blocks.entrySet()) {
GameRegistryUtil.registerBlock(entry.getValue(), entry.getKey(), itemBlocks.get(entry.getKey()));
}
@@ -116,11 +116,11 @@ public final class TempleEvents {
if (world == null) setStage(DestroyStage.DELETE);
else if (world.playerEntities.isEmpty()) setStage(DestroyStage.UNLOAD);
else {
List<EntityPlayerMP> players = new ArrayList<>(world.playerEntities);
List<EntityPlayer> players = new ArrayList<>(world.playerEntities);
for (EntityPlayerMP player : players) {
for (EntityPlayer player : players) {
if (player.ridingEntity != null) player.mountEntity(null);
DragonUtil.teleportToOverworld(player);
DragonUtil.teleportToOverworld((EntityPlayerMP) player);
}
}
} else if (stage == DestroyStage.UNLOAD) {
@@ -0,0 +1,70 @@
package chylex.hee.mixins;
import static com.gtnewhorizon.gtnhlib.mixin.TargetedMod.VANILLA;
import java.util.List;
import java.util.function.Supplier;
import com.gtnewhorizon.gtnhlib.mixin.IMixins;
import com.gtnewhorizon.gtnhlib.mixin.ITargetedMod;
import com.gtnewhorizon.gtnhlib.mixin.MixinBuilder;
import com.gtnewhorizon.gtnhlib.mixin.Phase;
import com.gtnewhorizon.gtnhlib.mixin.Side;
public enum Mixins implements IMixins {
REPLACE_DRAGON_EGG(new MixinBuilder("Replaces the dragon egg").setApplyIf(() -> true)
.addMixinClasses("minecraft.MixinBlock").addTargetedMod(VANILLA).setSide(Side.BOTH).setPhase(Phase.EARLY));
private final List<String> mixinClasses;
private final List<ITargetedMod> targetedMods;
private final List<ITargetedMod> excludedMods;
private final Supplier<Boolean> applyIf;
private final Phase phase;
private final Side side;
Mixins(MixinBuilder builder) {
mixinClasses = builder.mixinClasses;
targetedMods = builder.targetedMods;
excludedMods = builder.excludedMods;
applyIf = builder.applyIf;
phase = builder.phase;
side = builder.side;
if (mixinClasses.isEmpty()) throw new RuntimeException("No mixin class specified for Mixin : " + name());
if (targetedMods.isEmpty()) throw new RuntimeException("No targeted mods specified for Mixin : " + name());
if (applyIf == null) throw new RuntimeException("No ApplyIf function specified for Mixin : " + name());
if (phase == null) throw new RuntimeException("No Phase specified for Mixin : " + name());
if (side == null) throw new RuntimeException("No Side function specified for Mixin : " + name());
}
@Override
public List<String> getMixinClasses() {
return mixinClasses;
}
@Override
public Supplier<Boolean> getApplyIf() {
return applyIf;
}
@Override
public Phase getPhase() {
return phase;
}
@Override
public Side getSide() {
return side;
}
@Override
public List<ITargetedMod> getTargetedMods() {
return targetedMods;
}
@Override
public List<ITargetedMod> getExcludedMods() {
return excludedMods;
}
}
@@ -0,0 +1,26 @@
package chylex.hee.mixins.early.minecraft;
import net.minecraft.block.Block;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.Slice;
import chylex.hee.block.BlockDragonEggCustom;
@Mixin(Block.class)
public class MixinBlock {
@ModifyArg(
method = "registerBlocks",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/util/RegistryNamespaced;addObject(ILjava/lang/String;Ljava/lang/Object;)V"),
slice = @Slice(
from = @At(value = "CONSTANT", args = "intValue=122"),
to = @At(value = "CONSTANT", args = "intValue=123")))
private static Object hee$replaceDragonEgg(Object block) {
return new BlockDragonEggCustom();
}
}
@@ -5,6 +5,7 @@ import java.util.Collections;
import java.util.List;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.ServerConfigurationManager;
import net.minecraftforge.common.ForgeHooks;
@@ -53,7 +54,7 @@ public class NotificationCommonProxy {
if (manager == null) return;
boolean delivered = false;
List<EntityPlayer> players = manager.playerEntityList;
List<EntityPlayerMP> players = manager.playerEntityList;
for (EntityPlayer player : players) {
if (manager.func_152596_g(player.getGameProfile())) {
@@ -0,0 +1,8 @@
{
"required": true,
"minVersion": "0.8.3-GTNH",
"package": "chylex.hee.mixins.early",
"refmap": "mixins.HardcoreEnderExpansion.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8"
}
@@ -0,0 +1,7 @@
{
"required": true,
"minVersion": "0.8.3-GTNH",
"refmap": "mixins.HardcoreEnderExpansion.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8"
}