diff --git a/build.gradle b/build.gradle index d565dc1c..b81ac0b2 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,9 @@ group = project.maven_group repositories { mavenCentral() + maven { + url 'https://masa.dy.fi/maven' + } maven { url "https://cursemaven.com" } @@ -36,7 +39,7 @@ dependencies { // MaLiLib, required on client modImplementation "curse.maven:malilib-303119:4623483" // carpet, required on client & server - modImplementation "curse.maven:carpet-349239:4573334" + modImplementation "carpet:fabric-carpet:1.20-1.4.112+v230608" // Game test testImplementation "net.fabricmc:fabric-loader-junit:${project.loader_version}" // Conditional Mixin diff --git a/src/main/java/com/github/zly2006/reden/access/PlayerData.kt b/src/main/java/com/github/zly2006/reden/access/PlayerData.kt index b436be9a..7c9a9aff 100644 --- a/src/main/java/com/github/zly2006/reden/access/PlayerData.kt +++ b/src/main/java/com/github/zly2006/reden/access/PlayerData.kt @@ -2,7 +2,6 @@ package com.github.zly2006.reden.access import com.github.zly2006.reden.carpet.RedenCarpetSettings import com.github.zly2006.reden.malilib.UNDO_CHEATING_ONLY -import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper import com.github.zly2006.reden.utils.isClient import com.github.zly2006.reden.utils.isSinglePlayerAndCheating import net.minecraft.command.EntitySelector @@ -32,10 +31,6 @@ class PlayerData( var isRecording: Boolean = false var pearlListening: Boolean = false - fun stopRecording(world: World) { - UpdateMonitorHelper.playerStopRecording(player) - } - data class Entry( val blockState: NbtCompound, val blockEntity: NbtCompound?, diff --git a/src/main/java/com/github/zly2006/reden/access/UndoRecordContainer.kt b/src/main/java/com/github/zly2006/reden/access/UndoRecordContainer.kt deleted file mode 100644 index d1ba4f0b..00000000 --- a/src/main/java/com/github/zly2006/reden/access/UndoRecordContainer.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.zly2006.reden.access - -interface UndoRecordContainer { - var recording: PlayerData.UndoRecord? - - fun swap(another: UndoRecordContainer) { - val tmp = recording - recording = another.recording - another.recording = tmp - } -} diff --git a/src/main/java/com/github/zly2006/reden/access/UndoRecordContainerImpl.kt b/src/main/java/com/github/zly2006/reden/access/UndoRecordContainerImpl.kt deleted file mode 100644 index 126f4f44..00000000 --- a/src/main/java/com/github/zly2006/reden/access/UndoRecordContainerImpl.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.github.zly2006.reden.access - -import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper -import org.jetbrains.annotations.TestOnly - -class UndoRecordContainerImpl : UndoRecordContainer { - override var recording: PlayerData.UndoRecord? = null - var id: Long - get() = recording?.id ?: 0 - set(value) { recording = UpdateMonitorHelper.undoRecordsMap[value] } - @TestOnly @JvmField internal var swapped = false -} diff --git a/src/main/java/com/github/zly2006/reden/access/WorldData.kt b/src/main/java/com/github/zly2006/reden/access/WorldData.kt index 1d5a02e5..050f0cdb 100644 --- a/src/main/java/com/github/zly2006/reden/access/WorldData.kt +++ b/src/main/java/com/github/zly2006/reden/access/WorldData.kt @@ -1,10 +1,14 @@ package com.github.zly2006.reden.access +import com.github.zly2006.reden.mixinhelper.BreakpointHelper import net.minecraft.server.world.ServerWorld import net.minecraft.world.World -class WorldData(serverWorld: ServerWorld) { +class WorldData( + val serverWorld: ServerWorld +) { var status: Long = 0 + val breakpointHelper = BreakpointHelper(serverWorld) interface WorldDataAccess { fun getRedenWorldData(): WorldData } diff --git a/src/main/java/com/github/zly2006/reden/carpet/RedenCarpetSettings.java b/src/main/java/com/github/zly2006/reden/carpet/RedenCarpetSettings.java index dc01f9c5..a98ed5f4 100644 --- a/src/main/java/com/github/zly2006/reden/carpet/RedenCarpetSettings.java +++ b/src/main/java/com/github/zly2006/reden/carpet/RedenCarpetSettings.java @@ -24,4 +24,16 @@ public class RedenCarpetSettings { strict = false ) public static int allowedUndoSizeInBytes = 52428800; + + @Rule( + categories = {CATEGORY_REDEN, RuleCategory.CREATIVE}, + options = {"0", "100"}, + strict = false + ) + public static int tickBackMaxTicks = 100; + + @Rule( + categories = {CATEGORY_REDEN, RuleCategory.CREATIVE} + ) + public static boolean undoScheduledTicks = false; } diff --git a/src/main/java/com/github/zly2006/reden/malilib/MalilibSettings.kt b/src/main/java/com/github/zly2006/reden/malilib/MalilibSettings.kt index 60e3e549..34839779 100644 --- a/src/main/java/com/github/zly2006/reden/malilib/MalilibSettings.kt +++ b/src/main/java/com/github/zly2006/reden/malilib/MalilibSettings.kt @@ -65,6 +65,7 @@ private fun ConfigBase.debug() = this.apply(DEBUG_TAB::add @JvmField val UNDO_REPORT_UN_TRACKED_TNT = RedenConfigBoolean("undoReportUnTrackedTnt", false).debug() @JvmField val OPEN_GITHUB_AUTH_SCREEN = RedenConfigHotkey("openGithubAuthScreen", "R,G").debug().hotkey() @JvmField val GITHUB_TOKEN = RedenConfigString("githubToken", "").debug() +@JvmField val ALLOW_SOCIAL_FOLLOW = RedenConfigBoolean("allowSocialFollow", true).debug() fun ConfigHotkey.runCommand(commands: ConfigStringList) { this.keybind.setCallback { _, _ -> diff --git a/src/main/java/com/github/zly2006/reden/mixin/tickBack/MixinTickCommand.java b/src/main/java/com/github/zly2006/reden/mixin/tickBack/MixinTickCommand.java new file mode 100644 index 00000000..d0cf35dc --- /dev/null +++ b/src/main/java/com/github/zly2006/reden/mixin/tickBack/MixinTickCommand.java @@ -0,0 +1,26 @@ +package com.github.zly2006.reden.mixin.tickBack; + +import carpet.commands.TickCommand; +import com.github.zly2006.reden.carpet.RedenCarpetSettings; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = TickCommand.class, remap = false) +public class MixinTickCommand { + @Redirect( + method = "register", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/brigadier/arguments/IntegerArgumentType;integer(II)Lcom/mojang/brigadier/arguments/IntegerArgumentType;" + ) + ) + private static IntegerArgumentType onIntegerArg(int min, int max) { + if (min == 1 && max == 72000) { + return IntegerArgumentType.integer(-RedenCarpetSettings.tickBackMaxTicks, max); + } else { + return IntegerArgumentType.integer(min, max); + } + } +} diff --git a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinCommands.java b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinCommands.java index aaf0e486..9bc91ee2 100644 --- a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinCommands.java +++ b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinCommands.java @@ -1,6 +1,5 @@ package com.github.zly2006.reden.mixin.undo; -import com.github.zly2006.reden.access.PlayerData; import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper; import com.github.zly2006.reden.utils.DebugKt; import com.mojang.brigadier.ParseResults; @@ -42,10 +41,7 @@ private void onExecute(ParseResults parseResults, String co private void afterExecute(ParseResults parseResults, String command, CallbackInfoReturnable cir) { if (parseResults.getContext().getSource().getEntity() instanceof ServerPlayerEntity player) { DebugKt.debugLogger.invoke("Stop monitoring of CHAIN - Command"); - PlayerData playerView = PlayerData.Companion.data(player); - if (playerView.isRecording()) { - playerView.stopRecording(player.getWorld()); - } + UpdateMonitorHelper.playerStartRecord(player); } } } diff --git a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinExplosion.java b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinExplosion.java index 4ea2f1ed..082f5306 100644 --- a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinExplosion.java +++ b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinExplosion.java @@ -1,7 +1,6 @@ package com.github.zly2006.reden.mixin.undo; import com.github.zly2006.reden.access.PlayerData; -import com.github.zly2006.reden.access.UndoRecordContainerImpl; import com.github.zly2006.reden.access.UndoableAccess; import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper; import com.github.zly2006.reden.utils.DebugKt; @@ -19,10 +18,7 @@ @SuppressWarnings("AddedMixinMembersNamePattern") @Mixin(Explosion.class) public class MixinExplosion implements UndoableAccess { - @Unique - UndoRecordContainerImpl recordContainer = new UndoRecordContainerImpl(); - @Unique - long undoId; + @Unique long undoId; @Inject( method = "(Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/damage/DamageSource;Lnet/minecraft/world/explosion/ExplosionBehavior;DDDFZLnet/minecraft/world/explosion/Explosion$DestructionType;)V", @@ -40,8 +36,7 @@ private void onInit(World world, Entity entity, DamageSource damageSource, Explo private void beforeAffectWorld(boolean particles, CallbackInfo ci) { DebugKt.debugLogger.invoke("Explosion affect world start, undoID=" + undoId); if (undoId != 0) { - recordContainer.setId(undoId); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); + UpdateMonitorHelper.pushRecord(undoId); } } @@ -49,8 +44,7 @@ private void beforeAffectWorld(boolean particles, CallbackInfo ci) { private void afterAffectWorld(boolean particles, CallbackInfo ci) { DebugKt.debugLogger.invoke("Explosion affect world end, undoID=" + undoId); if (undoId != 0) { - UpdateMonitorHelper.INSTANCE.swap(recordContainer); - recordContainer.setRecording(null); + UpdateMonitorHelper.popRecord(); } } @@ -58,8 +52,7 @@ private void afterAffectWorld(boolean particles, CallbackInfo ci) { private void beforeDamageEntities(CallbackInfo ci) { DebugKt.debugLogger.invoke("Explosion damage entities start, undoID=" + undoId); if (undoId != 0) { - recordContainer.setId(undoId); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); + UpdateMonitorHelper.pushRecord(undoId); } } @@ -67,8 +60,7 @@ private void beforeDamageEntities(CallbackInfo ci) { private void afterDamageEntities(CallbackInfo ci) { DebugKt.debugLogger.invoke("Explosion damage entities end, undoID=" + undoId); if (undoId != 0) { - UpdateMonitorHelper.INSTANCE.swap(recordContainer); - recordContainer.setRecording(null); + UpdateMonitorHelper.popRecord(); } } diff --git a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinMovingPiston.java b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinMovingPiston.java index 871bec00..68524006 100644 --- a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinMovingPiston.java +++ b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinMovingPiston.java @@ -1,6 +1,5 @@ package com.github.zly2006.reden.mixin.undo; -import com.github.zly2006.reden.access.UndoRecordContainerImpl; import com.github.zly2006.reden.access.UndoableAccess; import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper; import com.github.zly2006.reden.utils.DebugKt; @@ -13,12 +12,9 @@ import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Unique; @Mixin(PistonExtensionBlock.class) public class MixinMovingPiston { - @Unique UndoRecordContainerImpl recordContainer = new UndoRecordContainerImpl(); - /** * @author zly2006 * @reason track undo, block entity tick is not the same time as block event tick @@ -32,16 +28,14 @@ public BlockEntityTicker getTicker(World world, if (shouldTrack) { if (be instanceof UndoableAccess access) { DebugKt.debugLogger.invoke("Before piston block entity tick: " + pos.toShortString() + ", id" + access.getUndoId()); - recordContainer.setId(access.getUndoId()); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); + UpdateMonitorHelper.pushRecord(access.getUndoId()); } } PistonBlockEntity.tick(world1, pos, state1, be); if (shouldTrack) { if (be instanceof UndoableAccess access) { DebugKt.debugLogger.invoke("After piston block entity tick: " + pos.toShortString() + ", id" + access.getUndoId()); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); - recordContainer.setRecording(null); + UpdateMonitorHelper.popRecord(); } } } : null; diff --git a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinPlayerMode.java b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinPlayerMode.java index 8a3405e1..9b59ea9f 100644 --- a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinPlayerMode.java +++ b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinPlayerMode.java @@ -1,7 +1,6 @@ package com.github.zly2006.reden.mixin.undo; import com.github.zly2006.reden.access.ChainedUpdaterView; -import com.github.zly2006.reden.access.PlayerData; import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper; import com.github.zly2006.reden.utils.DebugKt; import net.minecraft.item.ItemStack; @@ -40,8 +39,7 @@ private void onDestroy(BlockPos pos, CallbackInfoReturnable cir) { @Inject(method = "tryBreakBlock", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/server/world/ServerWorld;removeBlock(Lnet/minecraft/util/math/BlockPos;Z)Z")) private void afterDestroy(BlockPos pos, CallbackInfoReturnable cir) { DebugKt.debugLogger.invoke("Stop monitoring of CHAIN - Break block"); - PlayerData playerView = PlayerData.Companion.data(player); - playerView.stopRecording(world); + UpdateMonitorHelper.playerStartRecord(player); } @Inject(method = "interactBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;onUse(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;")) @@ -53,8 +51,7 @@ private void onUseBlock(ServerPlayerEntity player, World world, ItemStack stack, @Inject(method = "interactBlock", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/block/BlockState;onUse(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;")) private void afterUseBlock(ServerPlayerEntity player, World world, ItemStack stack, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir) { DebugKt.debugLogger.invoke("Stop monitoring of CHAIN - Interact block"); - PlayerData playerView = PlayerData.Companion.data(player); - playerView.stopRecording(world); + UpdateMonitorHelper.playerStartRecord(player); } @Inject(method = "interactBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;useOnBlock(Lnet/minecraft/item/ItemUsageContext;)Lnet/minecraft/util/ActionResult;")) @@ -66,8 +63,7 @@ private void onUseItemOnBlock(ServerPlayerEntity player, World world, ItemStack @Inject(method = "interactBlock", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/item/ItemStack;useOnBlock(Lnet/minecraft/item/ItemUsageContext;)Lnet/minecraft/util/ActionResult;")) private void afterUseItemOnBlock(ServerPlayerEntity player, World world, ItemStack stack, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir) { DebugKt.debugLogger.invoke("Stop monitoring of CHAIN - Interact block with item"); - PlayerData playerView = PlayerData.Companion.data(player); - playerView.stopRecording(world); + UpdateMonitorHelper.playerStartRecord(player); } @Inject(method = "interactItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;use(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/TypedActionResult;")) @@ -79,7 +75,6 @@ private void onUseItem(ServerPlayerEntity player, World world, ItemStack stack, @Inject(method = "interactItem", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/item/ItemStack;use(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/TypedActionResult;")) private void afterUseItem(ServerPlayerEntity player, World world, ItemStack stack, Hand hand, CallbackInfoReturnable cir) { DebugKt.debugLogger.invoke("Stop monitoring of CHAIN - Interact item"); - PlayerData playerView = PlayerData.Companion.data(player); - playerView.stopRecording(world); + UpdateMonitorHelper.playerStartRecord(player); } } diff --git a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinSchedule.java b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinSchedule.java index a3e2f5fe..8099c1a7 100644 --- a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinSchedule.java +++ b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinSchedule.java @@ -1,7 +1,6 @@ package com.github.zly2006.reden.mixin.undo; import com.github.zly2006.reden.access.PlayerData; -import com.github.zly2006.reden.access.UndoRecordContainerImpl; import com.github.zly2006.reden.access.UndoableAccess; import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper; import com.github.zly2006.reden.utils.DebugKt; @@ -9,7 +8,6 @@ import net.minecraft.world.tick.OrderedTick; import net.minecraft.world.tick.WorldTickScheduler; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -19,9 +17,6 @@ @Mixin(WorldTickScheduler.class) public class MixinSchedule { - @Unique - UndoRecordContainerImpl recordContainer = new UndoRecordContainerImpl(); - @SuppressWarnings("rawtypes") @Inject( method = "tick(Ljava/util/function/BiConsumer;)V", @@ -34,8 +29,7 @@ public class MixinSchedule { private void onRunSchedule(BiConsumer ticker, CallbackInfo ci, OrderedTick orderedTick) { long undoId = ((UndoableAccess) orderedTick).getUndoId(); DebugKt.debugLogger.invoke("Running scheduled tick at " + orderedTick.pos() + ", record=" + undoId); - recordContainer.setId(undoId); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); + UpdateMonitorHelper.pushRecord(undoId); } @Inject( method = "tick(Ljava/util/function/BiConsumer;)V", @@ -47,8 +41,7 @@ private void onRunSchedule(BiConsumer ticker, CallbackInfo ci, ) private void afterRunSchedule(CallbackInfo ci) { DebugKt.debugLogger.invoke("scheduled tick finished, removing it from record"); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); - recordContainer.setRecording(null); + UpdateMonitorHelper.popRecord(); } @Inject( method = "scheduleTick", diff --git a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinServerWorld.java b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinServerWorld.java index 43ce6f65..988b8e9e 100644 --- a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinServerWorld.java +++ b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinServerWorld.java @@ -1,7 +1,6 @@ package com.github.zly2006.reden.mixin.undo; import com.github.zly2006.reden.access.PlayerData; -import com.github.zly2006.reden.access.UndoRecordContainerImpl; import com.github.zly2006.reden.access.UndoableAccess; import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper; import com.github.zly2006.reden.utils.DebugKt; @@ -12,7 +11,6 @@ import net.minecraft.server.world.ServerWorld; 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.Inject; import org.spongepowered.asm.mixin.injection.Redirect; @@ -20,7 +18,6 @@ @Mixin(ServerWorld.class) public abstract class MixinServerWorld { - @Unique UndoRecordContainerImpl recordContainer = new UndoRecordContainerImpl(); @Shadow public abstract void removePlayer(ServerPlayerEntity player, Entity.RemovalReason reason); @Redirect( @@ -51,8 +48,7 @@ private boolean onAddBlockEvent(ObjectLinkedOpenHashSet instance, Ob private void beforeProcessBlockEvent(BlockEvent event, CallbackInfoReturnable cir) { long undoId = ((UndoableAccess) event).getUndoId(); DebugKt.debugLogger.invoke("block event start at " + event.pos().toShortString() + event.block().toString() + ", data=" + event.data() + ", type=" + event.type() + ", record "+ undoId); - recordContainer.setId(undoId); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); + UpdateMonitorHelper.pushRecord(undoId); } @Inject( method = "processBlockEvent", @@ -64,7 +60,6 @@ private void beforeProcessBlockEvent(BlockEvent event, CallbackInfoReturnable cir) { DebugKt.debugLogger.invoke("block event end"); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); - recordContainer.setRecording(null); + UpdateMonitorHelper.popRecord(); } } diff --git a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinTntEntity.java b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinTntEntity.java index 5f9b35eb..da2c2b02 100644 --- a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinTntEntity.java +++ b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinTntEntity.java @@ -1,7 +1,6 @@ package com.github.zly2006.reden.mixin.undo; import com.github.zly2006.reden.access.PlayerData; -import com.github.zly2006.reden.access.UndoRecordContainerImpl; import com.github.zly2006.reden.access.UndoableAccess; import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper; import com.github.zly2006.reden.utils.DebugKt; @@ -18,10 +17,7 @@ @SuppressWarnings("AddedMixinMembersNamePattern") @Mixin(TntEntity.class) public abstract class MixinTntEntity extends Entity implements UndoableAccess { - @Unique - long undoId; - @Unique - UndoRecordContainerImpl recordContainer = new UndoRecordContainerImpl(); + @Unique long undoId; public MixinTntEntity(EntityType type, World world) { super(type, world); @@ -42,15 +38,13 @@ private void onInit(EntityType entityType, World world, CallbackInfo ci) { @Inject(method = "explode", at = @At("HEAD")) private void beforeExplode(CallbackInfo ci) { DebugKt.debugLogger.invoke("TNT explode start, undoId=" + undoId); - recordContainer.setId(undoId); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); + UpdateMonitorHelper.pushRecord(undoId); } @Inject(method = "explode", at = @At("TAIL")) private void afterExplode(CallbackInfo ci) { DebugKt.debugLogger.invoke("TNT explode end, undoId=" + undoId); - UpdateMonitorHelper.INSTANCE.swap(recordContainer); - recordContainer.setRecording(null); + UpdateMonitorHelper.popRecord(); } @Override diff --git a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinUpdater.java b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinUpdater.java index 4d32df26..19dc79a0 100644 --- a/src/main/java/com/github/zly2006/reden/mixin/undo/MixinUpdater.java +++ b/src/main/java/com/github/zly2006/reden/mixin/undo/MixinUpdater.java @@ -1,6 +1,6 @@ package com.github.zly2006.reden.mixin.undo; -import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper; +import com.github.zly2006.reden.access.WorldData; import net.minecraft.world.World; import net.minecraft.world.block.ChainRestrictedNeighborUpdater; import org.spongepowered.asm.mixin.Final; @@ -23,10 +23,16 @@ private void onInit(World world, int maxChainDepth, CallbackInfo ci) { } @Inject(method = "runQueuedUpdates", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/block/ChainRestrictedNeighborUpdater$Entry;update(Lnet/minecraft/world/World;)Z"), locals = LocalCapture.CAPTURE_FAILHARD) private void onRunQueuedUpdates(CallbackInfo ci, ChainRestrictedNeighborUpdater.Entry entry) { - UpdateMonitorHelper.onUpdate(world, entry); + WorldData data = WorldData.Companion.data(world); + if (data != null) { + data.getBreakpointHelper().onUpdate(entry); + } } @Inject(method = "runQueuedUpdates", at = @At("RETURN")) private void finishUpdates(CallbackInfo ci) { - UpdateMonitorHelper.onChainFinish(world); + WorldData data = WorldData.Companion.data(world); + if (data != null) { + data.getBreakpointHelper().onChainFinish(); + } } } diff --git a/src/main/java/com/github/zly2006/reden/mixinhelper/BreakpointHelper.kt b/src/main/java/com/github/zly2006/reden/mixinhelper/BreakpointHelper.kt index aef05d69..bfa0a031 100644 --- a/src/main/java/com/github/zly2006/reden/mixinhelper/BreakpointHelper.kt +++ b/src/main/java/com/github/zly2006/reden/mixinhelper/BreakpointHelper.kt @@ -5,13 +5,46 @@ import net.minecraft.block.BlockState import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.world.World +import net.minecraft.world.block.ChainRestrictedNeighborUpdater import net.minecraft.world.block.NeighborUpdater class BreakpointHelper( - world: World + val world: World ) { + private val listeners: MutableMap Unit, UpdateMonitorHelper.LifeTime> = mutableMapOf() + private val chainFinishListeners = mutableMapOf Unit, UpdateMonitorHelper.LifeTime>() var isInterrupted = false private set + + fun onChainFinish() { + //debugLogger("UpdateMonitorHelper.finish") + listeners.forEach { (k, v) -> + if (v == UpdateMonitorHelper.LifeTime.CHAIN) { + listeners.remove(k) + } + } + chainFinishListeners.forEach { (k, v) -> + k.invoke(world) + if (v == UpdateMonitorHelper.LifeTime.ONCE || v == UpdateMonitorHelper.LifeTime.CHAIN) { + chainFinishListeners.remove(k) + } + } + } + + fun startMonitor(onUpdate: World.(ChainRestrictedNeighborUpdater.Entry) -> Unit, lifeTime: UpdateMonitorHelper.LifeTime) { + listeners[onUpdate] = lifeTime + } + + fun onUpdate(entry: ChainRestrictedNeighborUpdater.Entry) { + //debugLogger("UpdateMonitorHelper.onUpdate") + listeners.forEach { (k, v) -> + k.invoke(world, entry) + if (v == UpdateMonitorHelper.LifeTime.ONCE) { + listeners.remove(k) + } + } + } + fun handle(entry: Entry): Boolean { return false } diff --git a/src/main/java/com/github/zly2006/reden/mixinhelper/TickBackHelper.kt b/src/main/java/com/github/zly2006/reden/mixinhelper/TickBackHelper.kt new file mode 100644 index 00000000..d83afdb5 --- /dev/null +++ b/src/main/java/com/github/zly2006/reden/mixinhelper/TickBackHelper.kt @@ -0,0 +1,15 @@ +package com.github.zly2006.reden.mixinhelper + +import net.minecraft.util.math.ChunkPos +import java.nio.file.Path + +object TickBackHelper { + class TickBackup( + val time: Long, + val modifiedChunks: MutableSet = mutableSetOf(), + val filePath: Path + ) + var isTickStepping = false + val backups = mutableMapOf() + +} \ No newline at end of file diff --git a/src/main/java/com/github/zly2006/reden/mixinhelper/UpdateMonitorHelper.kt b/src/main/java/com/github/zly2006/reden/mixinhelper/UpdateMonitorHelper.kt index bfd04f91..df999979 100644 --- a/src/main/java/com/github/zly2006/reden/mixinhelper/UpdateMonitorHelper.kt +++ b/src/main/java/com/github/zly2006/reden/mixinhelper/UpdateMonitorHelper.kt @@ -2,8 +2,6 @@ package com.github.zly2006.reden.mixinhelper import com.github.zly2006.reden.access.PlayerData import com.github.zly2006.reden.access.PlayerData.Companion.data -import com.github.zly2006.reden.access.UndoRecordContainer -import com.github.zly2006.reden.access.UndoRecordContainerImpl import com.github.zly2006.reden.carpet.RedenCarpetSettings import com.github.zly2006.reden.utils.debugLogger import com.github.zly2006.reden.utils.server @@ -14,14 +12,13 @@ import net.minecraft.entity.Entity import net.minecraft.server.network.ServerPlayerEntity import net.minecraft.server.world.ServerWorld import net.minecraft.util.math.BlockPos -import net.minecraft.world.World -import net.minecraft.world.block.ChainRestrictedNeighborUpdater -object UpdateMonitorHelper: UndoRecordContainer { - private val listeners: MutableMap Unit, LifeTime> = mutableMapOf() - private val chainFinishListeners = mutableMapOf Unit, LifeTime>() +object UpdateMonitorHelper { private var recordId = 20060210L val undoRecordsMap: MutableMap = HashMap() + val undoRecords = mutableListOf() + @JvmStatic fun pushRecord(id: Long) = undoRecords.add(undoRecordsMap[id]) + @JvmStatic fun popRecord() = undoRecords.removeLast() data class Changed( val record: PlayerData.UndoRecord, val pos: BlockPos @@ -29,22 +26,7 @@ object UpdateMonitorHelper: UndoRecordContainer { var lastTickChanged: MutableSet = hashSetOf(); private set var thisTickChanged: MutableSet = hashSetOf(); private set - /** - * 非常非常危险的变量,如果没有十足把握请不要直接操作 - * - * 这会带来不经检查的访问 - */ - override var recording: PlayerData.UndoRecord? = null - set(value) { - if (field != value) { - field = value - if (value == null) { - debugLogger("record canceled") - } else { - debugLogger("record start") - } - } - } + val recording: PlayerData.UndoRecord? get() = undoRecords.lastOrNull() enum class LifeTime { PERMANENT, TICK, @@ -52,49 +34,6 @@ object UpdateMonitorHelper: UndoRecordContainer { ONCE } - @JvmStatic - fun startMonitor(onUpdate: World.(ChainRestrictedNeighborUpdater.Entry) -> Unit, lifeTime: LifeTime) { - listeners[onUpdate] = lifeTime - } - - @JvmStatic - fun onUpdate(world: World, entry: ChainRestrictedNeighborUpdater.Entry) { - //debugLogger("UpdateMonitorHelper.onUpdate") - listeners.forEach { (k, v) -> - k.invoke(world, entry) - if (v == LifeTime.ONCE) { - listeners.remove(k) - } - } - } - - var depth = 0; private set - override fun swap(another: UndoRecordContainer) { - if (another is UndoRecordContainerImpl) { - if (another.swapped) depth-- - else depth++ - another.swapped = !another.swapped - } - debugLogger("swap, depth=$depth") - super.swap(another) - } - - @JvmStatic - fun onChainFinish(world: World) { - //debugLogger("UpdateMonitorHelper.finish") - listeners.forEach { (k, v) -> - if (v == LifeTime.CHAIN) { - listeners.remove(k) - } - } - chainFinishListeners.forEach { (k, v) -> - k.invoke(world) - if (v == LifeTime.ONCE || v == LifeTime.CHAIN) { - chainFinishListeners.remove(k) - } - } - } - @JvmStatic fun monitorSetBlock(world: ServerWorld, pos: BlockPos, blockState: BlockState) { debugLogger("id ${recording?.id ?: 0}: set$pos, ${world.getBlockState(pos)} -> $blockState") @@ -112,13 +51,17 @@ object UpdateMonitorHelper: UndoRecordContainer { * 此缓存可能在没有确认的情况下不经检查直接调用 */ private fun addRecord(): PlayerData.UndoRecord { - recording = PlayerData.UndoRecord( + if (undoRecords.size != 0) { + throw IllegalStateException("Cannot add record when there is already one.") + } + val undoRecord = PlayerData.UndoRecord( id = recordId, lastChangedTick = server.ticks, ) - undoRecordsMap[recordId] = recording!! + undoRecords.add(undoRecord) + undoRecordsMap[recordId] = undoRecord recordId++ - return recording!! + return undoRecord } internal fun removeRecord(id: Long) = undoRecordsMap.remove(id) @@ -136,7 +79,8 @@ object UpdateMonitorHelper: UndoRecordContainer { val playerView = player.data() if (playerView.isRecording) { playerView.isRecording = false - recording = null + undoRecords.removeLast() + debugLogger("Stop recording, undo depth=" + undoRecords.size) playerView.redo .onEach { removeRecord(it.id) } .clear() diff --git a/src/main/java/com/github/zly2006/reden/network/Rollback.kt b/src/main/java/com/github/zly2006/reden/network/Rollback.kt index e419d6d1..61b44009 100644 --- a/src/main/java/com/github/zly2006/reden/network/Rollback.kt +++ b/src/main/java/com/github/zly2006/reden/network/Rollback.kt @@ -85,7 +85,7 @@ class Rollback( if (UpdateMonitorHelper.recording != null) { Reden.LOGGER.warn("Undo when a record is still active, id=" + UpdateMonitorHelper.recording?.id) // 不取消跟踪会导致undo的更改也被记录,边读边写异常 - UpdateMonitorHelper.recording = null + UpdateMonitorHelper.undoRecords.clear() } when (packet.status) { 0 -> view.undo.lastValid()?.let { undoRecord -> diff --git a/src/main/java/com/github/zly2006/reden/report/Report.kt b/src/main/java/com/github/zly2006/reden/report/Report.kt index 48486960..258d2fe7 100644 --- a/src/main/java/com/github/zly2006/reden/report/Report.kt +++ b/src/main/java/com/github/zly2006/reden/report/Report.kt @@ -1,5 +1,6 @@ package com.github.zly2006.reden.report +import com.github.zly2006.reden.malilib.ALLOW_SOCIAL_FOLLOW import com.google.gson.Gson import net.fabricmc.loader.api.FabricLoader import net.minecraft.MinecraftVersion @@ -70,6 +71,7 @@ fun initReport() { private var usedTimes = 0 private fun requestFollow() { + if (!ALLOW_SOCIAL_FOLLOW.booleanValue) return val mc = MinecraftClient.getInstance() val text = Text.literal( if (mc.languageManager.language == "zh_cn") diff --git a/src/main/resources/assets/reden/lang/en_us.yml b/src/main/resources/assets/reden/lang/en_us.yml index 5dcabe31..a0927ccb 100644 --- a/src/main/resources/assets/reden/lang/en_us.yml +++ b/src/main/resources/assets/reden/lang/en_us.yml @@ -133,4 +133,11 @@ carpet: allowedUndoSizeInBytes: desc: |- Memory size a player can use for undo. Default is 5MB, 0 to disable, -1 for infinite. - + + tickBackMaxTicks: + desc: |- + Maximum ticks for tick back. Default is 100, 0 to disable. + + undoScheduledTicks: + desc: |- + Allow undo record scheduled ticks. Default is false. diff --git a/src/main/resources/reden.mixins.json b/src/main/resources/reden.mixins.json index 347b886c..69850202 100644 --- a/src/main/resources/reden.mixins.json +++ b/src/main/resources/reden.mixins.json @@ -13,6 +13,7 @@ "pearl.MixinExplosion", "tick.MixinTick", "tick.MixinWatchdog", + "tickBack.MixinTickCommand", "undo.MixinBlockEvent", "undo.MixinCommands", "undo.MixinEntity", @@ -29,10 +30,10 @@ "undo.MixinUpdater" ], "client": [ - "debug.undoReportUnTrackedTnt.MixinTntEntity", "chat.ChatHudMixin", "chat.ChatScreenMixin", "chat.VisibleChatHudLineMixin", + "debug.undoReportUnTrackedTnt.MixinTntEntity", "fix.NoTimeOut", "fix.chatCrash.MixinChatHud", "fix.forceSyncEntityPos.MixinClientNetwork",