优化炮弹区块加载

This commit is contained in:
Light_Quanta 2025-01-18 20:41:22 +08:00
parent c5f87bb215
commit c75246dbfc
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
3 changed files with 64 additions and 40 deletions

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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<Long> 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<Long>();
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<Long> loadedChunks) {
loadedChunks.forEach(chunk -> {
var chunkPos = new ChunkPos(chunk);
ForgeChunkManager.forceChunk(level, ModUtils.MODID, entity, chunkPos.x, chunkPos.z, false, false);
});
}
}