diff --git a/src/main/java/me/earthme/millacat/hook/ServerThreadingHooks.java b/src/main/java/me/earthme/millacat/hook/ServerThreadingHooks.java index a396954..e976c79 100644 --- a/src/main/java/me/earthme/millacat/hook/ServerThreadingHooks.java +++ b/src/main/java/me/earthme/millacat/hook/ServerThreadingHooks.java @@ -2,6 +2,10 @@ import com.google.common.collect.Maps; import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.longs.Long2BooleanLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2BooleanMap; +import it.unimi.dsi.fastutil.longs.Long2BooleanOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import me.earthme.millacat.concurrent.SplittingTraverseTask; import me.earthme.millacat.concurrent.thread.TickForkJoinWorker; import me.earthme.millacat.concurrent.thread.TickThreadImpl; @@ -21,6 +25,7 @@ import net.minecraft.world.ticks.ScheduledTick; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.bukkit.Chunk; import org.bukkit.craftbukkit.v1_18_R2.SpigotTimings; import org.jetbrains.annotations.NotNull; @@ -128,11 +133,11 @@ public static void callGlobalTileEntityTickTask(ServerLevel levelIn){ } final AtomicInteger taskCounter = worldTaskCount.get(levelIn); - for (Map.Entry> split : groupByChunk(levelIn.blockEntityTickers).entrySet()){ + for (List split : remerge(groupByChunk(levelIn.blockEntityTickers))){ taskCounter.getAndIncrement(); tileEntityThreadPool.execute(()->{ try { - for (Locatable l : split.getValue()){ + for (Locatable l : split){ final TickingBlockEntity tickingblockentity = ((TickingBlockEntity) l); if (tickingblockentity.isRemoved()) { @@ -170,6 +175,62 @@ public static Map> groupByChunk(Collection getNeighbors(ChunkPos pos) { + List neighbors = new ArrayList<>(); + for (int dx = -1; dx <= 1; dx++) { + for (int dz = -1; dz <= 1; dz++) { + if (dx != 0 || dz != 0) { + neighbors.add(new ChunkPos(pos.x + dx, pos.z + dz)); + } + } + } + return neighbors; + } + + public static Collection> remerge(Map> map) { + Map> aggregatedMap = new HashMap<>(); + Set visited = new HashSet<>(); + + for (Long chunkPos : map.keySet()) { + if (visited.contains(chunkPos)) { + continue; // 如果已访问过该 Chunk,则跳过 + } + + List locatables = new ArrayList<>(); + Queue queue = new LinkedList<>(); + queue.offer(new ChunkPos(chunkPos)); + visited.add(chunkPos); + + while (!queue.isEmpty()) { + ChunkPos currentPos = queue.poll(); + locatables.addAll(map.get(chunkPos)); + + for (ChunkPos neighbor : getNeighbors(currentPos)) { + Long neighborKey = neighbor.toLong(); + if (!visited.contains(neighborKey) && map.containsKey(neighborKey) && + distance(currentPos,neighbor) <= 2) { + queue.offer(neighbor); + visited.add(neighborKey); + } + } + } + + long newKey = (chunkPos >> 32) << 32 | (chunkPos & 0xffffffffL); // 更新 key 为最左上角的 ChunkPos + aggregatedMap.put(newKey, locatables); + } + + + return aggregatedMap.values(); + } + + + private static double distance(ChunkPos point1, ChunkPos point2) { + int deltaX = point2.x - point1.x; + int deltaZ = point2.z - point1.z; + + return Math.sqrt(deltaX * deltaX + deltaZ * deltaZ); + } + public static void postRunScheduledTicks(LevelTicks ticks, BiConsumer action){ final List> scheduledTicks = new ArrayList<>(); final AtomicInteger taskCounter = worldTaskCount.get(ticks.level); @@ -191,11 +252,11 @@ public static void postRunScheduledTicks(LevelTicks ticks, BiConsumer toRun = new ArrayList<>(); - for (Map.Entry> split : groupByChunk(scheduledTicks).entrySet()){ + for (List split : remerge(groupByChunk(scheduledTicks))){ taskCounter.getAndIncrement(); toRun.add(() -> { try { - for (Locatable l : split.getValue()){ + for (Locatable l : split){ final ScheduledTick scheduledTick = ((ScheduledTick) l); action.accept(scheduledTick.pos(), scheduledTick.type()); @@ -215,11 +276,11 @@ public static void postEntityTicKTask(ServerLevel level){ final AtomicInteger taskCounter = worldTaskCount.get(level); final List toRun = new ArrayList<>(); - for (Map.Entry> split : groupByChunk(level.entityTickList.entities).entrySet()){ + for (List split : remerge(groupByChunk(level.entityTickList.entities))){ taskCounter.getAndIncrement(); toRun.add(() -> { try { - for (Locatable entityInO : split.getValue()){ + for (Locatable entityInO : split){ Entity entityIn = ((Entity) entityInO); if (!entityIn.isRemoved()) { if (level.shouldDiscardEntity(entityIn)) { diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 7bb26dd..3ea4b34 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -434,10 +434,7 @@ public static void onLivingJump(LivingEntity entity) @Nullable public static ItemEntity onPlayerTossEvent(@Nonnull Player player, @Nonnull ItemStack item, boolean includeName) { - player.captureDrops(Lists.newArrayList()); ItemEntity ret = player.drop(item, false, includeName); - player.captureDrops(null); - if (ret == null) return null;