Skip to content

Commit

Permalink
feat: tnt explosion undo
Browse files Browse the repository at this point in the history
  • Loading branch information
zly2006 committed Aug 13, 2023
1 parent a4b52c0 commit 0d5b078
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 40 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies {
testImplementation "net.fabricmc:fabric-loader-junit:${project.loader_version}"
include(implementation("org.bouncycastle:bcprov-jdk18on:1.76"))
include(implementation("org.bouncycastle:bcpg-jdk18on:1.76"))
modImplementation "curse.maven:litematica-308892:4626718"
}

test {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/github/zly2006/reden/Reden.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.zly2006.reden;

import carpet.CarpetExtension;
import com.github.zly2006.reden.malilib.KeyCallbacksKt;
import com.github.zly2006.reden.malilib.MalilibSettingsKt;
import com.github.zly2006.reden.network.ChannelsKt;
Expand Down Expand Up @@ -28,7 +29,7 @@
import java.io.IOException;
import java.nio.file.Files;

public class Reden implements ModInitializer {
public class Reden implements ModInitializer, CarpetExtension {
public static final String MOD_ID = "reden";
public static final String MOD_NAME = "Reden";
public static final String CONFIG_FILE = "reden.json";
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/com/github/zly2006/reden/access/PlayerData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class PlayerData(
) {
val undo: MutableList<UndoRecord> = mutableListOf()
val redo: MutableList<UndoRecord> = mutableListOf()
var undoUsedBytes: Int = 0
var isRecording: Boolean = false
var pearlListening: Boolean = false

Expand Down Expand Up @@ -46,5 +47,9 @@ class PlayerData(
class UndoRecord(
val id: Long,
val data: MutableMap<Long, Entry>
)
) {
fun getMemorySize() = data.asSequence()
.map { it.value.blockState.sizeInBytes + (it.value.blockEntity?.sizeInBytes ?: 0) }
.sum()
}
}
30 changes: 19 additions & 11 deletions src/main/java/com/github/zly2006/reden/carpet/CarpetSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@ import carpet.api.settings.Rule

const val CATEGORY_REDEN = "Reden"

/**
* In 1.18-, the stack overflow error will be thrown when there are too many updates in one tick.
* However, we have to replace the recursive method with a loop to use breakpoint features.
* This is the of updates in one tick,
* when this number is reached and the game is 1.18-, we throw a stack overflow error.
*/
@Rule(
categories = [CATEGORY_REDEN],
options = ["-1", "500000"],
)
val stackOverflowUpdates = 500000
object CarpetSettings {
/**
* In 1.18-, the stack overflow error will be thrown when there are too many updates in one tick.
* However, we have to replace the recursive method with a loop to use breakpoint features.
* This is the of updates in one tick,
* when this number is reached and the game is 1.18-, we throw a stack overflow error.
*/
@Rule(
categories = [CATEGORY_REDEN],
options = ["-1", "500000"],
)
val stackOverflowUpdates = 500000

@Rule(
categories = [CATEGORY_REDEN],
options = ["52428800"], // 50 MB
)
val allowedUndoSizeInBytes = 52428800
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@

@Mixin(CommandManager.class)
public class MixinCommands {
@Inject(method = "execute", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/command/ServerCommandSource;getServer()Lnet/minecraft/server/MinecraftServer;"))
@Inject(
method = "execute",
at = @At(
value = "INVOKE",
target = "Lcom/mojang/brigadier/CommandDispatcher;execute(Lcom/mojang/brigadier/ParseResults;)I",
shift = At.Shift.BEFORE,
remap = false
)
)
private void onExecute(ParseResults<ServerCommandSource> parseResults, String command, CallbackInfoReturnable<Integer> cir) {
if (parseResults.getContext().getSource().getEntity() instanceof ServerPlayerEntity player) {
if (MalilibSettingsKt.debug()) {
Expand All @@ -25,7 +33,15 @@ private void onExecute(ParseResults<ServerCommandSource> parseResults, String co
}
}

@Inject(method = "execute", at = @At("RETURN"))
@Inject(
method = "execute",
at = @At(
value = "INVOKE",
target = "Lcom/mojang/brigadier/CommandDispatcher;execute(Lcom/mojang/brigadier/ParseResults;)I",
shift = At.Shift.AFTER,
remap = false
)
)
private void afterExecute(ParseResults<ServerCommandSource> parseResults, String command, CallbackInfoReturnable<Integer> cir) {
if (parseResults.getContext().getSource().getEntity() instanceof ServerPlayerEntity player) {
if (MalilibSettingsKt.debug()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.github.zly2006.reden.mixin.undo;

import com.github.zly2006.reden.access.ScheduledTickAccess;
import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper;
import net.minecraft.world.explosion.Explosion;
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;

@SuppressWarnings("AddedMixinMembersNamePattern")
@Mixin(Explosion.class)
public class MixinExplosion implements ScheduledTickAccess {
@Unique
long undoId;

@Inject(method = "affectWorld", at = @At("HEAD"))
private void beforeAffectWorld(boolean particles, CallbackInfo ci) {
if (undoId != 0) {
UpdateMonitorHelper.INSTANCE.setRecording(UpdateMonitorHelper.INSTANCE.getUndoRecordsMap().get(undoId));
}
}

@Inject(method = "affectWorld", at = @At("TAIL"))
private void afterAffectWorld(boolean particles, CallbackInfo ci) {
if (undoId != 0) {
UpdateMonitorHelper.INSTANCE.setRecording(null);
}
}

@Override
public void setUndoId(long undoId) {
this.undoId = undoId;
}

@Override
public long getUndoId() {
return undoId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ public class MixinSchedule {
)
private <T> void onRunSchedule(BiConsumer<BlockPos, T> ticker, CallbackInfo ci, OrderedTick orderedTick) {
long undoId = ((ScheduledTickAccess) orderedTick).getUndoId();
if (MalilibSettingsKt.DEBUG_LOGGER.getBooleanValue()) {
PlayerData.UndoRecord record = UpdateMonitorHelper.INSTANCE.getUndoRecordsMap().get(undoId);
if (MalilibSettingsKt.DEBUG_LOGGER.getBooleanValue() && record != null) {
MinecraftClient.getInstance().player.sendMessage(Text.of("Scheduled tick at " + orderedTick.pos() + ", adding it into record " + undoId));
}
UpdateMonitorHelper.INSTANCE.setRecording(UpdateMonitorHelper.INSTANCE.getUndoRecordsMap().get(undoId));
UpdateMonitorHelper.INSTANCE.setRecording(record);
}
@Inject(
method = "tick(Ljava/util/function/BiConsumer;)V",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.github.zly2006.reden.mixin.undo;

import com.github.zly2006.reden.access.PlayerData;
import com.github.zly2006.reden.access.ScheduledTickAccess;
import com.github.zly2006.reden.malilib.MalilibSettingsKt;
import com.github.zly2006.reden.mixinhelper.UpdateMonitorHelper;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.TntEntity;
import net.minecraft.text.Text;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import net.minecraft.world.explosion.Explosion;
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;

@SuppressWarnings("AddedMixinMembersNamePattern")
@Mixin(TntEntity.class)
public abstract class MixinTntEntity extends Entity implements ScheduledTickAccess {
@Unique
long undoId;

public MixinTntEntity(EntityType<?> type, World world) {
super(type, world);
}

@Inject(
method = "<init>(Lnet/minecraft/entity/EntityType;Lnet/minecraft/world/World;)V",
at = @At("RETURN")
)
private void onInit(EntityType<?> entityType, World world, CallbackInfo ci) {
PlayerData.UndoRecord recording = UpdateMonitorHelper.INSTANCE.getRecording();
if (recording != null) {
if (MalilibSettingsKt.DEBUG_LOGGER.getBooleanValue()) {
MinecraftClient.getInstance().player.sendMessage(Text.literal("TNT spawned, adding it into record "+ recording.getId()));
}
undoId = recording.getId();
}
}

@Inject(method = "explode", at = @At("HEAD"), cancellable = true)
private void onExplode(CallbackInfo ci) {
Explosion explosion = new Explosion(
this.getWorld(),
this,
null,
null,
this.getX(),
this.getBodyY(0.0625),
this.getZ(),
4.0f,
false,
this.getWorld().getDestructionType(GameRules.TNT_EXPLOSION_DROP_DECAY)
);
if (undoId != 0) {
if (MalilibSettingsKt.DEBUG_LOGGER.getBooleanValue()) {
MinecraftClient.getInstance().player.sendMessage(Text.literal("TNT exploded, adding it into record "+ undoId));
}
((ScheduledTickAccess) explosion).setUndoId(undoId);
}
explosion.collectBlocksAndDamageEntities();
explosion.affectWorld(true);
ci.cancel();
}

@Override
public long getUndoId() {
return undoId;
}

@Override
public void setUndoId(long undoId) {
this.undoId = undoId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ 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.carpet.CarpetSettings
import com.github.zly2006.reden.malilib.DEBUG_LOGGER
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents
import net.minecraft.block.BlockState
import net.minecraft.client.MinecraftClient
import net.minecraft.server.network.ServerPlayerEntity
Expand Down Expand Up @@ -69,7 +71,7 @@ object UpdateMonitorHelper {

@JvmStatic
fun monitorSetBlock(world: ServerWorld, pos: BlockPos, blockState: BlockState) {
if (isPlayerRecording()) {
if (recording != null) {
if (DEBUG_LOGGER.booleanValue) {
MinecraftClient.getInstance().player?.sendMessage(Text.literal("set$pos, ${world.getBlockState(pos)} -> $blockState"))
}
Expand Down Expand Up @@ -111,18 +113,28 @@ object UpdateMonitorHelper {
if (playerView.isRecording) {
playerView.isRecording = false
recording = null
playerView.redo.onEach { removeRecord(it.id) }.clear()
if (playerView.undo.lastOrNull() != null) {
if (playerView.undo.last().data.isEmpty()) {
removeRecord(playerView.undo.last().id)
playerView.undo.removeLast()
playerView.redo
.onEach { removeRecord(it.id) }
.clear()
var sum = playerView.undo.map(PlayerData.UndoRecord::getMemorySize).sum()
if (DEBUG_LOGGER.booleanValue) {
MinecraftClient.getInstance().player?.sendMessage(Text.literal("Undo size: $sum"))
}
while (sum > CarpetSettings.allowedUndoSizeInBytes) {
removeRecord(playerView.undo.first().id)
playerView.undo.removeFirst()
if (DEBUG_LOGGER.booleanValue) {
MinecraftClient.getInstance().player?.sendMessage(Text.literal("Undo size: $sum, removing."))
}
sum = playerView.undo.map(PlayerData.UndoRecord::getMemorySize).sum()
}
}
}

@JvmStatic
fun isPlayerRecording(): Boolean {
return recording != null
private fun playerQuit(player: ServerPlayerEntity) =
player.data().undo.forEach { removeRecord(it.id) }

init {
ServerPlayConnectionEvents.DISCONNECT.register { handler, _ -> playerQuit(handler.player) }
}
}
31 changes: 22 additions & 9 deletions src/main/java/com/github/zly2006/reden/network/Rollback.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,26 @@ class Rollback(
}
return ret
}
fun MutableList<PlayerData.UndoRecord>.lastValid(): PlayerData.UndoRecord? {
while (this.isNotEmpty()) {
val last = this.last()
if (last.data.isNotEmpty()) {
return last
}
UpdateMonitorHelper.removeRecord(last.id)
this.removeLast()
}
return null
}
res.sendPacket(Rollback(when (packet.status) {
0 -> view.undo.removeLastOrNull()?.let {
0 -> view.undo.lastValid()?.let {
view.undo.removeLast()
view.redo.add(operate(it))
0
} ?: 2

1 -> view.redo.removeLastOrNull()?.let {
1 -> view.redo.lastValid()?.let {
view.redo.removeLast()
view.undo.add(operate(it))
1
} ?: 2
Expand All @@ -76,13 +89,13 @@ class Rollback(
ClientPlayNetworking.registerGlobalReceiver(pType) { packet, player, res ->
player.sendMessage(
when (packet.status) {
0 -> Text.literal("Rollback success")
1 -> Text.literal("Restore success")
2 -> Text.literal("No blocks info")
16 -> Text.literal("No permission")
32 -> Text.literal("Not recording")
65536 -> Text.literal("Unknown error")
else -> Text.literal("Unknown status")
0 -> Text.literal("[Reden/Undo] Rollback success")
1 -> Text.literal("[Reden/Undo] Restore success")
2 -> Text.literal("[Reden/Undo] No blocks info")
16 -> Text.literal("[Reden/Undo] No permission")
32 -> Text.literal("[Reden/Undo] Not recording")
65536 -> Text.literal("[Reden/Undo] Unknown error")
else -> Text.literal("[Reden/Undo] Unknown status")
}
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/github/zly2006/reden/report/Report.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import java.io.ByteArrayInputStream


fun checkSignature(): Boolean {
return true
if (ResourceLoader.loadString("cert") == "SOS Dan Saiko") {
println("SOS団最高")
return true
}
val key = """-----BEGIN PGP PUBLIC KEY BLOCK-----
Expand Down
Loading

0 comments on commit 0d5b078

Please sign in to comment.