Skip to content

Commit

Permalink
JAFFA patch
Browse files Browse the repository at this point in the history
A set of three patches to JAFF which together serve to implement vanilla spawning mechanics.
  * Removes JAFF's own spawn loop
  * Register vanilla spawns and placement types
  * Implement EntityFish#isNotColliding, overriding EntityAnimal's implementation which prevents spawning in water.
  • Loading branch information
sam-kirby committed May 16, 2020
1 parent 36f0000 commit f3d08ed
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 2 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ Patches Galacticraft Core. In the method BlockBasic#getPickBlock, Galacticraft r
rather than using the state passed in to the method. This leaves it incompatible with Scannable which does not pass in
the BlockPos when calling Block#getPickBlock. This patch simply removes the call to World#getBlockState, replacing it
with the state from the argument.

#### Just A Few Fish Augmentation (JAFFA)
A set of three patches to JAFF which together serve to implement vanilla spawning mechanics.
* Removes JAFF's own spawn loop
* Register vanilla spawns and placement types
* Implement EntityFish#isNotColliding, overriding EntityAnimal's implementation which prevents spawning in water.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ dependencies {
}

compile fg.deobf('curse.maven:astralsorcery-1.0.23:2920254')
compile fg.deobf('curse.maven:jaff-1.7:2448283')
}

mixin {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version_base = 1.2
version_base = 1.3

# 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.
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/tv/darkosto/sevpatches/core/FishHook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package tv.darkosto.sevpatches.core;

import com.tmtravlr.jaff.entities.*;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntitySpawnPlacementRegistry;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.world.biome.Biome;
import net.minecraftforge.common.BiomeDictionary;
import net.minecraftforge.fml.common.registry.EntityRegistry;

import java.util.HashSet;
import java.util.Set;

public class FishHook {
public static void registerPlacement() {
SevPatchesLoadingPlugin.LOGGER.info("JAFFA Phase 1");
EntitySpawnPlacementRegistry.setPlacementType(EntityFishCod.class, EntityLiving.SpawnPlacementType.IN_WATER);
EntitySpawnPlacementRegistry.setPlacementType(EntityFishClownfish.class, EntityLiving.SpawnPlacementType.IN_WATER);
EntitySpawnPlacementRegistry.setPlacementType(EntityFishPufferfish.class, EntityLiving.SpawnPlacementType.IN_WATER);
EntitySpawnPlacementRegistry.setPlacementType(EntityFishSalmon.class, EntityLiving.SpawnPlacementType.IN_WATER);
}

public static void registerSpawns() {
SevPatchesLoadingPlugin.LOGGER.info("JAFFA Phase 2");

Set<Biome> waterBiomes = new HashSet<>();
waterBiomes.addAll(BiomeDictionary.getBiomes(BiomeDictionary.Type.RIVER));
waterBiomes.addAll(BiomeDictionary.getBiomes(BiomeDictionary.Type.SWAMP));
waterBiomes.addAll(BiomeDictionary.getBiomes(BiomeDictionary.Type.OCEAN));

Set<Biome> landWaterBiomes = new HashSet<>();
landWaterBiomes.addAll(BiomeDictionary.getBiomes(BiomeDictionary.Type.RIVER));
landWaterBiomes.addAll(BiomeDictionary.getBiomes(BiomeDictionary.Type.SWAMP));

EntityRegistry.addSpawn(EntityFishCod.class, 40, 4, 4, EnumCreatureType.WATER_CREATURE, waterBiomes.toArray(new Biome[0]));
EntityRegistry.addSpawn(EntityFishClownfish.class, 12, 4, 4, EnumCreatureType.WATER_CREATURE, BiomeDictionary.getBiomes(BiomeDictionary.Type.OCEAN).toArray(new Biome[0]));
EntityRegistry.addSpawn(EntityFishPufferfish.class, 8, 1, 1, EnumCreatureType.WATER_CREATURE, BiomeDictionary.getBiomes(BiomeDictionary.Type.OCEAN).toArray(new Biome[0]));
EntityRegistry.addSpawn(EntityFishSalmon.class, 4, 4, 4, EnumCreatureType.WATER_CREATURE, BiomeDictionary.getBiomes(BiomeDictionary.Type.OCEAN).toArray(new Biome[0]));
EntityRegistry.addSpawn(EntityFishSalmon.class, 40, 4, 4, EnumCreatureType.WATER_CREATURE, landWaterBiomes.toArray(new Biome[0]));

SevPatchesLoadingPlugin.LOGGER.info(EntitySpawnPlacementRegistry.getPlacementForEntity(EntityFishCod.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public class SevPatchesLoadingPlugin implements IFMLLoadingPlugin {

public static String GET_BLOCK_STATE;

public static String ENTITY_WORLD;
public static String ENTITY_IS_NOT_COLLIDING;
public static String ENTITY_GET_CAN_SPAWN_HERE;
public static String GET_ENTITY_BOUNDING_BOX;
public static String CHECK_NO_ENTITY_COLLISION;

public SevPatchesLoadingPlugin() {
LOGGER.info("setting up mixin environment");
MixinBootstrap.init();
Expand Down Expand Up @@ -54,6 +60,12 @@ public void injectData(Map<String, Object> data) {
SevPatchesLoadingPlugin.SET_INT = dev ? "setInteger" : "func_74768_a";

SevPatchesLoadingPlugin.GET_BLOCK_STATE = dev ? "getBlockState" : "func_180495_p";

SevPatchesLoadingPlugin.ENTITY_WORLD = dev ? "world" : "field_70170_p";
SevPatchesLoadingPlugin.ENTITY_IS_NOT_COLLIDING = dev ? "isNotColliding" : "func_70058_J";
SevPatchesLoadingPlugin.ENTITY_GET_CAN_SPAWN_HERE = dev ? "getCanSpawnHere" : "func_70601_bi";
SevPatchesLoadingPlugin.GET_ENTITY_BOUNDING_BOX = dev ? "getEntityBoundingBox" : "func_174813_aQ";
SevPatchesLoadingPlugin.CHECK_NO_ENTITY_COLLISION = dev ? "checkNoEntityCollision" : "func_72917_a";
}

@Override
Expand Down
152 changes: 152 additions & 0 deletions src/main/java/tv/darkosto/sevpatches/core/SevPatchesTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ public byte[] transform(String name, String transformedName, byte[] basicClass)
return this.amuletTransform(basicClass);
case "micdoodle8.mods.galacticraft.core.blocks.BlockBasic":
return this.galacticraftBlockTransform(basicClass);
case "com.tmtravlr.jaff.JAFFEventHandler":
return this.unnecessaryLagRemover(basicClass);
case "com.tmtravlr.jaff.JAFFMod":
return this.fishLiveInWater(basicClass);
case "com.tmtravlr.jaff.entities.EntityFish":
return this.fishAreFish(basicClass);
default:
return basicClass;
}
Expand All @@ -48,6 +54,152 @@ private void setEventSubPriority(ClassNode input, String targetMethod, String pr
}
}

/**
* Make JAFF fish behave like fish
* The JAFFA patch
*/
private byte[] unnecessaryLagRemover(byte[] basicClass) {
ClassReader classReader = new ClassReader(basicClass);

ClassNode classNode = new ClassNode();
classReader.accept(classNode, 0);

for (MethodNode methodNode : classNode.methods) {
if (!methodNode.name.equals("onWorldTick")) continue;
for (AnnotationNode annotationNode : methodNode.visibleAnnotations) {
if (!annotationNode.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/SubscribeEvent;"))
continue;

methodNode.visibleAnnotations.remove(annotationNode);
SevPatchesLoadingPlugin.LOGGER.info("Disabling custom spawn logic in JAFF");
break;
}
}

ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
return classWriter.toByteArray();
}

private byte[] fishLiveInWater(byte[] basicClass) {
ClassReader classReader = new ClassReader(basicClass);

ClassNode classNode = new ClassNode();
classReader.accept(classNode, 0);

MethodNode preInit = null;
MethodNode postInit = null;

for (MethodNode methodNode : classNode.methods) {
if (methodNode.name.equals("preInit")) preInit = methodNode;
if (methodNode.name.equals("postInit")) postInit = methodNode;
}

if (preInit == null || postInit == null) {
SevPatchesLoadingPlugin.LOGGER.warn("Failed to find JAFF init methods");
return basicClass;
}

InsnList callRegisterPlacement = new InsnList();
callRegisterPlacement.add(new MethodInsnNode(
Opcodes.INVOKESTATIC,
"tv/darkosto/sevpatches/core/FishHook",
"registerPlacement",
"()V",
false
));

InsnNode preInitReturn = null;
for (ListIterator<AbstractInsnNode> it = preInit.instructions.iterator(); it.hasNext(); ) {
AbstractInsnNode insnNode = it.next();

if (insnNode.getOpcode() == Opcodes.RETURN) preInitReturn = (InsnNode) insnNode;
}

if (preInitReturn != null)
preInit.instructions.insertBefore(preInitReturn, callRegisterPlacement);

InsnList callRegisterSpawns = new InsnList();
callRegisterSpawns.add(new MethodInsnNode(
Opcodes.INVOKESTATIC,
"tv/darkosto/sevpatches/core/FishHook",
"registerSpawns",
"()V",
false
));

InsnNode postInitReturn = null;
for (ListIterator<AbstractInsnNode> it = postInit.instructions.iterator(); it.hasNext(); ) {
AbstractInsnNode insnNode = it.next();

if (insnNode.getOpcode() == Opcodes.RETURN) postInitReturn = (InsnNode) insnNode;
}

if (postInitReturn != null)
postInit.instructions.insertBefore(postInitReturn, callRegisterSpawns);

ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
return classWriter.toByteArray();
}

private byte[] fishAreFish(byte[] basicClass) {
SevPatchesLoadingPlugin.LOGGER.info("JAFFA patch in progress");

ClassReader classReader = new ClassReader(basicClass);

ClassNode classNode = new ClassNode();
classReader.accept(classNode, 0);

MethodNode isFishNotColliding = new MethodNode(
Opcodes.ACC_PUBLIC,
SevPatchesLoadingPlugin.ENTITY_IS_NOT_COLLIDING,
"()Z",
null,
null
);
InsnList fishyInsns = isFishNotColliding.instructions;
fishyInsns.add(new VarInsnNode(Opcodes.ALOAD, 0));
fishyInsns.add(new FieldInsnNode(
Opcodes.GETFIELD,
"com/tmtravlr/jaff/entities/EntityFish",
SevPatchesLoadingPlugin.ENTITY_WORLD,
"Lnet/minecraft/world/World;"
));
fishyInsns.add(new VarInsnNode(Opcodes.ALOAD, 0));
fishyInsns.add(new MethodInsnNode(
Opcodes.INVOKEVIRTUAL,
"com/tmtravlr/jaff/entities/EntityFish",
SevPatchesLoadingPlugin.GET_ENTITY_BOUNDING_BOX,
"()Lnet/minecraft/util/math/AxisAlignedBB;",
false
));
fishyInsns.add(new VarInsnNode(Opcodes.ALOAD, 0));
fishyInsns.add(new MethodInsnNode(
Opcodes.INVOKEVIRTUAL,
"net/minecraft/world/World",
SevPatchesLoadingPlugin.CHECK_NO_ENTITY_COLLISION,
"(Lnet/minecraft/util/math/AxisAlignedBB;Lnet/minecraft/entity/Entity;)Z",
false
));
fishyInsns.add(new InsnNode(Opcodes.IRETURN));
classNode.methods.add(isFishNotColliding);
SevPatchesLoadingPlugin.LOGGER.info("JAFFA patch: implemented isNotColliding");

for (MethodNode methodNode : classNode.methods) {
if (!methodNode.name.equals(SevPatchesLoadingPlugin.ENTITY_GET_CAN_SPAWN_HERE)) continue;
InsnList replacement = new InsnList();
replacement.add(new InsnNode(Opcodes.ICONST_1));
replacement.add(new InsnNode(Opcodes.IRETURN));
methodNode.instructions = replacement;
SevPatchesLoadingPlugin.LOGGER.info("JAFFA patch: getCanSpawnHere now always true");
}

ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
return classWriter.toByteArray();
}

/**
* DarkPacks/SevTech-Ages#3522
*/
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/mcmod.info
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"modid": "sevpatches",
"name": "SevPatches",
"description": "Consolidated patches for mods that are EOL used in SevTech: Ages",
"version": "1.1",
"version": "1.3",
"mcversion": "1.12.2",
"url": "https://www.curseforge.com/minecraft/mc-mods/sevpatches",
"updateUrl": "",
Expand Down

0 comments on commit f3d08ed

Please sign in to comment.