mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-19 14:59:32 +00:00
Fix replay api and add null check in botlist (#627)
* Fix replay api and add null check in botlist * Update botlist fix * Fix bugs * All done! * Clean up
This commit is contained in:
@@ -36,6 +36,7 @@ import org.leavesmc.leaves.event.bot.BotRemoveEvent;
|
||||
import org.leavesmc.leaves.event.bot.BotSpawnLocationEvent;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -204,7 +205,7 @@ public class BotList {
|
||||
playerIO.save(bot);
|
||||
} else {
|
||||
bot.dropAll(true);
|
||||
botsNameByWorldUuid.get(bot.level().uuid.toString()).remove(bot.getBukkitEntity().getRealName());
|
||||
botsNameByWorldUuid.getOrDefault(bot.level().uuid.toString(), new HashSet<>()).remove(bot.getBukkitEntity().getRealName());
|
||||
}
|
||||
|
||||
if (bot.isPassenger() && event.shouldSave()) {
|
||||
@@ -305,6 +306,17 @@ public class BotList {
|
||||
bots.forEach(this::loadNewBot);
|
||||
}
|
||||
|
||||
public void updateBotLevel(ServerBot bot, ServerLevel level) {
|
||||
String prevUuid = bot.level().uuid.toString();
|
||||
String newUuid = level.uuid.toString();
|
||||
this.botsNameByWorldUuid
|
||||
.computeIfAbsent(newUuid, (k) -> new HashSet<>())
|
||||
.add(bot.getBukkitEntity().getRealName());
|
||||
this.botsNameByWorldUuid
|
||||
.computeIfAbsent(prevUuid, (k) -> new HashSet<>())
|
||||
.remove(bot.getBukkitEntity().getRealName());
|
||||
}
|
||||
|
||||
public void networkTick() {
|
||||
this.bots.forEach(ServerBot::networkTick);
|
||||
}
|
||||
|
||||
@@ -275,6 +275,12 @@ public class ServerBot extends ServerPlayer {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServerLevel(ServerLevel level) {
|
||||
BotList.INSTANCE.updateBotLevel(this, level);
|
||||
super.setServerLevel(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void knockback(double strength, double x, double z, @Nullable Entity attacker, EntityKnockbackEvent.@NotNull Cause eventCause) {
|
||||
if (!this.hurtMarked) {
|
||||
|
||||
@@ -26,14 +26,17 @@ import net.minecraft.network.protocol.configuration.ClientboundUpdateEnabledFeat
|
||||
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetTimePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSystemChatPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundTrackedWaypointPacket;
|
||||
import net.minecraft.network.protocol.login.ClientboundLoginFinishedPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.RegistryLayer;
|
||||
import net.minecraft.server.packs.repository.KnownPack;
|
||||
import net.minecraft.tags.TagNetworkSerialization;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.PositionMoveRotation;
|
||||
import net.minecraft.world.flag.FeatureFlags;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -41,23 +44,27 @@ import org.leavesmc.leaves.LeavesLogger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class Recorder extends Connection {
|
||||
|
||||
public static final Executor saveService = Executors.newVirtualThreadPerTaskExecutor();
|
||||
public static final LeavesLogger LOGGER = LeavesLogger.LOGGER;
|
||||
public final ExecutorService saveService = Executors.newSingleThreadExecutor();
|
||||
|
||||
private final ReplayFile replayFile;
|
||||
private final ServerPhotographer photographer;
|
||||
private final RecorderOption recorderOption;
|
||||
private final RecordMetaData metaData;
|
||||
private final AtomicBoolean isSaving = new AtomicBoolean(false);
|
||||
|
||||
private boolean stopped = false;
|
||||
private boolean paused = false;
|
||||
@@ -68,7 +75,6 @@ public class Recorder extends Connection {
|
||||
private long timeShift = 0;
|
||||
|
||||
private boolean isSaved;
|
||||
private boolean isSaving;
|
||||
private ConnectionProtocol state = ConnectionProtocol.LOGIN;
|
||||
|
||||
public Recorder(ServerPhotographer photographer, RecorderOption recorderOption, File replayFile) throws IOException {
|
||||
@@ -77,7 +83,7 @@ public class Recorder extends Connection {
|
||||
this.photographer = photographer;
|
||||
this.recorderOption = recorderOption;
|
||||
this.metaData = new RecordMetaData();
|
||||
this.replayFile = new ReplayFile(replayFile);
|
||||
this.replayFile = new ReplayFile(replayFile, saveService);
|
||||
this.channel = new LocalChannel();
|
||||
}
|
||||
|
||||
@@ -93,6 +99,8 @@ public class Recorder extends Connection {
|
||||
this.savePacket(new ClientboundLoginFinishedPacket(photographer.getGameProfile()), ConnectionProtocol.LOGIN);
|
||||
this.startConfiguration();
|
||||
|
||||
savePacket(ClientboundPlayerPositionPacket.of(photographer.getId(), PositionMoveRotation.of(photographer), Collections.emptySet()));
|
||||
|
||||
if (recorderOption.forceWeather != null) {
|
||||
setWeather(recorderOption.forceWeather);
|
||||
}
|
||||
@@ -170,22 +178,29 @@ public class Recorder extends Connection {
|
||||
|
||||
@Override
|
||||
public void send(@NotNull Packet<?> packet, @Nullable ChannelFutureListener callbacks, boolean flush) {
|
||||
if (!stopped) {
|
||||
if (packet instanceof BundlePacket<?> packet1) {
|
||||
if (stopped) {
|
||||
return;
|
||||
}
|
||||
switch (packet) {
|
||||
case BundlePacket<?> packet1 -> {
|
||||
packet1.subPackets().forEach(subPacket -> send(subPacket, null));
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet instanceof ClientboundAddEntityPacket packet1) {
|
||||
case ClientboundAddEntityPacket packet1 -> {
|
||||
if (packet1.getType() == EntityType.PLAYER) {
|
||||
metaData.players.add(packet1.getUUID());
|
||||
saveMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
if (packet instanceof ClientboundDisconnectPacket) {
|
||||
case ClientboundDisconnectPacket ignored -> {
|
||||
return;
|
||||
}
|
||||
case ClientboundTrackedWaypointPacket ignored -> {
|
||||
return;
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
|
||||
if (recorderOption.forceDayTime != -1 && packet instanceof ClientboundSetTimePacket packet1) {
|
||||
packet = new ClientboundSetTimePacket(packet1.dayTime(), recorderOption.forceDayTime, false);
|
||||
@@ -204,7 +219,6 @@ public class Recorder extends Connection {
|
||||
|
||||
savePacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveMetadata() {
|
||||
saveService.execute(() -> {
|
||||
@@ -235,36 +249,23 @@ public class Recorder extends Connection {
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> saveRecording(File dest, boolean save) {
|
||||
if (!isSaving.compareAndSet(false, true)) {
|
||||
LOGGER.warning("saveRecording() called twice");
|
||||
return CompletableFuture.failedFuture(new IllegalStateException("saveRecording() called twice"));
|
||||
}
|
||||
isSaved = true;
|
||||
if (!isSaving) {
|
||||
isSaving = true;
|
||||
metaData.duration = (int) lastPacket;
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
saveMetadata();
|
||||
boolean interrupted = false;
|
||||
try {
|
||||
replayFile.saveMetaData(metaData);
|
||||
if (save) {
|
||||
replayFile.closeAndSave(dest);
|
||||
} else {
|
||||
replayFile.closeNotSave();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new CompletionException(e);
|
||||
} finally {
|
||||
if (interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}, runnable -> {
|
||||
final Thread thread = new Thread(runnable, "Recording file save thread");
|
||||
thread.start();
|
||||
});
|
||||
} else {
|
||||
LOGGER.warning("saveRecording() called twice");
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
throw new IllegalStateException("saveRecording() called twice");
|
||||
});
|
||||
}
|
||||
}, saveService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,12 +34,12 @@ import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.leavesmc.leaves.replay.Recorder.LOGGER;
|
||||
import static org.leavesmc.leaves.replay.Recorder.saveService;
|
||||
|
||||
public class ReplayFile {
|
||||
|
||||
@@ -59,8 +59,10 @@ public class ReplayFile {
|
||||
private final File metaFile;
|
||||
|
||||
private final Map<ConnectionProtocol, ProtocolInfo<?>> protocols;
|
||||
private final ExecutorService saveService;
|
||||
|
||||
public ReplayFile(@NotNull File name) throws IOException {
|
||||
public ReplayFile(@NotNull File name, ExecutorService saveService) throws IOException {
|
||||
this.saveService = saveService;
|
||||
this.tmpDir = new File(name.getParentFile(), name.getName() + ".tmp");
|
||||
if (tmpDir.exists()) {
|
||||
if (!ReplayFile.deleteDir(tmpDir)) {
|
||||
|
||||
@@ -55,6 +55,8 @@ public class ServerPhotographer extends ServerPlayer {
|
||||
GameProfile profile = new GameProfile(UUID.randomUUID(), state.id);
|
||||
|
||||
ServerPhotographer photographer = new ServerPhotographer(server, world, profile);
|
||||
photographer.absSnapTo(state.loc.x(), state.loc.y(), state.loc.z(), state.loc.getYaw(), state.loc.getPitch());
|
||||
|
||||
photographer.recorder = new Recorder(photographer, state.option, new File("replay", state.id));
|
||||
photographer.saveFile = new File("replay", state.id + ".mcpr");
|
||||
photographer.createState = state;
|
||||
@@ -146,6 +148,10 @@ public class ServerPhotographer extends ServerPlayer {
|
||||
this.followPlayer = followPlayer;
|
||||
}
|
||||
|
||||
public ServerPlayer getFollowPlayer() {
|
||||
return followPlayer;
|
||||
}
|
||||
|
||||
public void setSaveFile(File saveFile) {
|
||||
this.saveFile = saveFile;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user