Skip to content

Commit

Permalink
fix: Use MixinExtras when possible over ThreadLocal (#129)
Browse files Browse the repository at this point in the history
* Fix: Always clear fall event

If the event hasn't been modified, this can temporarily leak an entity and its world, causing memory usage to inflate on the client.

* Port fall event to MixinExtras

This removes the need to store a global variable.

* Use Share local for fromDimHolder

* Use Share local for balmCurrentUseEvent

This could've ideally just had `@Cancellable CallbackInfo` but it appears that this has an older Mixin Extras.

* Use Share local for getGrowthSpeedBlockState, renamed to farmBlock
  • Loading branch information
Ampflower authored Feb 25, 2025
1 parent d70e940 commit d1860f3
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.blay09.mods.balm.mixin;

import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import net.blay09.mods.balm.api.Balm;
import net.blay09.mods.balm.api.block.CustomFarmBlock;
import net.blay09.mods.balm.api.event.CropGrowEvent;
Expand All @@ -20,8 +22,6 @@
@Mixin(CropBlock.class)
public class FabricCropBlockMixin {

private static final ThreadLocal<BlockState> getGrowthSpeedBlockState = new ThreadLocal<>();

@Inject(method = "randomTick(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/util/RandomSource;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z"), cancellable = true)
public void randomTickPreGrow(BlockState state, ServerLevel level, BlockPos pos, RandomSource random, CallbackInfo callbackInfo) {
CropGrowEvent.Pre event = new CropGrowEvent.Pre(level, pos, state);
Expand All @@ -38,17 +38,16 @@ public void randomTickPostGrow(BlockState state, ServerLevel level, BlockPos pos
}



@ModifyVariable(method = "getGrowthSpeed(Lnet/minecraft/world/level/block/Block;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)F", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z", ordinal = 0))
private static BlockState getGrowthSpeedCaptureLocals(BlockState state) {
getGrowthSpeedBlockState.set(state);
private static BlockState getGrowthSpeedCaptureLocals(BlockState state, @Share("farmBlock") LocalRef<BlockState> farmBlock) {
farmBlock.set(state);
return state;
}


@ModifyVariable(method = "getGrowthSpeed(Lnet/minecraft/world/level/block/Block;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)F", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z"), ordinal = 1)
private static float getGrowthSpeed(float g, Block block, BlockGetter blockGetter, BlockPos pos) {
BlockState state = getGrowthSpeedBlockState.get();
private static float getGrowthSpeed(float g, Block block, BlockGetter blockGetter, BlockPos pos, @Share("farmBlock") LocalRef<BlockState> farmBlock) {
BlockState state = farmBlock.get();
if (state.getBlock() instanceof CustomFarmBlock customFarmBlock) {
if (customFarmBlock.canSustainPlant(state, blockGetter, pos, Direction.UP, block)) {
if (customFarmBlock.isFertile(state, blockGetter, pos)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package net.blay09.mods.balm.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import net.blay09.mods.balm.api.Balm;
import net.blay09.mods.balm.api.event.LivingDamageEvent;
import net.blay09.mods.balm.api.event.LivingFallEvent;
import net.blay09.mods.balm.api.event.LivingHealEvent;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
Expand All @@ -16,9 +19,6 @@
@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin {

@Unique
private static final ThreadLocal<LivingFallEvent> balmCurrentFallEvent = new ThreadLocal<>();

@ModifyVariable(method = "actuallyHurt(Lnet/minecraft/world/damagesource/DamageSource;F)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;setAbsorptionAmount(F)V"), index = 2, argsOnly = true)
private float actuallyHurt(float damageAmount, DamageSource damageSource) {
LivingDamageEvent event = new LivingDamageEvent((LivingEntity) (Object) this, damageSource, damageAmount);
Expand All @@ -31,22 +31,22 @@ private float actuallyHurt(float damageAmount, DamageSource damageSource) {
}

@Inject(method = "causeFallDamage(FFLnet/minecraft/world/damagesource/DamageSource;)Z", at = @At("HEAD"), cancellable = true)
private void causeFallDamage(float distance, float damageMultiplier, DamageSource damageSource, CallbackInfoReturnable<Boolean> callbackInfo) {
private void causeFallDamage(float distance, float damageMultiplier, DamageSource damageSource, CallbackInfoReturnable<Boolean> callbackInfo, @Share("eventRef") LocalRef<LivingFallEvent> eventRef) {
LivingFallEvent event = new LivingFallEvent((LivingEntity) (Object) this);
Balm.getEvents().fireEvent(event);
if (event.isCanceled()) {
callbackInfo.setReturnValue(false);
}
balmCurrentFallEvent.set(event);
eventRef.set(event);
}

@Inject(method = "calculateFallDamage(FF)I", at = @At("RETURN"), cancellable = true)
private void calculateFallDamage(float f, float g, CallbackInfoReturnable<Integer> cir) {
LivingFallEvent event = balmCurrentFallEvent.get();
@WrapOperation(method = "causeFallDamage(FFLnet/minecraft/world/damagesource/DamageSource;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;calculateFallDamage(FF)I"))
private int calculateFallDamage(LivingEntity self, float fallDistance, float multiplier, Operation<Integer> operation, @Share("eventRef") LocalRef<LivingFallEvent> eventRef) {
LivingFallEvent event = eventRef.get();
if (event != null && event.getFallDamageOverride() != null) {
cir.setReturnValue(event.getFallDamageOverride().intValue());
balmCurrentFallEvent.set(null);
return event.getFallDamageOverride().intValue();
}
return operation.call(self, fallDistance, multiplier);
}

@ModifyVariable(method = "heal(F)V", at = @At("HEAD"), argsOnly = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.blay09.mods.balm.mixin;

import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import net.blay09.mods.balm.api.Balm;
import net.blay09.mods.balm.api.event.LevelLoadingEvent;
import net.blay09.mods.balm.api.event.client.OpenScreenEvent;
Expand All @@ -13,7 +15,6 @@
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
Expand All @@ -28,9 +29,6 @@ public class MinecraftMixin {
@Shadow
public ClientLevel level;

@Unique
private static final ThreadLocal<UseItemInputEvent> balmCurrentUseEvent = new ThreadLocal<>();

@ModifyVariable(method = "setScreen(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;", opcode = Opcodes.GETFIELD, shift = At.Shift.AFTER), argsOnly = true)
public Screen modifyScreen(Screen screen) {
OpenScreenEvent event = new OpenScreenEvent(screen);
Expand All @@ -39,22 +37,19 @@ public Screen modifyScreen(Screen screen) {
}

@Inject(method = "startUseItem()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;", shift = At.Shift.AFTER), cancellable = true)
public void startUseItem(CallbackInfo callbackInfo) {
public void startUseItem(CallbackInfo callbackInfo, @Share("currentUseEvent") LocalRef<UseItemInputEvent> balmCurrentUseEvent) {
final var event = balmCurrentUseEvent.get();
if (event != null && event.isCanceled()) {
callbackInfo.cancel();
}
balmCurrentUseEvent.remove();
}

@ModifyArg(method = "startUseItem()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getItemInHand(Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/item/ItemStack;"), index = 0)
public InteractionHand modifyHand(InteractionHand hand) {
public InteractionHand modifyHand(InteractionHand hand, @Share("currentUseEvent") LocalRef<UseItemInputEvent> balmCurrentUseEvent) {
if (this.hitResult != null && this.hitResult.getType() != HitResult.Type.MISS) {
UseItemInputEvent event = new UseItemInputEvent(hand);
Balm.getEvents().fireEvent(event);
balmCurrentUseEvent.set(event);
} else {
balmCurrentUseEvent.remove();
}
return hand;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.blay09.mods.balm.mixin;

import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import net.blay09.mods.balm.api.Balm;
import net.blay09.mods.balm.api.event.PlayerChangedDimensionEvent;
import net.blay09.mods.balm.api.event.PlayerOpenMenuEvent;
Expand All @@ -14,7 +16,6 @@
import net.minecraft.world.level.portal.DimensionTransition;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
Expand All @@ -24,23 +25,20 @@
@Mixin(ServerPlayer.class)
public class ServerPlayerMixin {

@Unique
private static final ThreadLocal<ResourceKey<Level>> fromDimHolder = new ThreadLocal<>();

@Inject(method = "openMenu(Lnet/minecraft/world/MenuProvider;)Ljava/util/OptionalInt;", at = @At("RETURN"))
public void openMenu(@Nullable MenuProvider menuProvider, CallbackInfoReturnable<OptionalInt> callbackInfo) {
ServerPlayer player = (ServerPlayer) (Object) this;
Balm.getEvents().fireEvent(new PlayerOpenMenuEvent(player, player.containerMenu));
}

@Inject(method = "changeDimension(Lnet/minecraft/world/level/portal/DimensionTransition;)Lnet/minecraft/world/entity/Entity;", at = @At("HEAD"))
public void changeDimensionHead(DimensionTransition transition, CallbackInfoReturnable<Entity> callbackInfo) {
public void changeDimensionHead(DimensionTransition transition, CallbackInfoReturnable<Entity> callbackInfo, @Share("fromDimHolder") LocalRef<ResourceKey<Level>> fromDimHolder) {
ServerPlayer player = (ServerPlayer) (Object) this;
fromDimHolder.set(player.level().dimension());
}

@Inject(method = "changeDimension(Lnet/minecraft/world/level/portal/DimensionTransition;)Lnet/minecraft/world/entity/Entity;", at = @At("RETURN"))
public void changeDimensionTail(DimensionTransition transition, CallbackInfoReturnable<Entity> callbackInfo) {
public void changeDimensionTail(DimensionTransition transition, CallbackInfoReturnable<Entity> callbackInfo, @Share("fromDimHolder") LocalRef<ResourceKey<Level>> fromDimHolder) {
ServerPlayer player = (ServerPlayer) (Object) this;
final ResourceKey<Level> fromDim = fromDimHolder.get();
final ResourceKey<Level> toDim = transition.newLevel().dimension();
Expand Down

0 comments on commit d1860f3

Please sign in to comment.