diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java index 481e12663..0cc7ab429 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java @@ -5,6 +5,7 @@ import com.atsuishio.superbwarfare.config.server.ExplosionDestroyConfig; import com.atsuishio.superbwarfare.entity.AnimatedEntity; import com.atsuishio.superbwarfare.init.*; import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.ChunkLoadTool; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.ProjectileTool; @@ -25,7 +26,6 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.projectile.ThrowableItemProjectile; import net.minecraft.world.item.Item; -import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -35,7 +35,6 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.world.ForgeChunkManager; import net.minecraftforge.network.NetworkHooks; import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.PlayMessages; @@ -272,21 +271,8 @@ public class CannonShellEntity extends ThrowableItemProjectile implements GeoEnt ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, 1, 0, 0, 0, 0.001, true); - var movement = this.getDeltaMovement(); - var currentX = this.chunkPosition().x; - var currentZ = this.chunkPosition().z; - var nextX = movement.x > 0 ? currentX + 1 : currentX - 1; - var nextZ = movement.z > 0 ? currentZ + 1 : currentZ - 1; - - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, currentX, currentZ, true, false); - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, currentX, nextZ, true, false); - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, nextX, currentZ, true, false); - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, nextX, nextZ, true, false); - - this.loadedChunks.add(ChunkPos.asLong(currentX, currentZ)); - this.loadedChunks.add(ChunkPos.asLong(currentX, nextZ)); - this.loadedChunks.add(ChunkPos.asLong(nextX, currentZ)); - this.loadedChunks.add(ChunkPos.asLong(nextX, nextZ)); + // 更新需要加载的区块 + ChunkLoadTool.updateLoadedChunks(serverLevel, this, this.loadedChunks); } if (this.tickCount > 600 || this.isInWater()) { if (this.level() instanceof ServerLevel) { @@ -404,9 +390,7 @@ public class CannonShellEntity extends ThrowableItemProjectile implements GeoEnt @Override public void onRemovedFromWorld() { if (this.level() instanceof ServerLevel serverLevel) { - for (long chunkPos : this.loadedChunks) { - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, ChunkPos.getX(chunkPos), ChunkPos.getZ(chunkPos), false, false); - } + ChunkLoadTool.unloadAllChunks(serverLevel, this, this.loadedChunks); } super.onRemovedFromWorld(); } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MortarShellEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MortarShellEntity.java index 01a47d865..28f33d93c 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MortarShellEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MortarShellEntity.java @@ -1,10 +1,10 @@ package com.atsuishio.superbwarfare.entity.projectile; -import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.config.server.ExplosionConfig; import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.ChunkLoadTool; import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.ProjectileTool; import net.minecraft.core.BlockPos; @@ -25,7 +25,6 @@ import net.minecraft.world.level.block.BellBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; -import net.minecraftforge.common.world.ForgeChunkManager; import net.minecraftforge.network.NetworkHooks; import net.minecraftforge.network.PlayMessages; import software.bernie.geckolib.animatable.GeoEntity; @@ -158,21 +157,8 @@ public class MortarShellEntity extends ThrowableItemProjectile implements GeoEnt ParticleTool.sendParticle(serverLevel, ParticleTypes.CAMPFIRE_COSY_SMOKE, this.xo, this.yo, this.zo, 1, 0, 0, 0, 0.001, true); - var movement = this.getDeltaMovement(); - var currentX = this.chunkPosition().x; - var currentZ = this.chunkPosition().z; - var nextX = movement.x > 0 ? currentX + 1 : currentX - 1; - var nextZ = movement.z > 0 ? currentZ + 1 : currentZ - 1; - - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, currentX, currentZ, true, false); - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, currentX, nextZ, true, false); - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, nextX, currentZ, true, false); - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, nextX, nextZ, true, false); - - this.loadedChunks.add(ChunkPos.asLong(currentX, currentZ)); - this.loadedChunks.add(ChunkPos.asLong(currentX, nextZ)); - this.loadedChunks.add(ChunkPos.asLong(nextX, currentZ)); - this.loadedChunks.add(ChunkPos.asLong(nextX, nextZ)); + // 更新需要加载的区块 + ChunkLoadTool.updateLoadedChunks(serverLevel, this, this.loadedChunks); } if (this.tickCount > this.life || this.isInWater()) { if (this.level() instanceof ServerLevel) { @@ -199,9 +185,7 @@ public class MortarShellEntity extends ThrowableItemProjectile implements GeoEnt @Override public void onRemovedFromWorld() { if (this.level() instanceof ServerLevel serverLevel) { - for (long chunkPos : this.loadedChunks) { - ForgeChunkManager.forceChunk(serverLevel, ModUtils.MODID, this, ChunkPos.getX(chunkPos), ChunkPos.getZ(chunkPos), false, false); - } + ChunkLoadTool.unloadAllChunks(serverLevel, this, this.loadedChunks); } super.onRemovedFromWorld(); } diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/ChunkLoadTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/ChunkLoadTool.java new file mode 100644 index 000000000..56aee48a5 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/tools/ChunkLoadTool.java @@ -0,0 +1,56 @@ +package com.atsuishio.superbwarfare.tools; + +import com.atsuishio.superbwarfare.ModUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraftforge.common.world.ForgeChunkManager; + +import java.util.HashSet; +import java.util.Set; + +public class ChunkLoadTool { + + /** + * 根据动量计算需要加载的区块并卸载不再需要加载的区块 + */ + public static void updateLoadedChunks(ServerLevel level, Entity entity, Set loadedChunks) { + var x = entity.position().x; + var z = entity.position().z; + var nextX = x + entity.getDeltaMovement().x; + var nextZ = z + entity.getDeltaMovement().z; + + // 加载当前区块和下一tick会进入的区块 + var newChunks = new HashSet(); + newChunks.add(ChunkPos.asLong(new BlockPos((int) x, 0, (int) z))); + newChunks.add(ChunkPos.asLong(new BlockPos((int) nextX, 0, (int) nextZ))); + + // 计算需要更新的区块 + var chunksToLoad = newChunks.stream().filter(chunk -> !loadedChunks.contains(chunk)).toList(); + var chunksToUnload = loadedChunks.stream().filter(chunk -> !newChunks.contains(chunk)).toList(); + + chunksToLoad.forEach(chunk -> { + var chunkPos = new ChunkPos(chunk); + ForgeChunkManager.forceChunk(level, ModUtils.MODID, entity, chunkPos.x, chunkPos.z, true, false); + }); + + chunksToUnload.forEach(chunk -> { + var chunkPos = new ChunkPos(chunk); + ForgeChunkManager.forceChunk(level, ModUtils.MODID, entity, chunkPos.x, chunkPos.z, false, false); + }); + + loadedChunks.clear(); + loadedChunks.addAll(newChunks); + } + + /** + * 卸载所有已加载区块 + */ + public static void unloadAllChunks(ServerLevel level, Entity entity, Set loadedChunks) { + loadedChunks.forEach(chunk -> { + var chunkPos = new ChunkPos(chunk); + ForgeChunkManager.forceChunk(level, ModUtils.MODID, entity, chunkPos.x, chunkPos.z, false, false); + }); + } +}