mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-30 16:19:03 +01:00
Add debug for sync chunk loads
This patch adds a tool to find calls to getChunkAt which would load chunks, however it must be enabled by setting the startup flag -Dpaper.debug-sync-loads=true - To get a debug log for sync loads, the command is /paper syncloadinfo - To clear clear the currently stored sync load info, use /paper syncloadinfo clear
This commit is contained in:
parent
2ce266b657
commit
f179cfaff2
5 changed files with 330 additions and 55 deletions
|
@ -14,12 +14,10 @@
|
||||||
|
|
||||||
public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) {
|
public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) {
|
||||||
this.level = world;
|
this.level = world;
|
||||||
@@ -93,8 +100,66 @@
|
@@ -95,6 +102,64 @@
|
||||||
this.distanceManager = this.chunkMap.getDistanceManager();
|
|
||||||
this.distanceManager.updateSimulationDistance(simulationDistance);
|
|
||||||
this.clearCache();
|
this.clearCache();
|
||||||
+ }
|
}
|
||||||
+
|
|
||||||
+ // CraftBukkit start - properly implement isChunkLoaded
|
+ // CraftBukkit start - properly implement isChunkLoaded
|
||||||
+ public boolean isChunkLoaded(int chunkX, int chunkZ) {
|
+ public boolean isChunkLoaded(int chunkX, int chunkZ) {
|
||||||
+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(ChunkPos.asLong(chunkX, chunkZ));
|
+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(ChunkPos.asLong(chunkX, chunkZ));
|
||||||
|
@ -50,8 +48,8 @@
|
||||||
+
|
+
|
||||||
+ public <T> void addTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
|
+ public <T> void addTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
|
||||||
+ this.distanceManager.addTicket(ticketType, chunkPos, ticketLevel, identifier);
|
+ this.distanceManager.addTicket(ticketType, chunkPos, ticketLevel, identifier);
|
||||||
}
|
+ }
|
||||||
|
+
|
||||||
+ public <T> void removeTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
|
+ public <T> void removeTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
|
||||||
+ this.distanceManager.removeTicket(ticketType, chunkPos, ticketLevel, identifier);
|
+ this.distanceManager.removeTicket(ticketType, chunkPos, ticketLevel, identifier);
|
||||||
+ }
|
+ }
|
||||||
|
@ -90,16 +88,18 @@
|
||||||
return ichunkaccess;
|
return ichunkaccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,7 +216,7 @@
|
@@ -150,8 +215,9 @@
|
||||||
|
|
||||||
Objects.requireNonNull(completablefuture);
|
Objects.requireNonNull(completablefuture);
|
||||||
chunkproviderserver_b.managedBlock(completablefuture::isDone);
|
chunkproviderserver_b.managedBlock(completablefuture::isDone);
|
||||||
|
+ // com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads
|
||||||
ChunkResult<ChunkAccess> chunkresult = (ChunkResult) completablefuture.join();
|
ChunkResult<ChunkAccess> chunkresult = (ChunkResult) completablefuture.join();
|
||||||
- ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse((Object) null);
|
- ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse((Object) null);
|
||||||
+ ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error
|
+ ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error
|
||||||
|
|
||||||
if (ichunkaccess1 == null && create) {
|
if (ichunkaccess1 == null && create) {
|
||||||
throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Chunk not there when requested: " + chunkresult.getError()));
|
throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Chunk not there when requested: " + chunkresult.getError()));
|
||||||
@@ -231,7 +296,15 @@
|
@@ -231,7 +297,15 @@
|
||||||
int l = ChunkLevel.byStatus(leastStatus);
|
int l = ChunkLevel.byStatus(leastStatus);
|
||||||
ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k);
|
ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k);
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
|
this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
|
||||||
if (this.chunkAbsent(playerchunk, l)) {
|
if (this.chunkAbsent(playerchunk, l)) {
|
||||||
ProfilerFiller gameprofilerfiller = Profiler.get();
|
ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||||
@@ -250,7 +323,7 @@
|
@@ -250,7 +324,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) {
|
private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) {
|
||||||
|
@ -125,7 +125,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -279,7 +352,7 @@
|
@@ -279,7 +353,7 @@
|
||||||
return this.mainThreadProcessor.pollTask();
|
return this.mainThreadProcessor.pollTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@
|
||||||
boolean flag = this.distanceManager.runAllUpdates(this.chunkMap);
|
boolean flag = this.distanceManager.runAllUpdates(this.chunkMap);
|
||||||
boolean flag1 = this.chunkMap.promoteChunkMap();
|
boolean flag1 = this.chunkMap.promoteChunkMap();
|
||||||
|
|
||||||
@@ -309,18 +382,40 @@
|
@@ -309,18 +383,40 @@
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
|
@ -177,7 +177,7 @@
|
||||||
this.distanceManager.purgeStaleTickets();
|
this.distanceManager.purgeStaleTickets();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,14 +496,22 @@
|
@@ -401,14 +497,22 @@
|
||||||
|
|
||||||
this.lastSpawnState = spawnercreature_d;
|
this.lastSpawnState = spawnercreature_d;
|
||||||
profiler.popPush("spawnAndTick");
|
profiler.popPush("spawnAndTick");
|
||||||
|
@ -203,7 +203,7 @@
|
||||||
} else {
|
} else {
|
||||||
list1 = List.of();
|
list1 = List.of();
|
||||||
}
|
}
|
||||||
@@ -420,7 +523,7 @@
|
@@ -420,7 +524,7 @@
|
||||||
ChunkPos chunkcoordintpair = chunk.getPos();
|
ChunkPos chunkcoordintpair = chunk.getPos();
|
||||||
|
|
||||||
chunk.incrementInhabitedTime(timeDelta);
|
chunk.incrementInhabitedTime(timeDelta);
|
||||||
|
@ -212,7 +212,7 @@
|
||||||
NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, list1);
|
NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, list1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,10 +644,16 @@
|
@@ -541,10 +645,16 @@
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSpawnSettings(boolean spawnMonsters) {
|
public void setSpawnSettings(boolean spawnMonsters) {
|
||||||
|
@ -231,7 +231,7 @@
|
||||||
public String getChunkDebugData(ChunkPos pos) {
|
public String getChunkDebugData(ChunkPos pos) {
|
||||||
return this.chunkMap.getChunkDebugData(pos);
|
return this.chunkMap.getChunkDebugData(pos);
|
||||||
}
|
}
|
||||||
@@ -618,14 +727,20 @@
|
@@ -618,14 +728,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
private int lastSpawnChunkRadius;
|
private int lastSpawnChunkRadius;
|
||||||
final EntityTickList entityTickList = new EntityTickList();
|
final EntityTickList entityTickList = new EntityTickList();
|
||||||
public final PersistentEntitySectionManager<Entity> entityManager;
|
public final PersistentEntitySectionManager<Entity> entityManager;
|
||||||
@@ -214,52 +226,194 @@
|
@@ -214,54 +226,203 @@
|
||||||
private final boolean tickTime;
|
private final boolean tickTime;
|
||||||
private final RandomSequences randomSequences;
|
private final RandomSequences randomSequences;
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@
|
||||||
+ }
|
+ }
|
||||||
+ int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3;
|
+ int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3;
|
||||||
+ int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3;
|
+ int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3;
|
||||||
+
|
|
||||||
+ int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3;
|
+ int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3;
|
||||||
+ int maxBlockZ = Mth.floor(axisalignedbb.maxZ + 1.0E-7D) + 3;
|
+ int maxBlockZ = Mth.floor(axisalignedbb.maxZ + 1.0E-7D) + 3;
|
||||||
+
|
+
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
+ ChunkGenerator chunkgenerator = worlddimension.generator();
|
+ ChunkGenerator chunkgenerator = worlddimension.generator();
|
||||||
+ // CraftBukkit start
|
+ // CraftBukkit start
|
||||||
+ this.serverLevelData.setWorld(this);
|
+ this.serverLevelData.setWorld(this);
|
||||||
|
+
|
||||||
+ if (biomeProvider != null) {
|
+ if (biomeProvider != null) {
|
||||||
+ BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME));
|
+ BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME));
|
||||||
+ if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) {
|
+ if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) {
|
||||||
|
@ -279,8 +279,17 @@
|
||||||
+ this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
+ this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ @Override
|
||||||
|
+ public boolean hasChunk(int chunkX, int chunkZ) {
|
||||||
|
+ return this.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ) != null;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
@@ -305,12 +459,20 @@
|
@Deprecated
|
||||||
|
@VisibleForTesting
|
||||||
|
@@ -305,12 +466,20 @@
|
||||||
long j;
|
long j;
|
||||||
|
|
||||||
if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) {
|
if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) {
|
||||||
|
@ -304,7 +313,7 @@
|
||||||
if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) {
|
if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) {
|
||||||
this.resetWeatherCycle();
|
this.resetWeatherCycle();
|
||||||
}
|
}
|
||||||
@@ -345,7 +507,7 @@
|
@@ -345,7 +514,7 @@
|
||||||
|
|
||||||
this.handlingTick = false;
|
this.handlingTick = false;
|
||||||
gameprofilerfiller.pop();
|
gameprofilerfiller.pop();
|
||||||
|
@ -313,7 +322,7 @@
|
||||||
|
|
||||||
if (flag1) {
|
if (flag1) {
|
||||||
this.resetEmptyTime();
|
this.resetEmptyTime();
|
||||||
@@ -359,6 +521,7 @@
|
@@ -359,6 +528,7 @@
|
||||||
gameprofilerfiller.pop();
|
gameprofilerfiller.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +330,7 @@
|
||||||
this.entityTickList.forEach((entity) -> {
|
this.entityTickList.forEach((entity) -> {
|
||||||
if (!entity.isRemoved()) {
|
if (!entity.isRemoved()) {
|
||||||
if (!tickratemanager.isEntityFrozen(entity)) {
|
if (!tickratemanager.isEntityFrozen(entity)) {
|
||||||
@@ -429,7 +592,7 @@
|
@@ -429,7 +599,7 @@
|
||||||
|
|
||||||
private void wakeUpAllPlayers() {
|
private void wakeUpAllPlayers() {
|
||||||
this.sleepStatus.removeAllSleepers();
|
this.sleepStatus.removeAllSleepers();
|
||||||
|
@ -330,7 +339,7 @@
|
||||||
entityplayer.stopSleepInBed(false, false);
|
entityplayer.stopSleepInBed(false, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -442,12 +605,12 @@
|
@@ -442,12 +612,12 @@
|
||||||
ProfilerFiller gameprofilerfiller = Profiler.get();
|
ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||||
|
|
||||||
gameprofilerfiller.push("thunder");
|
gameprofilerfiller.push("thunder");
|
||||||
|
@ -345,7 +354,7 @@
|
||||||
|
|
||||||
if (flag1) {
|
if (flag1) {
|
||||||
SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
|
SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
|
||||||
@@ -456,7 +619,7 @@
|
@@ -456,7 +626,7 @@
|
||||||
entityhorseskeleton.setTrap(true);
|
entityhorseskeleton.setTrap(true);
|
||||||
entityhorseskeleton.setAge(0);
|
entityhorseskeleton.setAge(0);
|
||||||
entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
|
entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
|
||||||
|
@ -354,7 +363,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,18 +628,20 @@
|
@@ -465,18 +635,20 @@
|
||||||
if (entitylightning != null) {
|
if (entitylightning != null) {
|
||||||
entitylightning.moveTo(Vec3.atBottomCenterOf(blockposition));
|
entitylightning.moveTo(Vec3.atBottomCenterOf(blockposition));
|
||||||
entitylightning.setVisualOnly(flag1);
|
entitylightning.setVisualOnly(flag1);
|
||||||
|
@ -376,7 +385,7 @@
|
||||||
|
|
||||||
gameprofilerfiller.popPush("tickBlocks");
|
gameprofilerfiller.popPush("tickBlocks");
|
||||||
if (randomTickSpeed > 0) {
|
if (randomTickSpeed > 0) {
|
||||||
@@ -521,7 +686,7 @@
|
@@ -521,7 +693,7 @@
|
||||||
Biome biomebase = (Biome) this.getBiome(blockposition1).value();
|
Biome biomebase = (Biome) this.getBiome(blockposition1).value();
|
||||||
|
|
||||||
if (biomebase.shouldFreeze(this, blockposition2)) {
|
if (biomebase.shouldFreeze(this, blockposition2)) {
|
||||||
|
@ -385,7 +394,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isRaining()) {
|
if (this.isRaining()) {
|
||||||
@@ -537,10 +702,10 @@
|
@@ -537,10 +709,10 @@
|
||||||
BlockState iblockdata1 = (BlockState) iblockdata.setValue(SnowLayerBlock.LAYERS, j + 1);
|
BlockState iblockdata1 = (BlockState) iblockdata.setValue(SnowLayerBlock.LAYERS, j + 1);
|
||||||
|
|
||||||
Block.pushEntitiesUp(iblockdata, iblockdata1, this, blockposition1);
|
Block.pushEntitiesUp(iblockdata, iblockdata1, this, blockposition1);
|
||||||
|
@ -398,7 +407,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,33 +866,67 @@
|
@@ -701,33 +873,67 @@
|
||||||
this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F);
|
this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +483,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetEmptyTime() {
|
public void resetEmptyTime() {
|
||||||
@@ -754,6 +953,13 @@
|
@@ -754,6 +960,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tickNonPassenger(Entity entity) {
|
public void tickNonPassenger(Entity entity) {
|
||||||
|
@ -488,7 +497,7 @@
|
||||||
entity.setOldPosAndRot();
|
entity.setOldPosAndRot();
|
||||||
ProfilerFiller gameprofilerfiller = Profiler.get();
|
ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||||
|
|
||||||
@@ -763,6 +969,7 @@
|
@@ -763,6 +976,7 @@
|
||||||
});
|
});
|
||||||
gameprofilerfiller.incrementCounter("tickNonPassenger");
|
gameprofilerfiller.incrementCounter("tickNonPassenger");
|
||||||
entity.tick();
|
entity.tick();
|
||||||
|
@ -496,7 +505,7 @@
|
||||||
gameprofilerfiller.pop();
|
gameprofilerfiller.pop();
|
||||||
Iterator iterator = entity.getPassengers().iterator();
|
Iterator iterator = entity.getPassengers().iterator();
|
||||||
|
|
||||||
@@ -786,6 +993,7 @@
|
@@ -786,6 +1000,7 @@
|
||||||
});
|
});
|
||||||
gameprofilerfiller.incrementCounter("tickPassenger");
|
gameprofilerfiller.incrementCounter("tickPassenger");
|
||||||
passenger.rideTick();
|
passenger.rideTick();
|
||||||
|
@ -504,7 +513,7 @@
|
||||||
gameprofilerfiller.pop();
|
gameprofilerfiller.pop();
|
||||||
Iterator iterator = passenger.getPassengers().iterator();
|
Iterator iterator = passenger.getPassengers().iterator();
|
||||||
|
|
||||||
@@ -810,6 +1018,7 @@
|
@@ -810,6 +1025,7 @@
|
||||||
ServerChunkCache chunkproviderserver = this.getChunkSource();
|
ServerChunkCache chunkproviderserver = this.getChunkSource();
|
||||||
|
|
||||||
if (!savingDisabled) {
|
if (!savingDisabled) {
|
||||||
|
@ -512,7 +521,7 @@
|
||||||
if (progressListener != null) {
|
if (progressListener != null) {
|
||||||
progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel"));
|
progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel"));
|
||||||
}
|
}
|
||||||
@@ -827,11 +1036,19 @@
|
@@ -827,11 +1043,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -533,7 +542,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
DimensionDataStorage worldpersistentdata = this.getChunkSource().getDataStorage();
|
DimensionDataStorage worldpersistentdata = this.getChunkSource().getDataStorage();
|
||||||
@@ -903,18 +1120,40 @@
|
@@ -903,18 +1127,40 @@
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addFreshEntity(Entity entity) {
|
public boolean addFreshEntity(Entity entity) {
|
||||||
|
@ -577,7 +586,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -939,41 +1178,93 @@
|
@@ -939,41 +1185,93 @@
|
||||||
this.entityManager.addNewEntity(player);
|
this.entityManager.addNewEntity(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,7 +685,7 @@
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
||||||
|
|
||||||
@@ -982,6 +1273,12 @@
|
@@ -982,6 +1280,12 @@
|
||||||
double d1 = (double) pos.getY() - entityplayer.getY();
|
double d1 = (double) pos.getY() - entityplayer.getY();
|
||||||
double d2 = (double) pos.getZ() - entityplayer.getZ();
|
double d2 = (double) pos.getZ() - entityplayer.getZ();
|
||||||
|
|
||||||
|
@ -689,7 +698,7 @@
|
||||||
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
|
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
|
||||||
entityplayer.connection.send(new ClientboundBlockDestructionPacket(entityId, pos, progress));
|
entityplayer.connection.send(new ClientboundBlockDestructionPacket(entityId, pos, progress));
|
||||||
}
|
}
|
||||||
@@ -1030,7 +1327,7 @@
|
@@ -1030,7 +1334,7 @@
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void levelEvent(@Nullable Player player, int eventId, BlockPos pos, int data) {
|
public void levelEvent(@Nullable Player player, int eventId, BlockPos pos, int data) {
|
||||||
|
@ -698,7 +707,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLogicalHeight() {
|
public int getLogicalHeight() {
|
||||||
@@ -1060,7 +1357,18 @@
|
@@ -1060,7 +1364,18 @@
|
||||||
Iterator iterator = this.navigatingMobs.iterator();
|
Iterator iterator = this.navigatingMobs.iterator();
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
|
@ -718,7 +727,7 @@
|
||||||
PathNavigation navigationabstract = entityinsentient.getNavigation();
|
PathNavigation navigationabstract = entityinsentient.getNavigation();
|
||||||
|
|
||||||
if (navigationabstract.shouldRecomputePath(pos)) {
|
if (navigationabstract.shouldRecomputePath(pos)) {
|
||||||
@@ -1086,11 +1394,13 @@
|
@@ -1086,11 +1401,13 @@
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateNeighborsAt(BlockPos pos, Block block) {
|
public void updateNeighborsAt(BlockPos pos, Block block) {
|
||||||
|
@ -732,7 +741,7 @@
|
||||||
this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null, orientation);
|
this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null, orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,9 +1436,20 @@
|
@@ -1126,9 +1443,20 @@
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions smallParticle, ParticleOptions largeParticle, Holder<SoundEvent> soundEvent) {
|
public void explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions smallParticle, ParticleOptions largeParticle, Holder<SoundEvent> soundEvent) {
|
||||||
|
@ -754,7 +763,7 @@
|
||||||
case NONE:
|
case NONE:
|
||||||
explosion_effect = Explosion.BlockInteraction.KEEP;
|
explosion_effect = Explosion.BlockInteraction.KEEP;
|
||||||
break;
|
break;
|
||||||
@@ -1144,16 +1465,27 @@
|
@@ -1144,16 +1472,27 @@
|
||||||
case TRIGGER:
|
case TRIGGER:
|
||||||
explosion_effect = Explosion.BlockInteraction.TRIGGER_BLOCK;
|
explosion_effect = Explosion.BlockInteraction.TRIGGER_BLOCK;
|
||||||
break;
|
break;
|
||||||
|
@ -785,7 +794,7 @@
|
||||||
Iterator iterator = this.players.iterator();
|
Iterator iterator = this.players.iterator();
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
@@ -1162,10 +1494,11 @@
|
@@ -1162,10 +1501,11 @@
|
||||||
if (entityplayer.distanceToSqr(vec3d) < 4096.0D) {
|
if (entityplayer.distanceToSqr(vec3d) < 4096.0D) {
|
||||||
Optional<Vec3> optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer));
|
Optional<Vec3> optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer));
|
||||||
|
|
||||||
|
@ -798,7 +807,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayRule) {
|
private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayRule) {
|
||||||
@@ -1226,17 +1559,29 @@
|
@@ -1226,17 +1566,29 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends ParticleOptions> int sendParticles(T parameters, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) {
|
public <T extends ParticleOptions> int sendParticles(T parameters, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) {
|
||||||
|
@ -834,7 +843,7 @@
|
||||||
++j;
|
++j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1292,7 +1637,7 @@
|
@@ -1292,7 +1644,7 @@
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) {
|
public BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) {
|
||||||
|
@ -843,7 +852,7 @@
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
Optional<HolderSet.Named<Structure>> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag);
|
Optional<HolderSet.Named<Structure>> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag);
|
||||||
@@ -1334,11 +1679,22 @@
|
@@ -1334,11 +1686,22 @@
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public MapItemSavedData getMapData(MapId id) {
|
public MapItemSavedData getMapData(MapId id) {
|
||||||
|
@ -867,7 +876,7 @@
|
||||||
this.getServer().overworld().getDataStorage().set(id.key(), state);
|
this.getServer().overworld().getDataStorage().set(id.key(), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1649,6 +2005,11 @@
|
@@ -1649,6 +2012,11 @@
|
||||||
@Override
|
@Override
|
||||||
public void blockUpdated(BlockPos pos, Block block) {
|
public void blockUpdated(BlockPos pos, Block block) {
|
||||||
if (!this.isDebug()) {
|
if (!this.isDebug()) {
|
||||||
|
@ -879,7 +888,7 @@
|
||||||
this.updateNeighborsAt(pos, block);
|
this.updateNeighborsAt(pos, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1668,12 +2029,12 @@
|
@@ -1668,12 +2036,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFlat() {
|
public boolean isFlat() {
|
||||||
|
@ -894,7 +903,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -1696,7 +2057,7 @@
|
@@ -1696,7 +2064,7 @@
|
||||||
private static <T> String getTypeCount(Iterable<T> items, Function<T, String> classifier) {
|
private static <T> String getTypeCount(Iterable<T> items, Function<T, String> classifier) {
|
||||||
try {
|
try {
|
||||||
Object2IntOpenHashMap<String> object2intopenhashmap = new Object2IntOpenHashMap();
|
Object2IntOpenHashMap<String> object2intopenhashmap = new Object2IntOpenHashMap();
|
||||||
|
@ -903,7 +912,7 @@
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
T t0 = iterator.next();
|
T t0 = iterator.next();
|
||||||
@@ -1705,7 +2066,7 @@
|
@@ -1705,7 +2073,7 @@
|
||||||
object2intopenhashmap.addTo(s, 1);
|
object2intopenhashmap.addTo(s, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -912,7 +921,7 @@
|
||||||
String s1 = (String) entry.getKey();
|
String s1 = (String) entry.getKey();
|
||||||
|
|
||||||
return s1 + ":" + entry.getIntValue();
|
return s1 + ":" + entry.getIntValue();
|
||||||
@@ -1717,6 +2078,7 @@
|
@@ -1717,6 +2085,7 @@
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LevelEntityGetter<Entity> getEntities() {
|
public LevelEntityGetter<Entity> getEntities() {
|
||||||
|
@ -920,7 +929,7 @@
|
||||||
return this.entityManager.getEntityGetter();
|
return this.entityManager.getEntityGetter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1802,6 +2164,17 @@
|
@@ -1802,6 +2171,17 @@
|
||||||
return this.serverLevelData.getGameRules();
|
return this.serverLevelData.getGameRules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -938,7 +947,7 @@
|
||||||
@Override
|
@Override
|
||||||
public CrashReportCategory fillReportDetails(CrashReport report) {
|
public CrashReportCategory fillReportDetails(CrashReport report) {
|
||||||
CrashReportCategory crashreportsystemdetails = super.fillReportDetails(report);
|
CrashReportCategory crashreportsystemdetails = super.fillReportDetails(report);
|
||||||
@@ -1836,6 +2209,7 @@
|
@@ -1836,6 +2216,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTrackingStart(Entity entity) {
|
public void onTrackingStart(Entity entity) {
|
||||||
|
@ -946,7 +955,7 @@
|
||||||
ServerLevel.this.getChunkSource().addEntity(entity);
|
ServerLevel.this.getChunkSource().addEntity(entity);
|
||||||
if (entity instanceof ServerPlayer entityplayer) {
|
if (entity instanceof ServerPlayer entityplayer) {
|
||||||
ServerLevel.this.players.add(entityplayer);
|
ServerLevel.this.players.add(entityplayer);
|
||||||
@@ -1864,9 +2238,52 @@
|
@@ -1864,9 +2245,52 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
|
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
|
||||||
|
@ -999,7 +1008,7 @@
|
||||||
ServerLevel.this.getChunkSource().removeEntity(entity);
|
ServerLevel.this.getChunkSource().removeEntity(entity);
|
||||||
if (entity instanceof ServerPlayer entityplayer) {
|
if (entity instanceof ServerPlayer entityplayer) {
|
||||||
ServerLevel.this.players.remove(entityplayer);
|
ServerLevel.this.players.remove(entityplayer);
|
||||||
@@ -1895,6 +2312,15 @@
|
@@ -1895,6 +2319,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.updateDynamicGameEventListener(DynamicGameEventListener::remove);
|
entity.updateDynamicGameEventListener(DynamicGameEventListener::remove);
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
package com.destroystokyo.paper.io;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public class SyncLoadFinder {
|
||||||
|
|
||||||
|
public static final boolean ENABLED = Boolean.getBoolean("paper.debug-sync-loads");
|
||||||
|
|
||||||
|
private static final WeakHashMap<Level, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation>> SYNC_LOADS = new WeakHashMap<>();
|
||||||
|
|
||||||
|
private static final class SyncLoadInformation {
|
||||||
|
|
||||||
|
public int times;
|
||||||
|
|
||||||
|
public final Long2IntOpenHashMap coordinateTimes = new Long2IntOpenHashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clear() {
|
||||||
|
SYNC_LOADS.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void logSyncLoad(final Level world, final int chunkX, final int chunkZ) {
|
||||||
|
if (!ENABLED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ThrowableWithEquals stacktrace = new ThrowableWithEquals(Thread.currentThread().getStackTrace());
|
||||||
|
|
||||||
|
SYNC_LOADS.compute(world, (final Level keyInMap, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation> map) -> {
|
||||||
|
if (map == null) {
|
||||||
|
map = new Object2ObjectOpenHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
map.compute(stacktrace, (ThrowableWithEquals keyInMap0, SyncLoadInformation valueInMap) -> {
|
||||||
|
if (valueInMap == null) {
|
||||||
|
valueInMap = new SyncLoadInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
++valueInMap.times;
|
||||||
|
|
||||||
|
valueInMap.coordinateTimes.compute(ChunkPos.asLong(chunkX, chunkZ), (Long keyInMap1, Integer valueInMap1) -> {
|
||||||
|
return valueInMap1 == null ? Integer.valueOf(1) : Integer.valueOf(valueInMap1.intValue() + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
return valueInMap;
|
||||||
|
});
|
||||||
|
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonObject serialize() {
|
||||||
|
final JsonObject ret = new JsonObject();
|
||||||
|
|
||||||
|
final JsonArray worldsData = new JsonArray();
|
||||||
|
|
||||||
|
for (final Map.Entry<Level, Object2ObjectOpenHashMap<ThrowableWithEquals, SyncLoadInformation>> entry : SYNC_LOADS.entrySet()) {
|
||||||
|
final Level world = entry.getKey();
|
||||||
|
|
||||||
|
final JsonObject worldData = new JsonObject();
|
||||||
|
|
||||||
|
worldData.addProperty("name", world.getWorld().getName());
|
||||||
|
|
||||||
|
final List<Pair<ThrowableWithEquals, SyncLoadInformation>> data = new ArrayList<>();
|
||||||
|
|
||||||
|
entry.getValue().forEach((ThrowableWithEquals stacktrace, SyncLoadInformation times) -> {
|
||||||
|
data.add(new Pair<>(stacktrace, times));
|
||||||
|
});
|
||||||
|
|
||||||
|
data.sort((Pair<ThrowableWithEquals, SyncLoadInformation> pair1, Pair<ThrowableWithEquals, SyncLoadInformation> pair2) -> {
|
||||||
|
return Integer.compare(pair2.getSecond().times, pair1.getSecond().times); // reverse order
|
||||||
|
});
|
||||||
|
|
||||||
|
final JsonArray stacktraces = new JsonArray();
|
||||||
|
|
||||||
|
for (Pair<ThrowableWithEquals, SyncLoadInformation> pair : data) {
|
||||||
|
final JsonObject stacktrace = new JsonObject();
|
||||||
|
|
||||||
|
stacktrace.addProperty("times", pair.getSecond().times);
|
||||||
|
|
||||||
|
final JsonArray traces = new JsonArray();
|
||||||
|
|
||||||
|
for (StackTraceElement element : pair.getFirst().stacktrace) {
|
||||||
|
traces.add(String.valueOf(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
stacktrace.add("stacktrace", traces);
|
||||||
|
|
||||||
|
final JsonArray coordinates = new JsonArray();
|
||||||
|
|
||||||
|
for (Long2IntMap.Entry coordinate : pair.getSecond().coordinateTimes.long2IntEntrySet()) {
|
||||||
|
final long key = coordinate.getLongKey();
|
||||||
|
final int times = coordinate.getIntValue();
|
||||||
|
final ChunkPos chunkPos = new ChunkPos(key);
|
||||||
|
coordinates.add("(" + chunkPos.x + "," + chunkPos.z + "): " + times);
|
||||||
|
}
|
||||||
|
|
||||||
|
stacktrace.add("coordinates", coordinates);
|
||||||
|
|
||||||
|
stacktraces.add(stacktrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
worldData.add("stacktraces", stacktraces);
|
||||||
|
worldsData.add(worldData);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.add("worlds", worldsData);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class ThrowableWithEquals {
|
||||||
|
|
||||||
|
private final StackTraceElement[] stacktrace;
|
||||||
|
private final int hash;
|
||||||
|
|
||||||
|
public ThrowableWithEquals(final StackTraceElement[] stacktrace) {
|
||||||
|
this.stacktrace = stacktrace;
|
||||||
|
this.hash = ThrowableWithEquals.hash(stacktrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int hash(final StackTraceElement[] stacktrace) {
|
||||||
|
int hash = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < stacktrace.length; ++i) {
|
||||||
|
hash *= 31;
|
||||||
|
hash += stacktrace[i].hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return this.hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj == null || obj.getClass() != this.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ThrowableWithEquals other = (ThrowableWithEquals)obj;
|
||||||
|
final StackTraceElement[] otherStackTrace = other.stacktrace;
|
||||||
|
|
||||||
|
if (this.stacktrace.length != otherStackTrace.length || this.hash != other.hash) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.stacktrace.length; ++i) {
|
||||||
|
if (!this.stacktrace[i].equals(otherStackTrace[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ public final class PaperCommand extends Command {
|
||||||
commands.put(Set.of("reload"), new ReloadCommand());
|
commands.put(Set.of("reload"), new ReloadCommand());
|
||||||
commands.put(Set.of("version"), new VersionCommand());
|
commands.put(Set.of("version"), new VersionCommand());
|
||||||
commands.put(Set.of("dumpplugins"), new DumpPluginsCommand());
|
commands.put(Set.of("dumpplugins"), new DumpPluginsCommand());
|
||||||
|
commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
|
||||||
|
|
||||||
return commands.entrySet().stream()
|
return commands.entrySet().stream()
|
||||||
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
|
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package io.papermc.paper.command.subcommands;
|
||||||
|
|
||||||
|
import com.destroystokyo.paper.io.SyncLoadFinder;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.internal.Streams;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import io.papermc.paper.command.CommandUtil;
|
||||||
|
import io.papermc.paper.command.PaperSubcommand;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||||
|
|
||||||
|
import static net.kyori.adventure.text.Component.text;
|
||||||
|
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||||
|
import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
|
||||||
|
import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||||
|
import static net.kyori.adventure.text.format.NamedTextColor.WHITE;
|
||||||
|
|
||||||
|
@DefaultQualifier(NonNull.class)
|
||||||
|
public final class SyncLoadInfoCommand implements PaperSubcommand {
|
||||||
|
@Override
|
||||||
|
public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
|
||||||
|
this.doSyncLoadInfo(sender, args);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
|
||||||
|
return CommandUtil.getListMatchingLast(sender, args, "clear");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss");
|
||||||
|
|
||||||
|
private void doSyncLoadInfo(final CommandSender sender, final String[] args) {
|
||||||
|
if (!SyncLoadFinder.ENABLED) {
|
||||||
|
String systemFlag = "-Dpaper.debug-sync-loads=true";
|
||||||
|
sender.sendMessage(text().color(RED).append(text("This command requires the server startup flag '")).append(
|
||||||
|
text(systemFlag, WHITE).clickEvent(ClickEvent.copyToClipboard(systemFlag))
|
||||||
|
.hoverEvent(HoverEvent.showText(text("Click to copy the system flag")))).append(
|
||||||
|
text("' to be set.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length > 0 && args[0].equals("clear")) {
|
||||||
|
SyncLoadFinder.clear();
|
||||||
|
sender.sendMessage(text("Sync load data cleared.", GRAY));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(new File(new File("."), "debug"),
|
||||||
|
"sync-load-info-" + FORMATTER.format(LocalDateTime.now()) + ".txt");
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
sender.sendMessage(text("Writing sync load info to " + file, GREEN));
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
final JsonObject data = SyncLoadFinder.serialize();
|
||||||
|
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||||
|
jsonWriter.setIndent(" ");
|
||||||
|
jsonWriter.setLenient(false);
|
||||||
|
Streams.write(data, jsonWriter);
|
||||||
|
|
||||||
|
try (
|
||||||
|
PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8)
|
||||||
|
) {
|
||||||
|
out.print(stringWriter);
|
||||||
|
}
|
||||||
|
sender.sendMessage(text("Successfully written sync load information!", GREEN));
|
||||||
|
} catch (Throwable thr) {
|
||||||
|
sender.sendMessage(text("Failed to write sync load information! See the console for more info.", RED));
|
||||||
|
MinecraftServer.LOGGER.warn("Error occurred while dumping sync chunk load info", thr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue