diff --git a/src/main/java/net/moonleay/gimbal/mixin/NoClipCameraFixMixin.java b/src/main/java/net/moonleay/gimbal/mixin/NoClipCameraFixMixin.java deleted file mode 100644 index 55a8882..0000000 --- a/src/main/java/net/moonleay/gimbal/mixin/NoClipCameraFixMixin.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Gimbal - * Copyright (C) 2024 moonleay - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.moonleay.gimbal.mixin; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.Camera; -import net.moonleay.gimbal.client.editor.ClientEditor; -import net.moonleay.gimbal.editor.state.mode.Capability; -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; - -@Mixin(Camera.class) -public class NoClipCameraFixMixin { - - @Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true) - private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable cir) { - if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) { - return; - } - cir.setReturnValue(desiredCameraDistance); - cir.cancel(); - } -} diff --git a/src/main/java/net/moonleay/gimbal/mixin/NoClipMixin.java b/src/main/java/net/moonleay/gimbal/mixin/NoClipMixin.java index fafab39..8e9a80a 100644 --- a/src/main/java/net/moonleay/gimbal/mixin/NoClipMixin.java +++ b/src/main/java/net/moonleay/gimbal/mixin/NoClipMixin.java @@ -19,12 +19,15 @@ package net.moonleay.gimbal.mixin; import com.mojang.authlib.GameProfile; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.Camera; import net.minecraft.entity.EntityPose; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerAbilities; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.World; +import net.moonleay.gimbal.client.editor.ClientEditor; import net.moonleay.gimbal.editor.ServerEditorManager; import net.moonleay.gimbal.editor.state.mode.Capability; import org.spongepowered.asm.mixin.Mixin; @@ -32,51 +35,72 @@ 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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.UUID; -@Mixin(PlayerEntity.class) -public abstract class NoClipMixin extends LivingEntity { - @Shadow public abstract GameProfile getGameProfile(); +public abstract class NoClipMixin { - @Shadow public abstract PlayerAbilities getAbilities(); - - @Shadow - public abstract boolean isCreative(); - - protected NoClipMixin(EntityType entityType, World world) { - super(entityType, world); - } // Server side - - - @Inject(method = "tick", at = @At(value = "FIELD", - target = "Lnet/minecraft/entity/player/PlayerEntity;noClip:Z", shift = At.Shift.AFTER) - ) private void enoClip(CallbackInfo ci) { - if (!this.isCreative()) - return; - UUID uuid = this.getGameProfile().getId(); - - if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) { - return; // NoClip is not enabled + @Mixin(PlayerEntity.class) // Serverside, allows clipping + public static abstract class PlayerEntityMixin extends LivingEntity { + protected PlayerEntityMixin(EntityType entityType, World world) { + super(entityType, world); } - if (!this.getAbilities().flying) { - return; + + @Shadow + public abstract GameProfile getGameProfile(); + + @Shadow + public abstract PlayerAbilities getAbilities(); + + @Shadow + public abstract boolean isCreative(); + + @Inject(method = "tick", at = @At(value = "FIELD", + target = "Lnet/minecraft/entity/player/PlayerEntity;noClip:Z", shift = At.Shift.AFTER) + ) + private void enoClip(CallbackInfo ci) { + if (!this.isCreative()) + return; + UUID uuid = this.getGameProfile().getId(); + + if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) { + return; // NoClip is not enabled + } + if (!this.getAbilities().flying) { + return; + } + // Enable NoClip + this.noClip = true; + } + + @Inject(method = "updatePose", at = @At("HEAD")) + private void onUpdatePose(CallbackInfo ci) { + UUID uuid = this.getGameProfile().getId(); + + if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) + return; // NoClip is not enabled + if (!this.getAbilities().flying) + return; + + // Force standing pose in NoClip mode + + this.setPose(EntityPose.STANDING); } - // Enable NoClip - this.noClip = true; } - @Inject(method = "updatePose", at = @At("HEAD")) - private void onUpdatePose(CallbackInfo ci) { - UUID uuid = this.getGameProfile().getId(); - if (!ServerEditorManager.INSTANCE.shouldPlayer(uuid, Capability.NO_CLIP)) - return; // NoClip is not enabled - if (!this.getAbilities().flying) - return; + @Mixin(Camera.class) // Clientside, fixes camera + public static abstract class CameraMixin { - // Force standing pose in NoClip mode - - this.setPose(EntityPose.STANDING); + @Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true) + private void fixCameraInNoClip(double desiredCameraDistance, CallbackInfoReturnable cir) { + if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) { + return; + } + cir.setReturnValue(desiredCameraDistance); + cir.cancel(); + } } + } diff --git a/src/main/java/net/moonleay/gimbal/mixin/ReplaceModeMixin.java b/src/main/java/net/moonleay/gimbal/mixin/ReplaceModeMixin.java index 8e2a4fa..8a28216 100644 --- a/src/main/java/net/moonleay/gimbal/mixin/ReplaceModeMixin.java +++ b/src/main/java/net/moonleay/gimbal/mixin/ReplaceModeMixin.java @@ -18,50 +18,87 @@ package net.moonleay.gimbal.mixin; +import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemUsageContext; +import net.minecraft.item.*; +import net.minecraft.state.property.Property; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.moonleay.gimbal.editor.ServerEditorManager; import net.moonleay.gimbal.editor.state.mode.Capability; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.UUID; -@Mixin(ItemPlacementContext.class) -public abstract class ReplaceModeMixin extends ItemUsageContext { +public abstract class ReplaceModeMixin { - @Shadow - protected boolean canReplaceExisting; + @Mixin(ItemPlacementContext.class) + public static abstract class ItemPlacementContextMixin extends ItemUsageContext { + @Shadow + protected boolean canReplaceExisting; - @Mutable - @Shadow - @Final - private BlockPos placementPos; + @Mutable + @Shadow + @Final + private BlockPos placementPos; - public ReplaceModeMixin(PlayerEntity player, Hand hand, BlockHitResult hit) { - super(player, hand, hit); + public ItemPlacementContextMixin(PlayerEntity player, Hand hand, BlockHitResult hit) { + super(player, hand, hit); + } + + @Inject(method = "(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/hit/BlockHitResult;)V", at = @At(value = "RETURN")) + private void func(World world, PlayerEntity playerEntity, Hand hand, ItemStack itemStack, BlockHitResult blockHitResult, CallbackInfo ci) { + if (playerEntity == null) + return; + UUID id = playerEntity.getGameProfile().getId(); + if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE)) + return; + + this.canReplaceExisting = true; + this.placementPos = blockHitResult.getBlockPos(); + } } - @Inject(method = "(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/hit/BlockHitResult;)V", at = @At(value = "RETURN")) - private void func(World world, PlayerEntity playerEntity, Hand hand, ItemStack itemStack, BlockHitResult blockHitResult, CallbackInfo ci) { - if (playerEntity == null) - return; - UUID id = playerEntity.getGameProfile().getId(); - if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE)) - return; + @Mixin(BlockItem.class) + public static abstract class BlockItemMixin extends Item { - this.canReplaceExisting = true; - this.placementPos = blockHitResult.getBlockPos(); + public BlockItemMixin(Settings settings) { + super(settings); + } + + @Shadow + protected abstract boolean place(ItemPlacementContext context, BlockState state); + + @Redirect(method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;place(Lnet/minecraft/item/ItemPlacementContext;Lnet/minecraft/block/BlockState;)Z")) + private boolean func(BlockItem instance, ItemPlacementContext context, BlockState state) { + if (context.getPlayer() == null) + return this.place(context, state); + UUID id = context.getPlayer().getGameProfile().getId(); + if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE)) + return this.place(context, state); + BlockState oldState = context.getWorld().getBlockState(context.getBlockPos()); + return this.place(context, getTargetBlockState(oldState, instance.getBlock().getDefaultState())); + } + + @Unique + public BlockState getTargetBlockState(BlockState oldState, BlockState newBlock) { + var oldManager = oldState.getBlock().getStateManager(); + var newManager = newBlock.getBlock().getStateManager(); + for (var prop : oldManager.getProperties()) { + var matchingProp = newManager.getProperty(prop.getName()); + if (matchingProp != null) { + //noinspection rawtypes,unchecked + newBlock = newBlock.with((Property) matchingProp, oldState.get(matchingProp)); + } + } + return newBlock; + } } + } diff --git a/src/main/java/net/moonleay/gimbal/mixin/ReplaceStateUpdaterMixin.java b/src/main/java/net/moonleay/gimbal/mixin/ReplaceStateUpdaterMixin.java deleted file mode 100644 index 255604a..0000000 --- a/src/main/java/net/moonleay/gimbal/mixin/ReplaceStateUpdaterMixin.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Gimbal - * Copyright (C) 2024 moonleay - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.moonleay.gimbal.mixin; - -import net.minecraft.block.BlockState; -import net.minecraft.item.BlockItem; -import net.minecraft.item.Item; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.state.property.Property; -import net.moonleay.gimbal.editor.ServerEditorManager; -import net.moonleay.gimbal.editor.state.mode.Capability; -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.Redirect; - -import java.util.UUID; - -@Mixin(BlockItem.class) -public abstract class ReplaceStateUpdaterMixin extends Item { - - public ReplaceStateUpdaterMixin(Settings settings) { - super(settings); - } - - @Shadow - protected abstract boolean place(ItemPlacementContext context, BlockState state); - - @Redirect(method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;place(Lnet/minecraft/item/ItemPlacementContext;Lnet/minecraft/block/BlockState;)Z")) - private boolean func(BlockItem instance, ItemPlacementContext context, BlockState state) { - if (context.getPlayer() == null) - return this.place(context, state); - UUID id = context.getPlayer().getGameProfile().getId(); - if (!ServerEditorManager.INSTANCE.shouldPlayer(id, Capability.REPLACE)) - return this.place(context, state); - BlockState oldState = context.getWorld().getBlockState(context.getBlockPos()); - return this.place(context, getTargetBlockState(oldState, instance.getBlock().getDefaultState())); - } - - @Unique - public BlockState getTargetBlockState(BlockState oldState, BlockState newBlock) { - var oldManager = oldState.getBlock().getStateManager(); - var newManager = newBlock.getBlock().getStateManager(); - for (var prop : oldManager.getProperties()) { - var matchingProp = newManager.getProperty(prop.getName()); - if (matchingProp != null) { - //noinspection rawtypes,unchecked - newBlock = newBlock.with((Property) matchingProp, oldState.get(matchingProp)); - } - } - return newBlock; - } -} diff --git a/src/main/resources/gimbal.mixins.json b/src/main/resources/gimbal.mixins.json index b383149..0babedd 100644 --- a/src/main/resources/gimbal.mixins.json +++ b/src/main/resources/gimbal.mixins.json @@ -6,15 +6,15 @@ "mixins": [ "ForcePlaceMixin", "NoBlockUpdatesMixin", - "NoClipMixin", - "ReplaceModeMixin", - "ReplaceStateUpdaterMixin" + "NoClipMixin$PlayerEntityMixin", + "ReplaceModeMixin$BlockItemMixin", + "ReplaceModeMixin$ItemPlacementContextMixin" ], "client": [ "BulldozerMixin$ClientPlayerInteractionManagerMixin", "BulldozerMixin$MinecraftClientMixin", "HudMixin", - "NoClipCameraFixMixin", + "NoClipMixin$CameraMixin", "NormalModeMixin", "YouInjectButtonMixin$GameMenuScreenMixin", "YouInjectButtonMixin$TitleScreenMixin"