-
-
Save ShetiPhian/a00a9e8cb6e1e5cb6ec6deeb77400e68 to your computer and use it in GitHub Desktop.
ShetiPhian-ASM Source and Explanation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Q: What does this do? | |
A: Adds a hook to Entity.createRunningParticles() that enabled me to override the run particles of my blocks. | |
Q: Where is it being used? | |
A: | |
- Platforms:platform uses it to change the particle texture into the material the platform is made from, otherwise it will always be oak. | |
- Terraqueous:pergola uses it to colorize the particles from white to the color of the pergola. | |
- Terraqueous:flowerpot uses it to colorize the particles, also used on the planter to texture the particles based on the block inside. | |
Q: Why is this a coremod? | |
A: I tried to get this into Forge. | |
They already add Block.addLandingEffects and Block.addHitEffects that cover falling, place and break, only run particles can not be controlled. | |
I opened a pull request Feb/6/2016 to add Block.addRunningEffects. | |
That pull was kept upto date and conflict free until I closed it May/24/2016 as Forge migrated to Minecraft 1.9. | |
I had opened a 1.9 verison of the pull request on May/10/2016, this was monitored for another month to make sure it stayed conflict free. | |
Eventually giving up I took the time to learn enough ASM to create ShetiPhian-ASM. | |
If I was to attempt to get the pull accepted again, I'd do it slightly different. | |
I'd still add the block patch as is: | |
--- | |
/** | |
* Allows a block to override the standard Entity.createRunningParticles particles. | |
* | |
* @param state State at the specific world/pos | |
* @param world The current world | |
* @param pos Position of the block that the entity is running on. | |
* @param entity The entity that is running on the block. | |
* @return True to prevent vanilla running particles form spawning. | |
*/ | |
public boolean addRunningEffects(IBlockState state, World world, BlockPos pos, Entity entity) | |
{ | |
return false; | |
} | |
--- | |
The Entity.createRunningParticles patch would be a single line at the very top pointing to the ForgeHooksClient class | |
--- | |
protected void createRunningParticles() | |
{ | |
if (ForgeHooksClient.createRunningParticles(this)) return; | |
<< Rest of the methods code here, unaltered >> | |
} | |
--- | |
My Hooks method would be added to ForgeHooksClient with alterations (dropping the interface, and inverting boolean logic) | |
--- | |
public static boolean createRunningParticles(Entity entity) | |
{ | |
int x = MathHelper.floor(entity.posX); | |
int y = MathHelper.floor(entity.posY - 0.0625D); // Larger values skip thin blocks, and use the block beneath. | |
int z = MathHelper.floor(entity.posZ); | |
BlockPos pos = new BlockPos(x, y, z); | |
if (entity.getEntityWorld().isAirBlock(pos)) | |
{ | |
pos = new BlockPos(x, MathHelper.floor(entity.posY - 0.2D), z); | |
} | |
IBlockState state = entity.getEntityWorld().getBlockState(pos); | |
return state.getBlock().addRunningEffects(state, entity.getEntityWorld(), pos, entity); | |
} | |
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package shetiphian.asm; | |
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.Type; | |
import org.objectweb.asm.tree.AbstractInsnNode; | |
import org.objectweb.asm.tree.ClassNode; | |
import org.objectweb.asm.tree.InsnList; | |
import org.objectweb.asm.tree.JumpInsnNode; | |
import org.objectweb.asm.tree.LabelNode; | |
import org.objectweb.asm.tree.MethodInsnNode; | |
import org.objectweb.asm.tree.MethodNode; | |
import org.objectweb.asm.tree.VarInsnNode; | |
import static org.objectweb.asm.Opcodes.ALOAD; | |
import static org.objectweb.asm.Opcodes.GETFIELD; | |
import static org.objectweb.asm.Opcodes.IFEQ; | |
import static org.objectweb.asm.Opcodes.INVOKESTATIC; | |
import static org.objectweb.asm.Opcodes.RETURN; | |
public class ClassTransformer implements IClassTransformer | |
{ | |
protected final Logger log = LogManager.getLogger("ShetiPhian-ASM"); | |
@Override | |
public byte[] transform(String name, String transformedName, byte[] basicClass) | |
{ | |
if (transformedName.equals("net.minecraft.entity.Entity")) { | |
return transform(0, basicClass); | |
} | |
return basicClass; | |
} | |
private byte[] transform(int index, byte[] basicClass) | |
{ | |
try { | |
ClassReader reader = new ClassReader(basicClass); | |
ClassNode node = new ClassNode(); | |
reader.accept(node, 0); | |
boolean transformed = false; | |
switch (index) { | |
case 0: | |
log.info("Attempting: Injection of Run Particle Override into Entity.createRunningParticles"); | |
transformed = transformEntity(node); | |
break; | |
} | |
if (transformed) { | |
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); | |
node.accept(writer); | |
return writer.toByteArray(); | |
} | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
return basicClass; | |
} | |
private boolean transformEntity(ClassNode node) | |
{ | |
final String ENTITY_PARTICLE = TweakPlugin.runtimeDeobfEnabled ? "func_174808_Z" : "createRunningParticles"; | |
final String ENTITY_PARTICLE_DESC = TweakPlugin.runtimeDeobfEnabled ? "()V" : "()V"; | |
final String HOOK = TweakPlugin.runtimeDeobfEnabled ? "(Lnet/minecraft/entity/Entity;)Z" : "(Lnet/minecraft/entity/Entity;)Z"; | |
log.info("Searching for: Entity.createRunningParticles (" + ENTITY_PARTICLE + ")"); | |
for (MethodNode method : node.methods) { | |
if (method.name.equals(ENTITY_PARTICLE) && method.desc.equals(ENTITY_PARTICLE_DESC)) { | |
log.info("Found Method: Entity.createRunningParticles"); | |
AbstractInsnNode targetNode = null; | |
AbstractInsnNode popNode = null; | |
for (AbstractInsnNode instruction : method.instructions.toArray()) { | |
if (instruction.getOpcode() == ALOAD) { | |
if (targetNode == null && ((VarInsnNode)instruction).var == 0 && instruction.getNext().getOpcode() == GETFIELD) { | |
targetNode = instruction; | |
} | |
} | |
if (instruction.getOpcode() == RETURN) { | |
popNode = instruction; | |
} | |
} | |
if (targetNode != null && popNode != null) { | |
log.info("Injecting: Run Particle Override"); | |
LabelNode newLabelNode = new LabelNode(); | |
InsnList toInsert = new InsnList(); | |
toInsert.add(new VarInsnNode(ALOAD, 0)); | |
toInsert.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(Hooks.class), "entityRunParticles", HOOK, false)); | |
toInsert.add(new JumpInsnNode(IFEQ, newLabelNode)); | |
method.instructions.insertBefore(targetNode, toInsert); | |
method.instructions.insertBefore(popNode, newLabelNode); | |
return true; | |
} | |
log.info("Injection Failed"); | |
} | |
} | |
return false; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package shetiphian.asm; | |
import net.minecraft.block.state.IBlockState; | |
import net.minecraft.entity.Entity; | |
import net.minecraft.util.math.BlockPos; | |
import net.minecraft.util.math.MathHelper; | |
import shetiphian.core.common.IParticleOverride; | |
public class Hooks | |
{ | |
public static boolean entityRunParticles(Entity entity) | |
{ | |
int x = MathHelper.floor(entity.posX); | |
int y = MathHelper.floor(entity.posY - 0.0625D); | |
int z = MathHelper.floor(entity.posZ); | |
BlockPos pos = new BlockPos(x, y, z); | |
if (entity.getEntityWorld().isAirBlock(pos)) { | |
pos = new BlockPos(x, MathHelper.floor(entity.posY - 0.20000000298023224D), z); | |
} | |
IBlockState state = entity.getEntityWorld().getBlockState(pos); | |
if (state.getBlock() instanceof IParticleOverride) { | |
return !((IParticleOverride)state.getBlock()).overrideRunningEffects(entity.getEntityWorld(), pos, state, entity); | |
} | |
return true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package shetiphian.asm; | |
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; | |
import java.util.Map; | |
@IFMLLoadingPlugin.Name(value = "ShetiPhian-ASM") | |
@IFMLLoadingPlugin.MCVersion(value = "1.12") | |
@IFMLLoadingPlugin.DependsOn(value = "required-after:shetiphiancore") | |
@IFMLLoadingPlugin.TransformerExclusions(value = "shetiphian.asm.") | |
@IFMLLoadingPlugin.SortingIndex(value = 1001) // > 1000 = srg names | |
public class TweakPlugin implements IFMLLoadingPlugin | |
{ | |
static boolean runtimeDeobfEnabled = false; | |
@Override | |
public String[] getASMTransformerClass() | |
{ | |
return new String[] { "shetiphian.asm.ClassTransformer" }; | |
} | |
@Override | |
public String getModContainerClass() | |
{ | |
return null; | |
} | |
@Override | |
public String getSetupClass() | |
{ | |
return null; | |
} | |
@Override | |
public void injectData(Map<String, Object> data) | |
{ | |
runtimeDeobfEnabled = (Boolean)data.get("runtimeDeobfuscationEnabled"); | |
} | |
@Override | |
public String getAccessTransformerClass() | |
{ | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment