diff --git a/fabric/src/main/java/ziyue/tjmetro/fabric/mixin/StorageMinecartEntityMixin.java b/fabric/src/main/java/ziyue/tjmetro/fabric/mixin/StorageMinecartEntityMixin.java new file mode 100644 index 0000000..2a2ed5e --- /dev/null +++ b/fabric/src/main/java/ziyue/tjmetro/fabric/mixin/StorageMinecartEntityMixin.java @@ -0,0 +1,34 @@ +package ziyue.tjmetro.fabric.mixin; + +import net.minecraft.entity.EntityType; +import net.minecraft.entity.vehicle.AbstractMinecartEntity; +import net.minecraft.entity.vehicle.StorageMinecartEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import ziyue.tjmetro.mapping.ContainerAccessor; + +/** + * @author ZiYueCommentary + * @see ziyue.tjmetro.mapping.ContainerAccessor + * @since 1.0.0-beta-2 + */ + +@Mixin(StorageMinecartEntity.class) +public abstract class StorageMinecartEntityMixin extends AbstractMinecartEntity implements Inventory, NamedScreenHandlerFactory, ContainerAccessor +{ + @Shadow private DefaultedList inventory; + + protected StorageMinecartEntityMixin(EntityType entityType, World world) { + super(entityType, world); + } + + @Override + public DefaultedList tianjin_Metro$getInventory() { + return this.inventory; + } +} diff --git a/fabric/src/main/java/ziyue/tjmetro/mapping/ContainerAccessor.java b/fabric/src/main/java/ziyue/tjmetro/mapping/ContainerAccessor.java new file mode 100644 index 0000000..81bed17 --- /dev/null +++ b/fabric/src/main/java/ziyue/tjmetro/mapping/ContainerAccessor.java @@ -0,0 +1,16 @@ +package ziyue.tjmetro.mapping; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.collection.DefaultedList; +import ziyue.tjmetro.fabric.mixin.StorageMinecartEntityMixin; + +/** + * @author ZiYueCommentary + * @see StorageMinecartEntityMixin + * @since 1.0.0-beta-2 + */ + +public interface ContainerAccessor +{ + DefaultedList tianjin_Metro$getInventory(); +} diff --git a/fabric/src/main/java/ziyue/tjmetro/mapping/DefaultedItemStackList.java b/fabric/src/main/java/ziyue/tjmetro/mapping/DefaultedItemStackList.java new file mode 100644 index 0000000..73cefe3 --- /dev/null +++ b/fabric/src/main/java/ziyue/tjmetro/mapping/DefaultedItemStackList.java @@ -0,0 +1,41 @@ +package ziyue.tjmetro.mapping; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.collection.DefaultedList; +import org.mtr.mapping.annotation.MappedMethod; +import org.mtr.mapping.tool.HolderBase; + +/** + * @author ZiYueCommentary + * @since 1.0.0-beta-2 + */ + +public class DefaultedItemStackList extends HolderBase> +{ + public DefaultedItemStackList(DefaultedItemStackList data) { + super(data.data); + } + + public DefaultedItemStackList(DefaultedList data) { + super(data); + } + + public static DefaultedItemStackList ofSize(int size) { + return new DefaultedItemStackList(DefaultedList.ofSize(size, ItemStack.EMPTY)); + } + + @MappedMethod + public int size() { + return this.data.size(); + } + + @MappedMethod + public void set(int i, ItemStack stack) { + this.data.set(i, stack); + } + + @MappedMethod + public ItemStack get(int i) { + return this.data.get(i); + } +} diff --git a/fabric/src/main/java/ziyue/tjmetro/mapping/MetalDetectionDoorEntity.java b/fabric/src/main/java/ziyue/tjmetro/mapping/MetalDetectionDoorEntity.java new file mode 100644 index 0000000..c64883a --- /dev/null +++ b/fabric/src/main/java/ziyue/tjmetro/mapping/MetalDetectionDoorEntity.java @@ -0,0 +1,134 @@ +package ziyue.tjmetro.mapping; + +/** + * An entity for GUI of Metal Detection Door. This entity is a minecart-with-chest. + * + * @author ZiYueCommentary + * @see BlockMetalDetectionDoor + * @since 1.0.0-beta-2 + */ + +#if MC_VERSION >= "11902" + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.vehicle.ChestMinecartEntity; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.text.Text; +import org.mtr.mapping.holder.BlockPos; +import org.mtr.mapping.holder.World; +import ziyue.tjmetro.mod.block.BlockMetalDetectionDoor; + +public class MetalDetectionDoorEntity extends ChestMinecartEntity +{ + public final BlockMetalDetectionDoor.BlockEntity blockEntity; + + public MetalDetectionDoorEntity(World world, BlockPos blockPos, BlockMetalDetectionDoor.BlockEntity blockEntity) { + super(world.data, blockPos.getX(), -1, blockPos.getZ()); + this.blockEntity = blockEntity; + for (int i = 0; i < blockEntity.inventory.size(); i++) { + this.getInventory().set(i, blockEntity.inventory.get(i)); + } + } + + @Override + public ScreenHandler getScreenHandler(int syncId, PlayerInventory playerInventory) { + return new GenericContainerScreenHandler(ScreenHandlerType.GENERIC_9X1, syncId, playerInventory, this, 1) + { + @Override + public void onClosed(PlayerEntity player) { + super.onClosed(player); + final MetalDetectionDoorEntity entity = (MetalDetectionDoorEntity) this.getInventory(); + entity.blockEntity.setData(new DefaultedItemStackList(entity.getInventory())); + entity.getInventory().clear(); + entity.kill(); + } + }; + } + + @Override + public boolean canPlayerUse(PlayerEntity player) { + return true; + } + + @Override + public boolean hasNoGravity() { + return true; + } + + @Override + public int getMaxCountPerStack() { + return 1; + } + + @Override + public Text getDisplayName() { + return Text.translatable("gui.tjmetro.metal_detection_door"); + } +} + +#else + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.vehicle.ChestMinecartEntity; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import org.mtr.mapping.holder.BlockPos; +import org.mtr.mapping.holder.World; +import ziyue.tjmetro.mod.block.BlockMetalDetectionDoor; + +public class MetalDetectionDoorEntity extends ChestMinecartEntity +{ + public final BlockMetalDetectionDoor.BlockEntity blockEntity; + + public MetalDetectionDoorEntity(World world, BlockPos blockPos, BlockMetalDetectionDoor.BlockEntity blockEntity) { + super(world.data, blockPos.getX(), -1, blockPos.getZ()); + this.blockEntity = blockEntity; + for (int i = 0; i < blockEntity.inventory.size(); i++) { + ((ContainerAccessor) this).tianjin_Metro$getInventory().set(i, blockEntity.inventory.get(i)); + } + } + + @Override + public ScreenHandler getScreenHandler(int syncId, PlayerInventory playerInventory) { + return new GenericContainerScreenHandler(ScreenHandlerType.GENERIC_9X1, syncId, playerInventory, this, 1) + { + @Override + public void close(PlayerEntity player) { + super.close(player); + final MetalDetectionDoorEntity entity = (MetalDetectionDoorEntity) this.getInventory(); + entity.blockEntity.setData(new DefaultedItemStackList(((ContainerAccessor) entity).tianjin_Metro$getInventory())); + ((ContainerAccessor) entity).tianjin_Metro$getInventory().clear(); + entity.kill(); + } + }; + } + + @Override + public boolean canPlayerUse(PlayerEntity player) { + return true; + } + + @Override + public boolean hasNoGravity() { + return true; + } + + @Override + public int getMaxCountPerStack() { + return 1; + } + + @Override + public Text getDisplayName() { + return new TranslatableText("gui.tjmetro.metal_detection_door"); + } +} + +#endif \ No newline at end of file diff --git a/fabric/src/main/java/ziyue/tjmetro/mapping/PlayerInventoryHelper.java b/fabric/src/main/java/ziyue/tjmetro/mapping/PlayerInventoryHelper.java new file mode 100644 index 0000000..7ded14a --- /dev/null +++ b/fabric/src/main/java/ziyue/tjmetro/mapping/PlayerInventoryHelper.java @@ -0,0 +1,50 @@ +package ziyue.tjmetro.mapping; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.collection.DefaultedList; +import org.mtr.mapping.holder.PlayerEntity; + +import java.util.function.Function; + +/** + * @author ZiYueCommentary + * @since 1.0.0-beta-2 + */ + +public interface PlayerInventoryHelper +{ + static void clearItems(PlayerEntity player, Function filter) { +#if MC_VERSION <= "11605" + final DefaultedList main = player.data.inventory.main; + for (int i = 0; i < main.size(); i++) { + if (filter.apply(main.get(i).getItem())) main.set(i, ItemStack.EMPTY); + } + + final DefaultedList armor = player.data.inventory.armor; + for (int i = 0; i < armor.size(); i++) { + if (filter.apply(armor.get(i).getItem())) armor.set(i, ItemStack.EMPTY); + } + + final DefaultedList offHand = player.data.inventory.offHand; + for (int i = 0; i < offHand.size(); i++) { + if (filter.apply(offHand.get(i).getItem())) offHand.set(i, ItemStack.EMPTY); + } +#else + final DefaultedList main = player.data.getInventory().main; + for (int i = 0; i < main.size(); i++) { + if (filter.apply(main.get(i).getItem())) main.set(i, ItemStack.EMPTY); + } + + final DefaultedList armor = player.data.getInventory().armor; + for (int i = 0; i < armor.size(); i++) { + if (filter.apply(armor.get(i).getItem())) armor.set(i, ItemStack.EMPTY); + } + + final DefaultedList offHand = player.data.getInventory().offHand; + for (int i = 0; i < offHand.size(); i++) { + if (filter.apply(offHand.get(i).getItem())) offHand.set(i, ItemStack.EMPTY); + } +#endif + } +} diff --git a/fabric/src/main/java/ziyue/tjmetro/mapping/RegistryHelper.java b/fabric/src/main/java/ziyue/tjmetro/mapping/RegistryHelper.java index 12cbb39..a35615f 100644 --- a/fabric/src/main/java/ziyue/tjmetro/mapping/RegistryHelper.java +++ b/fabric/src/main/java/ziyue/tjmetro/mapping/RegistryHelper.java @@ -1,5 +1,6 @@ package ziyue.tjmetro.mapping; +import net.minecraft.item.ItemStack; import org.mtr.mapping.holder.Identifier; import org.mtr.mapping.holder.Item; import org.mtr.mapping.registry.BlockRegistryObject; @@ -9,20 +10,38 @@ import java.lang.reflect.InvocationTargetException; /** - * Converting block to item. This may not be stable since it uses reflection. - * * @author ZiYueCommentary * @since 1.0.0-beta-2 */ -// This is a very mad way but I have no choice. public interface RegistryHelper { static ItemRegistryObject RegistryObjectBlock2Item(BlockRegistryObject fabric, Identifier forge) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException { + // This is a very mad way but I have no choice. Class clazz = ItemRegistryObject.class; Constructor constructor = clazz.getDeclaredConstructor(Item.class); constructor.setAccessible(true); return constructor.newInstance(fabric.get().asItem()); } + + static ItemStack cloneSingleItemStack(ItemStack itemStack) { + return new ItemStack(itemStack.getItem()); + } + + static Identifier getIdentifierByItem(net.minecraft.item.Item item) { +#if MC_VERSION >= "11902" + return new Identifier(net.minecraft.registry.Registries.ITEM.getId(item)); +#else + return new Identifier(net.minecraft.util.registry.Registry.ITEM.getId(item)); +#endif + } + + static ItemStack getItemStackByIdentifier(Identifier identifier) { +#if MC_VERSION >= "11902" + return net.minecraft.registry.Registries.ITEM.get(identifier.data).getDefaultStack(); +#else + return net.minecraft.util.registry.Registry.ITEM.get(identifier.data).getDefaultStack(); +#endif + } } diff --git a/fabric/src/main/java/ziyue/tjmetro/mod/block/BlockMetalDetectionDoor.java b/fabric/src/main/java/ziyue/tjmetro/mod/block/BlockMetalDetectionDoor.java index 98b354a..32185ba 100644 --- a/fabric/src/main/java/ziyue/tjmetro/mod/block/BlockMetalDetectionDoor.java +++ b/fabric/src/main/java/ziyue/tjmetro/mod/block/BlockMetalDetectionDoor.java @@ -3,25 +3,34 @@ import org.mtr.mapping.holder.*; import org.mtr.mapping.mapper.*; import org.mtr.mapping.tool.HolderBase; +import org.mtr.mod.SoundEvents; import org.mtr.mod.block.IBlock; +import ziyue.tjmetro.mapping.DefaultedItemStackList; +import ziyue.tjmetro.mapping.MetalDetectionDoorEntity; +import ziyue.tjmetro.mapping.PlayerInventoryHelper; +import ziyue.tjmetro.mapping.RegistryHelper; +import ziyue.tjmetro.mod.BlockEntityTypes; import ziyue.tjmetro.mod.BlockList; -import ziyue.tjmetro.mod.TianjinMetro; import ziyue.tjmetro.mod.data.IGuiExtension; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; +import java.util.stream.Collectors; /** * A device for clearing specify items from players' inventory. * * @author ZiYueCommentary + * @see BlockEntity * @since 1.0.0-beta-1 */ // Not working currently, waiting for another implementation. -public class BlockMetalDetectionDoor extends BlockExtension implements DirectionHelper, IBlock +public class BlockMetalDetectionDoor extends BlockExtension implements DirectionHelper, BlockWithEntity, IBlock { + public static final BooleanProperty OPEN = BooleanProperty.of("open"); + public BlockMetalDetectionDoor() { this(BlockHelper.createBlockSettings(true)); } @@ -48,15 +57,28 @@ public BlockState getPlacementState2(ItemPlacementContext ctx) { @Override public ActionResult onUse2(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { return IBlockExtension.checkHoldingBrushOrWrench(world, player, () -> { - TianjinMetro.LOGGER.info("There should be a GUI opened here... But there is nothing currently."); + final BlockPos blockPos; + switch (IBlock.getStatePropertySafe(state, THIRD)) { + case LOWER: + blockPos = pos; + break; + case MIDDLE: + blockPos = pos.down(1); + break; + default: + blockPos = pos.down(2); + } + MetalDetectionDoorEntity entity = new MetalDetectionDoorEntity(world, blockPos, (BlockEntity) world.getBlockEntity(blockPos).data); + world.spawnEntity(new Entity(entity)); + entity.interact(player.data, hand.data); + BlockEntity lower = (BlockEntity) world.getBlockEntity(blockPos).data; + BlockEntity middle = (BlockEntity) world.getBlockEntity(blockPos.up(1)).data; + BlockEntity upper = (BlockEntity) world.getBlockEntity(blockPos.up(2)).data; + middle.setData(lower.inventory); + upper.setData(lower.inventory); }); } - @Override - public void onEntityCollision2(BlockState state, World world, BlockPos pos, Entity entity) { - super.onEntityCollision2(state, world, pos, entity); - } - @Nonnull @Override public VoxelShape getOutlineShape2(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { @@ -70,6 +92,17 @@ public VoxelShape getOutlineShape2(BlockState state, BlockView world, BlockPos p } } + @Nonnull + @Override + public VoxelShape getCollisionShape2(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + final VoxelShape shape = this.getOutlineShape2(state, world, pos, context); + if ((!IBlock.getStatePropertySafe(state, OPEN)) && (IBlock.getStatePropertySafe(state, THIRD) != EnumThird.UPPER)) { + final VoxelShape barrier = IBlock.getVoxelShapeByDirection(0, 0, 1, 16, 16, 2, IBlock.getStatePropertySafe(state, FACING)); + return VoxelShapes.union(shape, barrier); + } + return shape; + } + @Override public void onBreak2(World world, BlockPos pos, BlockState state, PlayerEntity player) { switch (IBlock.getStatePropertySafe(state, THIRD)) { @@ -93,9 +126,71 @@ public void onBreak2(World world, BlockPos pos, BlockState state, PlayerEntity p public void addTooltips(ItemStack stack, @Nullable BlockView world, List tooltip, TooltipContext options) { IGuiExtension.addHoldShiftTooltip(tooltip, TextHelper.translatable("tooltip.tjmetro.metal_detection_door")); } + + @Override + public BlockEntityExtension createBlockEntity(BlockPos blockPos, BlockState blockState) { + return new BlockEntity(blockPos, blockState); + } + @Override public void addBlockProperties(List> properties) { properties.add(FACING); properties.add(THIRD); + properties.add(OPEN); + } + + /** + * @author ZiYueCommentary + * @since 1.0.0-beta-2 + */ + public static class BlockEntity extends BlockEntityExtension + { + public final DefaultedItemStackList inventory; + + public BlockEntity(BlockPos blockPos, BlockState blockState) { + super(BlockEntityTypes.METAL_DETECTION_DOOR.get(), blockPos, blockState); + this.inventory = DefaultedItemStackList.ofSize(9); + } + + @Override + public void blockEntityTick() { + if (IBlock.getStatePropertySafe(getCachedState2(), THIRD) != EnumThird.LOWER) return; + + final PlayerEntity player = getWorld2().getClosestPlayer(getPos2().getX(), getPos2().getY(), getPos2().getZ(), 1, false); + if (player != null) { + if (getPos2().getX() == Math.floor(player.getX()) && getPos2().getY() == Math.round(player.getY()) && getPos2().getZ() == Math.floor(player.getZ())) { + List items = this.inventory.data.stream().map(itemStack -> itemStack.getItem()).collect(Collectors.toList()); // Do not use method reference. + PlayerInventoryHelper.clearItems(player, items::contains); + if (IBlock.getStatePropertySafe(getCachedState2(), OPEN)) return; + getWorld2().playSound(null, getPos2(), SoundEvents.TICKET_BARRIER.get(), SoundCategory.BLOCKS, 1, 1); + getWorld2().setBlockState(getPos2(), getCachedState2().with(new Property<>(OPEN.data), true)); + } + } else { + getWorld2().setBlockState(getPos2(), getCachedState2().with(new Property<>(OPEN.data), false)); + } + } + + @Override + public void writeCompoundTag(CompoundTag compoundTag) { + for (int i = 0; i < this.inventory.size(); i++) { + compoundTag.data.putString(Integer.toString(i), RegistryHelper.getIdentifierByItem(this.inventory.get(i).getItem()).data.toString()); + } + super.writeCompoundTag(compoundTag); + } + + @Override + public void readCompoundTag(CompoundTag compoundTag) { + for (int i = 0; i < this.inventory.size(); i++) { + this.inventory.set(i, RegistryHelper.getItemStackByIdentifier(new Identifier(compoundTag.getString(Integer.toString(i))))); + } + super.readCompoundTag(compoundTag); + } + + public void setData(DefaultedItemStackList list) { + for (int i = 0; i < this.inventory.size(); i++) { + this.inventory.set(i, RegistryHelper.cloneSingleItemStack(list.get(i))); + } + markDirty2(); + } } } diff --git a/fabric/src/main/java/ziyue/tjmetro/mod/data/IGuiExtension.java b/fabric/src/main/java/ziyue/tjmetro/mod/data/IGuiExtension.java index 6abebd9..5dc49df 100644 --- a/fabric/src/main/java/ziyue/tjmetro/mod/data/IGuiExtension.java +++ b/fabric/src/main/java/ziyue/tjmetro/mod/data/IGuiExtension.java @@ -168,7 +168,7 @@ static String insertTranslation(String keyCJK, String key, int expectedArguments /** * Adding a hold-shift-tooltip to the tooltips. * - * @param list hover Text List, just like pointer in C/C++ + * @param list hover text List, just like pointer in C/C++ * @param component a component that waits for split * @param regex the delimiting regular expression * @param limit the result threshold, as described above diff --git a/fabric/src/main/java/ziyue/tjmetro/mod/render/RenderPSDTopTianjinBMT.java b/fabric/src/main/java/ziyue/tjmetro/mod/render/RenderPSDTopTianjinBMT.java index df03287..752ed5e 100644 --- a/fabric/src/main/java/ziyue/tjmetro/mod/render/RenderPSDTopTianjinBMT.java +++ b/fabric/src/main/java/ziyue/tjmetro/mod/render/RenderPSDTopTianjinBMT.java @@ -21,7 +21,7 @@ * @author ZiYueCommentary * @see BlockPSDTopTianjinBMT * @see RenderRouteBase - * @since 1.0.0-beta-1 + * @since 1.0.0-beta-2 */ public class RenderPSDTopTianjinBMT extends RenderRouteBase diff --git a/fabric/src/main/resources/assets/tjmetro/models/block/metal_detection_door_upper.json b/fabric/src/main/resources/assets/tjmetro/models/block/metal_detection_door_upper.json index caef34f..5844378 100644 --- a/fabric/src/main/resources/assets/tjmetro/models/block/metal_detection_door_upper.json +++ b/fabric/src/main/resources/assets/tjmetro/models/block/metal_detection_door_upper.json @@ -1,7 +1,7 @@ { "credit": "Made by ZiYueCommentary, made with Blockbench.", "textures": { - "1": "tjmetro:block/metal_detection_door_block", + "1": "tjmetro:block/metal_detection_door_sign", "2": "mtr:block/metal", "3": "block/air", "particle": "mtr:block/metal" diff --git a/fabric/src/main/resources/assets/tjmetro/models/item/metal_detection_door.json b/fabric/src/main/resources/assets/tjmetro/models/item/metal_detection_door.json index 6727223..7509fd3 100644 --- a/fabric/src/main/resources/assets/tjmetro/models/item/metal_detection_door.json +++ b/fabric/src/main/resources/assets/tjmetro/models/item/metal_detection_door.json @@ -2,7 +2,7 @@ "credit": "Made by ZiYueCommentary, made with Blockbench.", "parent": "block/block", "textures": { - "0": "tjmetro:sign/metal_detection_door_sign", + "0": "tjmetro:block/metal_detection_door_sign", "1": "mtr:block/metal", "particle": "tjmetro:sign/metal_detection_door_sign" }, diff --git a/fabric/src/main/resources/tjmetro-fabric.mixins.json b/fabric/src/main/resources/tjmetro-fabric.mixins.json index e99a2dd..6c99841 100644 --- a/fabric/src/main/resources/tjmetro-fabric.mixins.json +++ b/fabric/src/main/resources/tjmetro-fabric.mixins.json @@ -4,7 +4,8 @@ "package": "ziyue.tjmetro.fabric.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ - "FallingBlockMixin" + "FallingBlockMixin", + "StorageMinecartEntityMixin" ], "injectors": { "defaultRequire": 1 diff --git a/forge/src/main/java/ziyue/tjmetro/forge/mixin/AbstractMinecartContainerMixin.java b/forge/src/main/java/ziyue/tjmetro/forge/mixin/AbstractMinecartContainerMixin.java new file mode 100644 index 0000000..20e8ddd --- /dev/null +++ b/forge/src/main/java/ziyue/tjmetro/forge/mixin/AbstractMinecartContainerMixin.java @@ -0,0 +1,99 @@ +package ziyue.tjmetro.forge.mixin; + +/** + * @author ZiYueCommentary + * @see ContainerAccessor + * @since 1.0.0-beta-2 + */ + +#if MC_VERSION >= "11902" + +import net.minecraft.core.NonNullList; +import net.minecraft.world.Container; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.entity.vehicle.AbstractMinecartContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import ziyue.tjmetro.mapping.ContainerAccessor; + +@Mixin(AbstractMinecartContainer.class) +public abstract class AbstractMinecartContainerMixin extends AbstractMinecart implements Container, MenuProvider, ContainerAccessor +{ + @Shadow + private NonNullList itemStacks; + + protected AbstractMinecartContainerMixin(EntityType p_38213_, Level p_38214_) { + super(p_38213_, p_38214_); + } + + @Override + public NonNullList tianjin_Metro$getItemStacks() { + return this.itemStacks; + } +} + +#elif MC_VERSION >= "11701" + +import net.minecraft.core.NonNullList; +import net.minecraft.world.Container; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.entity.vehicle.AbstractMinecartContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import ziyue.tjmetro.mapping.ContainerAccessor; + +@Mixin(AbstractMinecartContainer.class) +public abstract class AbstractMinecartContainerMixin extends AbstractMinecart implements Container, MenuProvider, ContainerAccessor +{ + @Shadow + private NonNullList itemStacks; + + protected AbstractMinecartContainerMixin(EntityType p_38213_, Level p_38214_) { + super(p_38213_, p_38214_); + } + + @Override + public NonNullList tianjin_Metro$getItemStacks() { + return this.itemStacks; + } +} + +#else + +import net.minecraft.entity.EntityType; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.item.minecart.ContainerMinecartEntity; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import ziyue.tjmetro.mapping.ContainerAccessor; + +@Mixin(ContainerMinecartEntity.class) +public abstract class AbstractMinecartContainerMixin extends AbstractMinecartEntity implements IInventory, INamedContainerProvider, ContainerAccessor +{ + @Shadow + private NonNullList itemStacks; + + protected AbstractMinecartContainerMixin(EntityType p_i48538_1_, World p_i48538_2_) { + super(p_i48538_1_, p_i48538_2_); + } + + @Override + public NonNullList tianjin_Metro$getItemStacks() { + return this.itemStacks; + } +} + +#endif \ No newline at end of file diff --git a/forge/src/main/java/ziyue/tjmetro/mapping/ContainerAccessor.java b/forge/src/main/java/ziyue/tjmetro/mapping/ContainerAccessor.java new file mode 100644 index 0000000..a8e4e22 --- /dev/null +++ b/forge/src/main/java/ziyue/tjmetro/mapping/ContainerAccessor.java @@ -0,0 +1,39 @@ +package ziyue.tjmetro.mapping; + +/** + * @author ZiYueCommentary + * @see ziyue.tjmetro.forge.mixin.AbstractMinecartContainerMixin + * @since 1.0.0-beta-2 + */ + +#if MC_VERSION >= "11902" + +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; + +public interface ContainerAccessor +{ + NonNullList tianjin_Metro$getItemStacks(); +} + +#elif MC_VERSION >= "11701" + +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; + +public interface ContainerAccessor +{ + NonNullList tianjin_Metro$getItemStacks(); +} + +#else + +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; + +public interface ContainerAccessor +{ + NonNullList tianjin_Metro$getItemStacks(); +} + +#endif \ No newline at end of file diff --git a/forge/src/main/java/ziyue/tjmetro/mapping/DefaultedItemStackList.java b/forge/src/main/java/ziyue/tjmetro/mapping/DefaultedItemStackList.java new file mode 100644 index 0000000..d134259 --- /dev/null +++ b/forge/src/main/java/ziyue/tjmetro/mapping/DefaultedItemStackList.java @@ -0,0 +1,82 @@ +package ziyue.tjmetro.mapping; + +/** + * @author ZiYueCommentary + * @since 1.0.0-beta-2 + */ + +#if MC_VERSION >= "11701" + +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; +import org.mtr.mapping.annotation.MappedMethod; +import org.mtr.mapping.tool.HolderBase; + +public class DefaultedItemStackList extends HolderBase> +{ + public DefaultedItemStackList(DefaultedItemStackList data) { + super(data.data); + } + + public DefaultedItemStackList(NonNullList data) { + super(data); + } + + public static DefaultedItemStackList ofSize(int size) { + return new DefaultedItemStackList(NonNullList.withSize(size, ItemStack.EMPTY)); + } + + @MappedMethod + public int size() { + return this.data.size(); + } + + @MappedMethod + public void set(int i, ItemStack stack) { + this.data.set(i, stack); + } + + @MappedMethod + public ItemStack get(int i) { + return this.data.get(i); + } +} + +#else + +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import org.mtr.mapping.annotation.MappedMethod; +import org.mtr.mapping.tool.HolderBase; + +public class DefaultedItemStackList extends HolderBase> +{ + public DefaultedItemStackList(DefaultedItemStackList data) { + super(data.data); + } + + public DefaultedItemStackList(NonNullList data) { + super(data); + } + + public static DefaultedItemStackList ofSize(int size) { + return new DefaultedItemStackList(NonNullList.withSize(size, ItemStack.EMPTY)); + } + + @MappedMethod + public int size() { + return this.data.size(); + } + + @MappedMethod + public void set(int i, ItemStack stack) { + this.data.set(i, stack); + } + + @MappedMethod + public ItemStack get(int i) { + return this.data.get(i); + } +} + +#endif \ No newline at end of file diff --git a/forge/src/main/java/ziyue/tjmetro/mapping/MetalDetectionDoorEntity.java b/forge/src/main/java/ziyue/tjmetro/mapping/MetalDetectionDoorEntity.java new file mode 100644 index 0000000..a9bb97d --- /dev/null +++ b/forge/src/main/java/ziyue/tjmetro/mapping/MetalDetectionDoorEntity.java @@ -0,0 +1,204 @@ +package ziyue.tjmetro.mapping; + +/** + * An entity for GUI of Metal Detection Door. This entity is a minecart-with-chest. + * + * @author ZiYueCommentary + * @see BlockMetalDetectionDoor + * @since 1.0.0-beta-2 + */ + +#if MC_VERSION >= "11902" + +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.vehicle.MinecartChest; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.inventory.MenuType; +import org.mtr.mapping.holder.BlockPos; +import org.mtr.mapping.holder.World; +import ziyue.tjmetro.mod.block.BlockMetalDetectionDoor; + +import javax.annotation.Nullable; + +public class MetalDetectionDoorEntity extends MinecartChest +{ + public final BlockMetalDetectionDoor.BlockEntity blockEntity; + + public MetalDetectionDoorEntity(World world, BlockPos blockPos, BlockMetalDetectionDoor.BlockEntity blockEntity) { + super(world.data, blockPos.getX(), -1, blockPos.getZ()); + this.blockEntity = blockEntity; + for (int i = 0; i < blockEntity.inventory.size(); i++) { + this.getItemStacks().set(i, blockEntity.inventory.get(i)); + } + } + + @Override + public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) { + return new ChestMenu(MenuType.GENERIC_9x1, syncId, playerInventory, this, 1) { + @Override + public void removed(Player player) { + super.removed(player); + final MetalDetectionDoorEntity entity = (MetalDetectionDoorEntity) this.getContainer(); + entity.blockEntity.setData(new DefaultedItemStackList(entity.getItemStacks())); + entity.getItemStacks().clear(); + entity.kill(); + } + }; + } + + @Override + public boolean isChestVehicleStillValid(Player p_219955_) { + return true; + } + + @Override + public boolean isNoGravity() { + return true; + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Nullable + @Override + public Component getCustomName() { + return Component.translatable("gui.tjmetro.metal_detection_door"); + } +} + +#elif MC_VERSION >= "11701" + +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.vehicle.MinecartChest; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.inventory.MenuType; +import org.mtr.mapping.holder.BlockPos; +import org.mtr.mapping.holder.World; +import ziyue.tjmetro.mod.block.BlockMetalDetectionDoor; + +import javax.annotation.Nullable; + +public class MetalDetectionDoorEntity extends MinecartChest +{ + public final BlockMetalDetectionDoor.BlockEntity blockEntity; + + public MetalDetectionDoorEntity(World world, BlockPos blockPos, BlockMetalDetectionDoor.BlockEntity blockEntity) { + super(world.data, blockPos.getX(), -1, blockPos.getZ()); + this.blockEntity = blockEntity; + for (int i = 0; i < blockEntity.inventory.size(); i++) { + ((ContainerAccessor) this).tianjin_Metro$getItemStacks().set(i, blockEntity.inventory.get(i)); + } + } + + @Override + public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) { + return new ChestMenu(MenuType.GENERIC_9x1, syncId, playerInventory, this, 1) + { + @Override + public void removed(Player player) { + super.removed(player); + final MetalDetectionDoorEntity entity = (MetalDetectionDoorEntity) this.getContainer(); + entity.blockEntity.setData(new DefaultedItemStackList(((ContainerAccessor) entity).tianjin_Metro$getItemStacks())); + ((ContainerAccessor) entity).tianjin_Metro$getItemStacks().clear(); + entity.kill(); + } + }; + } + + @Override + public boolean stillValid(Player p_38230_) { + return true; + } + + @Override + public boolean isNoGravity() { + return true; + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Nullable + @Override + public Component getCustomName() { + return new TranslatableComponent("gui.tjmetro.metal_detection_door"); + } +} + +#else + +import net.minecraft.entity.item.minecart.ChestMinecartEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ChestContainer; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import org.mtr.mapping.holder.BlockPos; +import org.mtr.mapping.holder.World; +import ziyue.tjmetro.mod.block.BlockMetalDetectionDoor; + +import javax.annotation.Nullable; + +public class MetalDetectionDoorEntity extends ChestMinecartEntity +{ + public final BlockMetalDetectionDoor.BlockEntity blockEntity; + + public MetalDetectionDoorEntity(World world, BlockPos blockPos, BlockMetalDetectionDoor.BlockEntity blockEntity) { + super(world.data, blockPos.getX(), -1, blockPos.getZ()); + this.blockEntity = blockEntity; + for (int i = 0; i < blockEntity.inventory.size(); i++) { + ((ContainerAccessor) this).tianjin_Metro$getItemStacks().set(i, blockEntity.inventory.get(i)); + } + } + + @Override + public Container createMenu(int syncId, PlayerInventory playerInventory) { + return new ChestContainer(ContainerType.GENERIC_9x1, syncId, playerInventory, this, 1) + { + @Override + public void removed(PlayerEntity player) { + super.removed(player); + final MetalDetectionDoorEntity entity = (MetalDetectionDoorEntity) this.getContainer(); + entity.blockEntity.setData(new DefaultedItemStackList(((ContainerAccessor) entity).tianjin_Metro$getItemStacks())); + ((ContainerAccessor) entity).tianjin_Metro$getItemStacks().clear(); + entity.kill(); + } + }; + } + + @Override + public boolean stillValid(PlayerEntity p_38230_) { + return true; + } + + @Override + public boolean isNoGravity() { + return true; + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Nullable + @Override + public ITextComponent getCustomName() { + return new TranslationTextComponent("gui.tjmetro.metal_detection_door"); + } +} + +#endif \ No newline at end of file diff --git a/forge/src/main/java/ziyue/tjmetro/mapping/PlayerInventoryHelper.java b/forge/src/main/java/ziyue/tjmetro/mapping/PlayerInventoryHelper.java new file mode 100644 index 0000000..ea79a59 --- /dev/null +++ b/forge/src/main/java/ziyue/tjmetro/mapping/PlayerInventoryHelper.java @@ -0,0 +1,66 @@ +package ziyue.tjmetro.mapping; + +/** + * @author ZiYueCommentary + * @since 1.0.0-beta-2 + */ + +#if MC_VERSION >= "11701" + +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.mtr.mapping.holder.PlayerEntity; + +import java.util.function.Function; + +public class PlayerInventoryHelper +{ + public static void clearItems(PlayerEntity player, Function filter) { + final NonNullList items = player.data.getInventory().items; + for (int i = 0; i < items.size(); i++) { + if (filter.apply(items.get(i).getItem())) items.set(i, ItemStack.EMPTY); + } + + final NonNullList armor = player.data.getInventory().armor; + for (int i = 0; i < armor.size(); i++) { + if (filter.apply(armor.get(i).getItem())) armor.set(i, ItemStack.EMPTY); + } + + final NonNullList offhand = player.data.getInventory().offhand; + for (int i = 0; i < offhand.size(); i++) { + if (filter.apply(offhand.get(i).getItem())) offhand.set(i, ItemStack.EMPTY); + } + } +} + +#else + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import org.mtr.mapping.holder.PlayerEntity; + +import java.util.function.Function; + +public class PlayerInventoryHelper +{ + public static void clearItems(PlayerEntity player, Function filter) { + final NonNullList items = player.data.inventory.items; + for (int i = 0; i < items.size(); i++) { + if (filter.apply(items.get(i).getItem())) items.set(i, ItemStack.EMPTY); + } + + final NonNullList armor = player.data.inventory.armor; + for (int i = 0; i < armor.size(); i++) { + if (filter.apply(armor.get(i).getItem())) armor.set(i, ItemStack.EMPTY); + } + + final NonNullList offhand = player.data.inventory.offhand; + for (int i = 0; i < offhand.size(); i++) { + if (filter.apply(offhand.get(i).getItem())) offhand.set(i, ItemStack.EMPTY); + } + } +} + +#endif diff --git a/forge/src/main/java/ziyue/tjmetro/mapping/RegistryHelper.java b/forge/src/main/java/ziyue/tjmetro/mapping/RegistryHelper.java index 7c61f83..18000a3 100644 --- a/forge/src/main/java/ziyue/tjmetro/mapping/RegistryHelper.java +++ b/forge/src/main/java/ziyue/tjmetro/mapping/RegistryHelper.java @@ -8,20 +8,56 @@ import java.lang.reflect.InvocationTargetException; /** - * Converting block to item. This may not be stable since it uses reflection. - * * @author ZiYueCommentary * @since 1.0.0-beta-2 */ -// This is a very mad way but I have no choice. public interface RegistryHelper { static ItemRegistryObject RegistryObjectBlock2Item(BlockRegistryObject fabric, Identifier forge) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException { + // This is a very mad way but I have no choice. Class clazz = ItemRegistryObject.class; Constructor constructor = clazz.getDeclaredConstructor(Identifier.class); constructor.setAccessible(true); return constructor.newInstance(forge); } + +#if MC_VERSION >= "11701" + + static net.minecraft.world.item.ItemStack cloneSingleItemStack(net.minecraft.world.item.ItemStack itemStack) { + return new net.minecraft.world.item.ItemStack(itemStack.getItem()); + } + + static Identifier getIdentifierByItem(net.minecraft.world.item.Item item) { +#if MC_VERSION >= "11902" + return new Identifier(net.minecraft.core.registries.BuiltInRegistries.ITEM.getKey(item)); +#else + return new Identifier(net.minecraft.core.Registry.ITEM.getKey(item)); +#endif + } + + static net.minecraft.world.item.ItemStack getItemStackByIdentifier(Identifier identifier) { +#if MC_VERSION >= "11902" + return net.minecraft.core.registries.BuiltInRegistries.ITEM.get(identifier.data).getDefaultInstance(); +#else + return net.minecraft.core.Registry.ITEM.get(identifier.data).getDefaultInstance(); +#endif + } + +#else + + static net.minecraft.item.ItemStack cloneSingleItemStack(net.minecraft.item.ItemStack itemStack) { + return new net.minecraft.item.ItemStack(itemStack.getItem()); + } + + static Identifier getIdentifierByItem(net.minecraft.item.Item item) { + return new Identifier(net.minecraft.util.registry.Registry.ITEM.getKey(item)); + } + + static net.minecraft.item.ItemStack getItemStackByIdentifier(Identifier identifier) { + return net.minecraft.util.registry.Registry.ITEM.get(identifier.data).getDefaultInstance(); + } + +#endif } diff --git a/forge/src/main/resources/tjmetro-forge.mixins.json b/forge/src/main/resources/tjmetro-forge.mixins.json index c836508..6459c9d 100644 --- a/forge/src/main/resources/tjmetro-forge.mixins.json +++ b/forge/src/main/resources/tjmetro-forge.mixins.json @@ -4,8 +4,9 @@ "package": "ziyue.tjmetro.forge.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ - "GameRuleBooleanAccessor", - "FallingBlockMixin" + "AbstractMinecartContainerMixin", + "FallingBlockMixin", + "GameRuleBooleanAccessor" ], "injectors": { "defaultRequire": 1