This commit is contained in:
MoePus committed 2026-01-18 23:20:49 +09:00
1 parent e75b4f309a
commit ff1e30907c
9 files changed
+157 -7

No files matched your search

+1 -1
View File
@@ -29,7 +29,7 @@ mod_name=ServerWarashi
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=MIT
# The mod version. See https://semver.org/
mod_version=1.0.0
mod_version=1.0.1
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,56 @@
package com.moepus.serverwarashi;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
public class ChunkLoadInfo {
public int blockEntityCount;
public int entityCount;
public static void dumpToCsv(@NotNull HashMap<Long, ChunkLoadInfo> chunkLoadInfoMap) {
Path logDir = Paths.get("chunk_load");
var timestamp = LocalDateTime.now().toString().replace(":", "-").replace(".", "-");
var fileName = "chunk_load_info_" + timestamp + ".csv";
Path csvPath = logDir.resolve(fileName);
try {
Files.createDirectories(logDir);
try (BufferedWriter writer = Files.newBufferedWriter(csvPath)) {
writer.write("chunk_x,chunk_z,block_x,block_y,block_z,blockEntityCount,entityCount");
writer.newLine();
for (Map.Entry<Long, ChunkLoadInfo> entry : chunkLoadInfoMap.entrySet()) {
long chunkLong = entry.getKey();
ChunkLoadInfo info = entry.getValue();
ChunkPos chunkPos = new ChunkPos(chunkLong);
BlockPos blockPos = chunkPos.getWorldPosition();
writer.write(
chunkPos.x + "," +
chunkPos.z + "," +
blockPos.getX() + "," +
0 + "," +
blockPos.getZ() + "," +
info.blockEntityCount + "," +
info.entityCount
);
writer.newLine();
}
}
} catch (IOException ignored) {
}
}
}
@@ -4,7 +4,9 @@ import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.*;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.Ticket;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.state.BlockState;
import java.lang.reflect.Field;
@@ -46,6 +48,21 @@ public class TicketOwner<OwnerType> {
this.name = "Unknown entity";
}
}
} else if (ticket.getType() == TicketType.PLAYER) {
owner = "player";
final double[] mostNearDistance = {Double.MAX_VALUE};
BlockPos ticketPos = ((ChunkPos) key).getWorldPosition();
level.players().forEach(serverPlayer -> {
double distance = serverPlayer.blockPosition().distSqr(ticketPos);
if (distance < mostNearDistance[0]) {
mostNearDistance[0] = distance;
this.name = serverPlayer.getName().getString();
pos = serverPlayer.blockPosition();
}
});
} else if (ticket.getType() == TicketType.START) {
owner = "world_start";
this.pos = level.getSharedSpawnPos();
} else {
owner = key;
if (owner instanceof BlockPos blockPos) {
@@ -1,6 +1,9 @@
package com.moepus.serverwarashi;
import com.moepus.serverwarashi.mixin.DistanceManagerAccessor;
import com.moepus.serverwarashi.mixin.EntitySectionStorageAccessor;
import com.moepus.serverwarashi.mixin.PersistentEntitySectionManagerAccessor;
import com.moepus.serverwarashi.mixin.ServerLevelAcessor;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
@@ -14,15 +17,20 @@ import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.server.level.*;
import net.minecraft.util.SortedArraySet;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.entity.EntitySection;
import net.minecraft.world.level.entity.EntitySectionStorage;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
public class WarashiCommands {
private static final java.util.function.Predicate<CommandSourceStack> ADMIN_PERMISSION =
@@ -119,8 +127,8 @@ public class WarashiCommands {
private static Ticket<?> GetTicket(SortedArraySet<Ticket<?>> tickets, boolean currentWorking) {
for (Ticket<?> ticket : tickets) {
if (ticket.getType() == TicketType.PLAYER) continue;
if (ticket.getType() == TicketType.START) continue;
// if (ticket.getType() == TicketType.PLAYER) continue;
// if (ticket.getType() == TicketType.START) continue;
int level;
if (currentWorking) {
@@ -129,7 +137,7 @@ public class WarashiCommands {
IPauseableTicket pauseable = (IPauseableTicket) (Object) ticket;
level = pauseable.serverWarashi$getLevel();
}
if (level > 32) continue;
if (level > 33) continue;
return ticket;
}
@@ -157,25 +165,54 @@ public class WarashiCommands {
ownerMap.computeIfAbsent(owner, k -> new HashSet<>()).add(chunkPos);
}
PersistentEntitySectionManager<Entity> entityManager = ((ServerLevelAcessor) level).getEntityManager();
PersistentEntitySectionManagerAccessor entityAccessor = (PersistentEntitySectionManagerAccessor) entityManager;
EntitySectionStorage<?> sectionStorage = entityAccessor.getSectionStorage();
EntitySectionStorageAccessor sectionAccessor = (EntitySectionStorageAccessor) sectionStorage;
HashMap<Long, ChunkLoadInfo> chunkLoadInfoMap = new HashMap<>();
for (var entry : ownerMap.entrySet()) {
TicketOwner<?> owner = entry.getKey();
Set<Long> chunks = entry.getValue();
message.append(owner.asComponent());
message.append(" loads " + chunks.size() + " chunks ");
message.append(" C:" + chunks.size() + ",");
// Block Entity count
int totalBlockEntities = 0;
for (long chunkPos : chunks) {
ChunkPos pos = new ChunkPos(chunkPos);
ChunkAccess chunk = level.getChunk(pos.x, pos.z, ChunkStatus.FULL, false);
if (chunk != null) {
totalBlockEntities += chunk.getBlockEntitiesPos().size();
int chunkBlockEntities = chunk.getBlockEntitiesPos().size();
totalBlockEntities += chunkBlockEntities;
chunkLoadInfoMap.computeIfAbsent(chunkPos, k -> new ChunkLoadInfo()).blockEntityCount = chunkBlockEntities;
}
}
message.append("with " + totalBlockEntities + " block entities\n");
message.append(" BE: " + totalBlockEntities + ",");
// Entity count
int totalEntities = 0;
for (long chunkPos : chunks) {
ChunkPos pos = new ChunkPos(chunkPos);
AtomicInteger chunkEntities = new AtomicInteger();
sectionAccessor.invokeGetChunkSections(pos.x, pos.z).forEach(sectionIndex -> {
EntitySection<?> section = sectionStorage.getSection(sectionIndex);
if (section == null)
return;
chunkEntities.addAndGet(section.size());
});
totalEntities += chunkEntities.get();
chunkLoadInfoMap.computeIfAbsent(chunkPos, k -> new ChunkLoadInfo()).entityCount = chunkEntities.get();
}
message.append(" E: " + totalEntities + ".\n");
}
if (ownerMap.isEmpty()) {
message.append("No tickets found\n");
}
if (!chunkLoadInfoMap.isEmpty()) {
ChunkLoadInfo.dumpToCsv(chunkLoadInfoMap);
}
return message;
}, true)
;
@@ -0,0 +1,12 @@
package com.moepus.serverwarashi.mixin;
import it.unimi.dsi.fastutil.longs.LongSortedSet;
import net.minecraft.world.level.entity.EntitySectionStorage;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(value = EntitySectionStorage.class, remap = false)
public interface EntitySectionStorageAccessor {
@Invoker
LongSortedSet invokeGetChunkSections(int x, int z);
}
@@ -0,0 +1,12 @@
package com.moepus.serverwarashi.mixin;
import net.minecraft.world.level.entity.EntitySectionStorage;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(value = PersistentEntitySectionManager.class, remap = false)
public interface PersistentEntitySectionManagerAccessor {
@Accessor
EntitySectionStorage<?> getSectionStorage();
}
@@ -0,0 +1,13 @@
package com.moepus.serverwarashi.mixin;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(value = ServerLevel.class, remap = false)
public interface ServerLevelAcessor {
@Accessor
PersistentEntitySectionManager<Entity> getEntityManager();
}
@@ -5,6 +5,9 @@
"compatibilityLevel": "JAVA_21",
"mixins": [
"DistanceManagerAccessor",
"EntitySectionStorageAccessor",
"PersistentEntitySectionManagerAccessor",
"ServerLevelAcessor",
"TicketMixin"
],
"client": [