diff --git a/src/main/java/com/lovetropics/gamemodebuild/message/GBNetwork.java b/src/main/java/com/lovetropics/gamemodebuild/message/GBNetwork.java index 913a95d..2bcc14e 100644 --- a/src/main/java/com/lovetropics/gamemodebuild/message/GBNetwork.java +++ b/src/main/java/com/lovetropics/gamemodebuild/message/GBNetwork.java @@ -22,6 +22,11 @@ public static void register(RegisterPayloadHandlersEvent event) { UpdateFilterMessage.CODEC, UpdateFilterMessage::handle ); + registrar.playToServer( + SetGamemodeBuildSlotPacket.TYPE, + SetGamemodeBuildSlotPacket.CODEC, + SetGamemodeBuildSlotPacket::handle + ); registrar.playBidirectional( SetActiveMessage.TYPE, diff --git a/src/main/java/com/lovetropics/gamemodebuild/message/SetGamemodeBuildSlotPacket.java b/src/main/java/com/lovetropics/gamemodebuild/message/SetGamemodeBuildSlotPacket.java new file mode 100644 index 0000000..e56ac85 --- /dev/null +++ b/src/main/java/com/lovetropics/gamemodebuild/message/SetGamemodeBuildSlotPacket.java @@ -0,0 +1,96 @@ +package com.lovetropics.gamemodebuild.message; + +import com.lovetropics.gamemodebuild.GBConfigs; +import com.lovetropics.gamemodebuild.GamemodeBuild; +import com.lovetropics.gamemodebuild.container.BuildContainer; +import com.lovetropics.gamemodebuild.state.GBPlayerStore; +import com.lovetropics.gamemodebuild.state.GBServerState; +import net.minecraft.core.BlockPos; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.PacketUtils; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +import java.util.List; + +public record SetGamemodeBuildSlotPacket(short slotNum, ItemStack itemStack) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(GamemodeBuild.rl("set_slot")); + public static final StreamCodec CODEC; + static { + CODEC = StreamCodec.composite(ByteBufCodecs.SHORT, SetGamemodeBuildSlotPacket::slotNum, ItemStack.validatedStreamCodec(ItemStack.OPTIONAL_STREAM_CODEC), SetGamemodeBuildSlotPacket::itemStack, SetGamemodeBuildSlotPacket::new); + } + + public SetGamemodeBuildSlotPacket(short slotNum, ItemStack itemStack) { + this.slotNum = slotNum; + this.itemStack = itemStack; + } + + public static void handle(SetGamemodeBuildSlotPacket packet, IPayloadContext ctx) { + var player = ctx.player(); + + if (player instanceof ServerPlayer serverPlayer) { + ctx.enqueueWork(() -> { + if (GBServerState.isActiveFor(serverPlayer)) { + ItemStack itemstack = packet.itemStack(); + + FeatureFlagSet featureFlags = player.level().enabledFeatures(); + RegistryAccess registryAccess = player.level().registryAccess(); + List itemStacks = GBConfigs.SERVER.getFilter(GBPlayerStore.getList(player)).getAllStacks(featureFlags, registryAccess); + + if(!itemStacks.stream().anyMatch(stack -> stack.is(packet.itemStack.getItem()))) { + player.inventoryMenu.setRemoteSlot(packet.slotNum, packet.itemStack); + player.inventoryMenu.broadcastChanges(); + return; + } + + if (!itemstack.isItemEnabled(player.level().enabledFeatures())) { + return; + } + + CustomData customdata = itemstack.getOrDefault(DataComponents.BLOCK_ENTITY_DATA, CustomData.EMPTY); + if (customdata.contains("x") && customdata.contains("y") && customdata.contains("z")) { + BlockPos blockpos = BlockEntity.getPosFromTag(customdata.getUnsafe()); + if (player.level().isLoaded(blockpos)) { + BlockEntity blockentity = player.level().getBlockEntity(blockpos); + if (blockentity != null) { + blockentity.saveToItem(itemstack, player.level().registryAccess()); + } + } + } + + boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45; + boolean flag2 = itemstack.isEmpty() || itemstack.getCount() <= itemstack.getMaxStackSize(); + if (flag1 && flag2) { + player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemstack); + player.inventoryMenu.broadcastChanges(); + } + } + }); + } + } + + @Override + public Type type() { + return TYPE; + } + + + public short slotNum() { + return this.slotNum; + } + + public ItemStack itemStack() { + return this.itemStack; + } +} diff --git a/src/main/java/com/lovetropics/gamemodebuild/mixin/MinecraftMixin.java b/src/main/java/com/lovetropics/gamemodebuild/mixin/MinecraftMixin.java new file mode 100644 index 0000000..ed0f4fd --- /dev/null +++ b/src/main/java/com/lovetropics/gamemodebuild/mixin/MinecraftMixin.java @@ -0,0 +1,52 @@ +package com.lovetropics.gamemodebuild.mixin; + +import com.llamalad7.mixinextras.sugar.Local; +import com.lovetropics.gamemodebuild.container.GBStackMarker; +import com.lovetropics.gamemodebuild.state.GBClientState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.HitResult; +import org.spongepowered.asm.mixin.Debug; +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.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; + +import javax.annotation.Nullable; + +@Debug(export = true) +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Shadow @Nullable public LocalPlayer player; + + @ModifyVariable(method = "pickBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/HitResult;getType()Lnet/minecraft/world/phys/HitResult$Type;", shift = At.Shift.BY, by = 2)) + private boolean flagInsta(boolean value, @Local(ordinal = 0) HitResult.Type type) { + if(GBClientState.isActive() && type == HitResult.Type.BLOCK) { + return true; + } + return value; + } + + @ModifyVariable(method = "pickBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", ordinal = 0)) + private ItemStack addTag(ItemStack itemStack) { + if(GBClientState.isActive()) { + GBStackMarker.mark(itemStack); + } + return itemStack; + } + + @Redirect( + method = "pickBlock", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;hasControlDown()Z") + ) + private boolean redirectHasControlDown() { + if(GBClientState.isActive()) { + return false; + } + return Screen.hasControlDown(); + } +} diff --git a/src/main/java/com/lovetropics/gamemodebuild/mixin/MultiPlayerGameModeMixin.java b/src/main/java/com/lovetropics/gamemodebuild/mixin/MultiPlayerGameModeMixin.java new file mode 100644 index 0000000..96883de --- /dev/null +++ b/src/main/java/com/lovetropics/gamemodebuild/mixin/MultiPlayerGameModeMixin.java @@ -0,0 +1,26 @@ +package com.lovetropics.gamemodebuild.mixin; + +import com.lovetropics.gamemodebuild.message.SetGamemodeBuildSlotPacket; +import com.lovetropics.gamemodebuild.state.GBClientState; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.GameType; +import net.neoforged.neoforge.network.PacketDistributor; +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.CallbackInfo; + +@Mixin(MultiPlayerGameMode.class) +public class MultiPlayerGameModeMixin { + + @Shadow private GameType localPlayerMode; + + @Inject(method = "handleCreativeModeItemAdd", at = @At(value = "HEAD")) + private void redirectIsCreative(ItemStack stack, int slotId, CallbackInfo ci) { + if(this.localPlayerMode != GameType.CREATIVE && GBClientState.isActive()) { + PacketDistributor.sendToServer(new SetGamemodeBuildSlotPacket((short) slotId, stack)); + } + } +} diff --git a/src/main/resources/gamemodebuild.mixins.json b/src/main/resources/gamemodebuild.mixins.json index 1412a87..7d24d65 100644 --- a/src/main/resources/gamemodebuild.mixins.json +++ b/src/main/resources/gamemodebuild.mixins.json @@ -8,5 +8,9 @@ "injectors": { "defaultRequire": 1 }, - "minVersion": "0.8" + "minVersion": "0.8", + "client": [ + "MinecraftMixin", + "MultiPlayerGameModeMixin" + ] }