mirror of
https://codeberg.org/moonleay/Gimbal.git
synced 2024-11-25 22:22:10 +00:00
refactor: combined NoClip and ReplaceMode mixins into one mixin each
Signed-off-by: moonleay <contact@moonleay.net>
This commit is contained in:
parent
4c8404d306
commit
6a89e5683f
5 changed files with 127 additions and 177 deletions
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Double> cir) {
|
||||
if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) {
|
||||
return;
|
||||
}
|
||||
cir.setReturnValue(desiredCameraDistance);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
|
@ -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<? extends LivingEntity> 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<? extends LivingEntity> 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<Double> cir) {
|
||||
if (!ClientEditor.INSTANCE.shouldClient(Capability.NO_CLIP) || (!(MinecraftClient.getInstance().player != null && MinecraftClient.getInstance().player.isCreative()))) {
|
||||
return;
|
||||
}
|
||||
cir.setReturnValue(desiredCameraDistance);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 = "<init>(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 = "<init>(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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue