diff --git a/README.md b/README.md index 23b0a23..e3bf524 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ carpet >= 1.4.45+v210811 - [白天睡觉](#白天睡觉-sleepingDuringTheDay) - [发射器修复铁傀儡](#发射器修复铁傀儡-dispenserFixIronGolem) - [发射器收集经验](#发射器收集经验-dispenserCollectXp) +- [玩家操作限制器](#玩家操作限制器-playerOperationLimiter) - [PCA 调试模式](#PCA-调试模式-pcaDebug) ## 规则列表 @@ -232,6 +233,15 @@ Carpet 默认实现的潜影盒可堆叠只能让潜影盒在地面上堆叠, - 参考选项: `true`, `false` - 分类: `PCA`, `feature`, `dispenser` +### 玩家操作限制器 (playerOperationLimiter) + +每 gt 玩家可以放置 2 个方块,秒破 1 个方块,这两个操作每 gt 只能做一种(用于防人肉盾构机和玩家自动破基岩 mod) + +- 类型: `boolean` +- 默认值: `false` +- 参考选项: `true`, `false` +- 分类: `PCA`, `feature` + ### PCA 调试模式 (pcaDebug) 开启后会打印调试信息 diff --git a/gradle.properties b/gradle.properties index 41dc9c5..e45d93b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ loader_version=0.11.6 # carpet_core_version=1.4.45+v210811 carpet_core_version=3422601 # Mod Properties -mod_version=0.2.0 +mod_version=0.2.1 maven_group=net.fabricmc archives_base_name=plusls-carpet-addition # Dependencies diff --git a/src/main/java/com/plusls/carpet/PcaSettings.java b/src/main/java/com/plusls/carpet/PcaSettings.java index b975927..71dd794 100644 --- a/src/main/java/com/plusls/carpet/PcaSettings.java +++ b/src/main/java/com/plusls/carpet/PcaSettings.java @@ -162,6 +162,12 @@ public enum PCA_SPAWN_BIOME { ) public static boolean dispenserCollectXp = false; + @Rule( + desc = "One tick player can place 2 block, insta break 1 block, can't do it at the same tick", + category = {PCA, RuleCategory.FEATURE} + ) + public static boolean playerOperationLimiter = false; + // debug @Rule( desc = "pcaDebug mode", diff --git a/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinBlockItem.java b/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinBlockItem.java new file mode 100644 index 0000000..ecd0a13 --- /dev/null +++ b/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinBlockItem.java @@ -0,0 +1,47 @@ +package com.plusls.carpet.mixin.rule.playerOperationLimiter; + +import com.plusls.carpet.PcaSettings; +import com.plusls.carpet.util.rule.playerOperationLimiter.SafeServerPlayerEntity; +import net.minecraft.block.BlockState; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.util.ActionResult; +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; + +@Mixin(BlockItem.class) +public abstract class MixinBlockItem extends Item { + public MixinBlockItem(Settings settings) { + super(settings); + } + + @Shadow + public abstract ItemPlacementContext getPlacementContext(ItemPlacementContext context); + + @Shadow + protected abstract BlockState getPlacementState(ItemPlacementContext context); + + @Inject(method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", at = @At(value = "HEAD"), cancellable = true) + private void checkOperationCountPerTick(ItemPlacementContext context, CallbackInfoReturnable cir) { + if (!PcaSettings.playerOperationLimiter || context.getWorld().isClient()) { + return; + } + + if (context.canPlace()) { + ItemPlacementContext itemPlacementContext = this.getPlacementContext(context); + SafeServerPlayerEntity safeServerPlayerEntity = (SafeServerPlayerEntity) context.getPlayer(); + if (safeServerPlayerEntity != null && itemPlacementContext != null && this.getPlacementState(itemPlacementContext) != null) { + safeServerPlayerEntity.addPlaceBlockCountPerTick(); + if (!safeServerPlayerEntity.allowOperation()) { + cir.setReturnValue(ActionResult.FAIL); + } + } + + } + + } +} diff --git a/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinServerPlayerEntity.java b/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinServerPlayerEntity.java new file mode 100644 index 0000000..ff973d7 --- /dev/null +++ b/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinServerPlayerEntity.java @@ -0,0 +1,45 @@ +package com.plusls.carpet.mixin.rule.playerOperationLimiter; + +import com.plusls.carpet.util.rule.playerOperationLimiter.SafeServerPlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +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.CallbackInfo; + +@Mixin(ServerPlayerEntity.class) +public class MixinServerPlayerEntity implements SafeServerPlayerEntity { + private int instaBreakCountPerTick = 0; + private int placeBlockCountPerTick = 0; + + @Inject(method = "tick", at = @At(value = "HEAD")) + private void resetOperationCountPerTick(CallbackInfo ci) { + instaBreakCountPerTick = 0; + placeBlockCountPerTick = 0; + } + + @Override + public int getInstaBreakCountPerTick() { + return instaBreakCountPerTick; + } + + @Override + public int getPlaceBlockCountPerTick() { + return placeBlockCountPerTick; + } + + @Override + public void addInstaBreakCountPerTick() { + ++instaBreakCountPerTick; + } + + @Override + public void addPlaceBlockCountPerTick() { + ++placeBlockCountPerTick; + } + + @Override + public boolean allowOperation() { + return (instaBreakCountPerTick == 0 || placeBlockCountPerTick == 0) && (instaBreakCountPerTick <= 1 && placeBlockCountPerTick <= 2); + } +} diff --git a/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinServerPlayerInteractionManager.java b/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinServerPlayerInteractionManager.java new file mode 100644 index 0000000..7a9fa03 --- /dev/null +++ b/src/main/java/com/plusls/carpet/mixin/rule/playerOperationLimiter/MixinServerPlayerInteractionManager.java @@ -0,0 +1,42 @@ +package com.plusls.carpet.mixin.rule.playerOperationLimiter; + +import com.plusls.carpet.PcaSettings; +import com.plusls.carpet.util.rule.playerOperationLimiter.SafeServerPlayerEntity; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.network.packet.s2c.play.PlayerActionResponseS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.ServerPlayerInteractionManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +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.CallbackInfo; + +@Mixin(ServerPlayerInteractionManager.class) +public class MixinServerPlayerInteractionManager { + + @Final + @Shadow + protected ServerPlayerEntity player; + + @Shadow + protected ServerWorld world; + + @Inject(method = "processBlockBreakingAction", at=@At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerInteractionManager;finishMining(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/network/packet/c2s/play/PlayerActionC2SPacket$Action;Ljava/lang/String;)V", ordinal = 1), cancellable = true) + private void checkOperationCountPerTick(BlockPos pos, PlayerActionC2SPacket.Action action, Direction direction, int worldHeight, CallbackInfo ci) { + if (!PcaSettings.playerOperationLimiter) { + return; + } + SafeServerPlayerEntity safeServerPlayerEntity = (SafeServerPlayerEntity)player; + safeServerPlayerEntity.addInstaBreakCountPerTick(); + if (!safeServerPlayerEntity.allowOperation()) { + this.player.networkHandler.sendPacket(new PlayerActionResponseS2CPacket(pos, this.world.getBlockState(pos), action, false, "insta mine")); + ci.cancel(); + } + } + +} diff --git a/src/main/java/com/plusls/carpet/util/rule/playerOperationLimiter/SafeServerPlayerEntity.java b/src/main/java/com/plusls/carpet/util/rule/playerOperationLimiter/SafeServerPlayerEntity.java new file mode 100644 index 0000000..4ff4d59 --- /dev/null +++ b/src/main/java/com/plusls/carpet/util/rule/playerOperationLimiter/SafeServerPlayerEntity.java @@ -0,0 +1,9 @@ +package com.plusls.carpet.util.rule.playerOperationLimiter; + +public interface SafeServerPlayerEntity { + int getInstaBreakCountPerTick(); + int getPlaceBlockCountPerTick(); + void addInstaBreakCountPerTick(); + void addPlaceBlockCountPerTick(); + boolean allowOperation(); +} diff --git a/src/main/resources/assets/pca/lang/zh_cn.json b/src/main/resources/assets/pca/lang/zh_cn.json index 1dde1f1..281bc80 100644 --- a/src/main/resources/assets/pca/lang/zh_cn.json +++ b/src/main/resources/assets/pca/lang/zh_cn.json @@ -48,6 +48,8 @@ "rule.dispenserFixIronGolem.desc": "发射器可以使用铁锭来修复铁傀儡", "rule.dispenserCollectXp.name": "发射器收集经验", "rule.dispenserCollectXp.desc": "发射器消耗玻璃瓶来收集经验,产出附魔之瓶", + "rule.playerOperationLimiter.name": "玩家操作限制器", + "rule.playerOperationLimiter.desc": "每 gt 玩家可以放置 2 个方块,秒破 1 个方块,这两个操作每 gt 只能做一种(用于防人肉盾构机和玩家自动破基岩 mod)", "rule.pcaDebug.name": "PCA调试模式", "rule.pcaDebug.desc": "打印更多调试信息" } diff --git a/src/main/resources/pca.mixins.json b/src/main/resources/pca.mixins.json index 083d6c0..3839054 100644 --- a/src/main/resources/pca.mixins.json +++ b/src/main/resources/pca.mixins.json @@ -11,6 +11,9 @@ "rule.flippingTotemOfUndying.MixinBlockRotator", "rule.gravestone.MixinPlayerSkullBlock", "rule.gravestone.MixinSkullBlockEntity", + "rule.playerOperationLimiter.MixinBlockItem", + "rule.playerOperationLimiter.MixinServerPlayerEntity", + "rule.playerOperationLimiter.MixinServerPlayerInteractionManager", "rule.pcaSyncProtocol.block.MixinAbstractFurnaceBlockEntity", "rule.pcaSyncProtocol.block.MixinBarrelBlockEntity", "rule.pcaSyncProtocol.block.MixinBeehiveBlockEntity",