Skip to content

Commit

Permalink
feat: mixin refactoring and entity gametest
Browse files Browse the repository at this point in the history
  • Loading branch information
CallMeEchoCodes committed Oct 5, 2024
1 parent acde4e1 commit e21e546
Show file tree
Hide file tree
Showing 31 changed files with 184 additions and 147 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,16 @@

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import dev.spiritstudios.specter.api.block.BlockMetatags;
import dev.spiritstudios.specter.impl.block.SpecterBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.AxeItem;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Map;
import java.util.Optional;
Expand All @@ -25,19 +20,25 @@
public class AxeItemMixin {
@Shadow
@Final
public static Map<Block, Block> STRIPPED_BLOCKS;
protected static Map<Block, Block> STRIPPED_BLOCKS;

@WrapOperation(method = "tryStrip", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/AxeItem;getStrippedState(Lnet/minecraft/block/BlockState;)Ljava/util/Optional;"))
private Optional<BlockState> getStrippedState(AxeItem instance, BlockState state, Operation<Optional<BlockState>> original) {
Optional<Block> strippedBlock = BlockMetatags.STRIPPABLE.get(state.getBlock());
if (strippedBlock.isEmpty()) strippedBlock = Optional.ofNullable(STRIPPED_BLOCKS.get(state.getBlock()));

return strippedBlock.map(block -> block.getStateWithProperties(state));
return Optional.ofNullable(STRIPPED_BLOCKS.get(state.getBlock()))
.or(() -> BlockMetatags.STRIPPABLE.get(state.getBlock()))
.map(block -> block.getStateWithProperties(state))
.or(() -> original.call(instance, state));
}

@Inject(method = "tryStrip", at = @At(value = "INVOKE", target = "Ljava/util/Optional;ofNullable(Ljava/lang/Object;)Ljava/util/Optional;"), cancellable = true)
private void tryStrip(World world, BlockPos pos, @Nullable PlayerEntity player, BlockState state, CallbackInfoReturnable<Optional<BlockState>> cir) {
Optional<BlockState> unwaxedBlockState = Optional.ofNullable(SpecterBlock.WAXED_TO_UNWAXED_BLOCKS.get(state.getBlock())).map(unwaxed -> unwaxed.getStateWithProperties(state));
if (unwaxedBlockState.isPresent()) cir.setReturnValue(unwaxedBlockState);
@WrapOperation(method = "tryStrip", at = @At(value = "INVOKE", target = "Ljava/util/Optional;ofNullable(Ljava/lang/Object;)Ljava/util/Optional;"))
private Optional<Object> tryStrip(
Object value,
Operation<Optional<Object>> original,
@Local(argsOnly = true) BlockState state
) {
Optional<Object> unwaxedBlock = Optional.ofNullable(SpecterBlock.WAXED_TO_UNWAXED_BLOCKS.get(state.getBlock()))
.map(block -> block.getStateWithProperties(state));

return unwaxedBlock.or(() -> original.call(value));
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
package dev.spiritstudios.specter.mixin.block;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import dev.spiritstudios.specter.api.block.BlockMetatags;
import dev.spiritstudios.specter.api.block.FlammableBlockData;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FireBlock;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Optional;

@Mixin(FireBlock.class)
public class FireBlockMixin {
@Inject(method = "getBurnChance(Lnet/minecraft/block/BlockState;)I", at = @At("HEAD"), cancellable = true)
private void getBurnChanceFromMetatag(BlockState state, CallbackInfoReturnable<Integer> cir) {
Optional<FlammableBlockData> data = BlockMetatags.FLAMMABLE.get(state.getBlock());
data.ifPresent(flammableBlockData -> cir.setReturnValue(flammableBlockData.burn()));
@WrapOperation(method = "getBurnChance(Lnet/minecraft/block/BlockState;)I", at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/objects/Object2IntMap;getInt(Ljava/lang/Object;)I", remap = false))
private int getBurnChanceFromMetatag(
Object2IntMap<Block> instance,
Object value,
Operation<Integer> original,
@Local(argsOnly = true) BlockState state
) {
return BlockMetatags.FLAMMABLE.get((state).getBlock())
.map(FlammableBlockData::burn)
.orElse(original.call(instance, value));
}

@Inject(method = "getSpreadChance(Lnet/minecraft/block/BlockState;)I", at = @At("HEAD"), cancellable = true)
private void getSpreadChanceFromMetatag(BlockState state, CallbackInfoReturnable<Integer> cir) {
Optional<FlammableBlockData> data = BlockMetatags.FLAMMABLE.get(state.getBlock());
data.ifPresent(flammableBlockData -> cir.setReturnValue(flammableBlockData.spread()));
@WrapOperation(method = "getSpreadChance(Lnet/minecraft/block/BlockState;)I", at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/objects/Object2IntMap;getInt(Ljava/lang/Object;)I", remap = false))
private int getSpreadChanceFromMetatag(
Object2IntMap<Block> instance,
Object value,
Operation<Integer> original,
@Local(argsOnly = true) BlockState state
) {
return BlockMetatags.FLAMMABLE.get((state).getBlock())
.map(FlammableBlockData::spread)
.orElse(original.call(instance, value));
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
package dev.spiritstudios.specter.mixin.block;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import dev.spiritstudios.specter.impl.block.SpecterBlock;
import net.minecraft.block.BlockState;
import net.minecraft.item.HoneycombItem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Optional;

@Mixin(HoneycombItem.class)
public class HoneycombItemMixin {
@Inject(method = "getWaxedState", at = @At("HEAD"), cancellable = true)
private static void getWaxedState(BlockState state, CallbackInfoReturnable<Optional<BlockState>> cir) {
Optional<BlockState> waxedBlockState = Optional.ofNullable(SpecterBlock.UNWAXED_TO_WAXED_BLOCKS.get(state.getBlock())).map(block -> block.getStateWithProperties(state));
if (waxedBlockState.isPresent()) cir.setReturnValue(waxedBlockState);
@WrapOperation(method = "getWaxedState", at = @At(value = "INVOKE", target = "Ljava/util/Optional;ofNullable(Ljava/lang/Object;)Ljava/util/Optional;"))
private static Optional<Object> getWaxedState(
Object value,
Operation<Optional<Object>> original,
@Local(argsOnly = true) BlockState state
) {
Optional<Object> waxedBlockState = Optional.ofNullable(SpecterBlock.UNWAXED_TO_WAXED_BLOCKS.get(state.getBlock()));

return waxedBlockState.or(() -> original.call(value));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,41 @@
import com.google.common.collect.BiMap;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import dev.spiritstudios.specter.impl.block.SpecterBlock;
import net.minecraft.block.Block;
import net.minecraft.block.Oxidizable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Optional;

@Mixin(Oxidizable.class)
public interface OxidizableMixin {
@Inject(method = "getIncreasedOxidationBlock", at = @At("HEAD"), cancellable = true)
private static void getIncreasedOxidationBlock(Block block, CallbackInfoReturnable<Optional<Block>> cir) {
Optional<Block> increasedOxidationBlock = Optional.ofNullable(SpecterBlock.OXIDATION_LEVEL_INCREASES.get(block));
if (increasedOxidationBlock.isPresent()) cir.setReturnValue(increasedOxidationBlock);
@WrapOperation(method = "getIncreasedOxidationBlock", at = @At(value = "INVOKE", target = "Ljava/util/Optional;ofNullable(Ljava/lang/Object;)Ljava/util/Optional;"))
private static Optional<Object> getIncreasedOxidationBlock(
Object value,
Operation<Optional<Object>> original,
@Local(argsOnly = true) Block block
) {
Optional<Object> increasedOxidationBlock = Optional.ofNullable(SpecterBlock.OXIDATION_LEVEL_INCREASES.get(block));
return increasedOxidationBlock.or(() -> original.call(value));
}

@Inject(method = "getDecreasedOxidationBlock", at = @At("HEAD"), cancellable = true)
private static void getDecreasedOxidationBlock(Block block, CallbackInfoReturnable<Optional<Block>> cir) {
Optional<Block> decreasedOxidationBlock = Optional.ofNullable(SpecterBlock.OXIDATION_LEVEL_DECREASES.get(block));
if (decreasedOxidationBlock.isPresent()) cir.setReturnValue(decreasedOxidationBlock);
@WrapOperation(method = "getDecreasedOxidationBlock", at = @At(value = "INVOKE", target = "Ljava/util/Optional;ofNullable(Ljava/lang/Object;)Ljava/util/Optional;"))
private static Optional<Object> getDecreasedOxidationBlock(
Object value,
Operation<Optional<Object>> original,
@Local(argsOnly = true) Block block
) {
Optional<Object> decreasedOxidationBlock = Optional.ofNullable(SpecterBlock.OXIDATION_LEVEL_DECREASES.get(block));
return decreasedOxidationBlock.or(() -> original.call(value));
}

@SuppressWarnings("rawtypes")
@WrapOperation(method = "getUnaffectedOxidationBlock", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/BiMap;get(Ljava/lang/Object;)Ljava/lang/Object;", remap = false))
private static Object getUnaffectedOxidationBlock(BiMap instance, Object o, Operation<Object> original) {
Block block = (Block) o;
Optional<Block> unaffectedOxidationBlock = Optional.ofNullable(SpecterBlock.OXIDATION_LEVEL_DECREASES.get(block));
return unaffectedOxidationBlock.orElseGet(() -> (Block) original.call(instance, o));
private static <K, V> Object getUnaffectedOxidationBlock(BiMap<K, V> instance, Object value, Operation<Object> original) {
Optional<Object> unaffectedOxidationBlock = Optional.ofNullable(SpecterBlock.OXIDATION_LEVEL_DECREASES.get((Block) value));
return unaffectedOxidationBlock.orElseGet(() -> original.call(instance, value));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import dev.spiritstudios.specter.api.block.BlockMetatags;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.ShovelItem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import java.util.Map;
import java.util.Optional;

@Mixin(ShovelItem.class)
public class ShovelItemMixin {
Expand All @@ -19,7 +17,8 @@ public class ShovelItemMixin {
private <K, V> V get(Map<K, V> instance, Object o, Operation<V> original) {
if (!(o instanceof Block block)) return original.call(instance, o);

Optional<BlockState> flattenedBlock = BlockMetatags.FLATTENABLE.get(block);
return flattenedBlock.map(blockState -> (V) blockState).orElseGet(() -> original.call(instance, o));
return BlockMetatags.FLATTENABLE.get(block)
.map(blockState -> (V) blockState)
.orElseGet(() -> original.call(instance, o));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,4 @@ public void testOxidizableMetatag(TestContext context) {

context.complete();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public void testTomlConfig(TestContext context) throws IOException {
context.assertTrue(TestConfig.TOML_HOLDER.load(), "Config file failed to load");
context.assertTrue(Files.exists(path), "Config file does not exist");
context.assertTrue(TestConfig.TOML_HOLDER.get().testString.get().equals("test2"), "String is not equal to test2, Make sure you haven't modified the config");
Files.deleteIfExists(path);

context.complete();
}
Expand All @@ -59,6 +60,7 @@ public void testJsonCConfig(TestContext context) throws IOException {
context.assertTrue(TestConfig.JSON_HOLDER.load(), "Config file failed to load");
context.assertTrue(Files.exists(path), "Config file does not exist");
context.assertTrue(TestConfig.JSON_HOLDER.get().testString.get().equals("test2"), "String is not equal to test2, Make sure you haven't modified the config");
Files.deleteIfExists(path);

context.complete();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class RunArgsNetworkMixin {
@Mutable
public Session session;

@Inject(method = "<init>", at = @At("TAIL"))
@Inject(method = "<init>", at = @At("RETURN"))
private void init(Session session, PropertyMap userProperties, PropertyMap profileProperties, Proxy proxy, CallbackInfo ci) {
if (!SpecterGlobals.DEBUG) return;

Expand All @@ -35,7 +35,7 @@ private void init(Session session, PropertyMap userProperties, PropertyMap profi
String username = System.getProperty("specter.development.username");
UUID uuid = UndashedUuid.fromString(System.getProperty("specter.development.uuid").replace("-", ""));

SpecterGlobals.LOGGER.info(String.format("Using development account %s (%s)", username, uuid));
SpecterGlobals.LOGGER.info("Using development account {} ({})", username, uuid);
this.session = new Session(
username,
uuid,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package dev.spiritstudios.specter.mixin.entity;

import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import dev.spiritstudios.specter.api.entity.EntityMetatags;
import dev.spiritstudios.specter.impl.entity.DataDefaultAttributeBuilder;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.DefaultAttributeRegistry;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -16,25 +19,21 @@

@Mixin(DefaultAttributeRegistry.class)
public class DefaultAttributeRegistryMixin {
@SuppressWarnings("unchecked")
@WrapOperation(method = "get", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;"))
private static <K, V> V get(Map<K, V> instance, Object o, Operation<V> original) {
if (!(o instanceof EntityType<?> entityType)) return original.call(instance, o);

Optional<DataDefaultAttributeBuilder> attributeBuilder = EntityMetatags.DEFAULT_ATTRIBUTES.get(entityType);
if (attributeBuilder.isEmpty()) return original.call(instance, o);

DefaultAttributeContainer originalAttributes = (DefaultAttributeContainer) original.call(instance, o);
if (originalAttributes == null) return (V) attributeBuilder.get().build();

return (V) DataDefaultAttributeBuilder.with(attributeBuilder.get(), originalAttributes).build();
@ModifyReturnValue(method = "get", at = @At("RETURN"))
private static DefaultAttributeContainer get(DefaultAttributeContainer original, @Local(argsOnly = true) EntityType<? extends LivingEntity> type) {
Optional<DefaultAttributeContainer> originalAttributes = Optional.ofNullable(original);
return EntityMetatags.DEFAULT_ATTRIBUTES.get(type)
.map(builder ->
originalAttributes
.map(attributes -> DataDefaultAttributeBuilder.with(builder, attributes))
.orElse(builder)
.build()
).orElse(original);
}

@WrapOperation(method = "hasDefinitionFor", at = @At(value = "INVOKE", target = "Ljava/util/Map;containsKey(Ljava/lang/Object;)Z"))
private static <K, V> boolean containsKey(Map<K, V> instance, Object o, Operation<Boolean> original) {
if (!(o instanceof EntityType<?> entityType)) return original.call(instance, o);

boolean hasDefinition = Objects.nonNull(EntityMetatags.DEFAULT_ATTRIBUTES.get(entityType));
return hasDefinition || original.call(instance, o);
return Objects.nonNull(EntityMetatags.DEFAULT_ATTRIBUTES.get(entityType)) || original.call(instance, o);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package dev.spiritstudios.testmod;

import net.fabricmc.fabric.api.gametest.v1.FabricGameTest;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.mob.WardenEntity;
import net.minecraft.test.GameTest;
import net.minecraft.test.TestContext;

public class SpecterEntityGameTest {
@GameTest(templateName = FabricGameTest.EMPTY_STRUCTURE)
public void testDefaultAttributes(TestContext context) {
WardenEntity warden = context.spawnEntity(EntityType.WARDEN, 0, 0, 0);
warden.damage(context.getWorld().getDamageSources().generic(), 1);

context.assertTrue(warden.isDead(), "Warden should be dead after being attacked by player");
context.complete();
}
}
3 changes: 3 additions & 0 deletions specter-entity/src/testmod/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
"license": "MPL-2.0",
"environment": "*",
"entrypoints": {
"fabric-gametest": [
"dev.spiritstudios.testmod.SpecterEntityGameTest"
]
},
"depends": {
"fabricloader": ">=${loader_version}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class CreativeInventoryScreenMixin {
@Inject(method = "init", at = @At("RETURN"))
private void init(CallbackInfo ci) {
if (!ItemGroupReloader.RELOADED) return;

((FabricCreativeInventoryScreen) this).switchToPage(0);
ItemGroupReloader.RELOADED = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,20 @@
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Optional;

@Mixin(AbstractFurnaceBlockEntity.class)
public class AbstractFurnaceBlockEntityMixin {
@Inject(method = "getFuelTime", at = @At("HEAD"), cancellable = true)
private void getFuelTime(ItemStack fuel, CallbackInfoReturnable<Integer> cir) {
if (fuel.isEmpty()) return;

Optional<Integer> fuelTime = ItemMetatags.FUEL.get(fuel.getItem());
fuelTime.ifPresent(cir::setReturnValue);
}

@ModifyReturnValue(method = "canUseAsFuel", at = @At("RETURN"))
private static boolean canUseAsFuel(boolean original, @Local(argsOnly = true) ItemStack stack) {
if (stack.isEmpty()) return original;

boolean hasFuelMetatag = ItemMetatags.FUEL.get(stack.getItem()).isPresent();
return original || hasFuelMetatag;
}

@ModifyReturnValue(method = "getFuelTime", at = @At("RETURN"))
private int getFuelTime(int original, @Local(argsOnly = true) ItemStack fuel) {
if (fuel.isEmpty()) return original;
return ItemMetatags.FUEL.get(fuel.getItem()).orElse(original);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
public class ComposterBlock$ComposterInventoryMixin {
@WrapOperation(method = "canInsert", at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/objects/Object2FloatMap;containsKey(Ljava/lang/Object;)Z", remap = false))
private boolean canInsert(Object2FloatMap<ItemConvertible> instance, Object o, Operation<Boolean> original) {
ItemConvertible itemConvertible = (ItemConvertible) o;
if (SpecterItem.ITEM_TO_LEVEL_INCREASE_CHANCE.containsKey(itemConvertible)) return true;

return original.call(instance, o);
return SpecterItem.ITEM_TO_LEVEL_INCREASE_CHANCE.containsKey((ItemConvertible) o) || original.call(instance, o);
}
}
Loading

0 comments on commit e21e546

Please sign in to comment.