mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-21 07:59:19 +00:00
实体剔除前置
This commit is contained in:
@@ -88,7 +88,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
|||||||
this.markVanillaNoteBlocks();
|
this.markVanillaNoteBlocks();
|
||||||
this.findViewBlockingVanillaBlocks();
|
this.findViewBlockingVanillaBlocks();
|
||||||
Arrays.fill(this.immutableBlockStates, EmptyBlock.INSTANCE.defaultState());
|
Arrays.fill(this.immutableBlockStates, EmptyBlock.INSTANCE.defaultState());
|
||||||
this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings); // 一定要预先初始化一次,预防id超出上限
|
this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings, this::isViewBlockingBlock); // 一定要预先初始化一次,预防id超出上限
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BukkitBlockManager instance() {
|
public static BukkitBlockManager instance() {
|
||||||
@@ -128,7 +128,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delayedLoad() {
|
public void delayedLoad() {
|
||||||
this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings); // 重置方块映射表
|
this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings, this::isViewBlockingBlock); // 重置方块映射表
|
||||||
super.delayedLoad();
|
super.delayedLoad();
|
||||||
this.cachedVisualBlockStatePacket = VisualBlockStatePacket.create();
|
this.cachedVisualBlockStatePacket = VisualBlockStatePacket.create();
|
||||||
for (BukkitServerPlayer player : BukkitNetworkManager.instance().onlineUsers()) {
|
for (BukkitServerPlayer player : BukkitNetworkManager.instance().onlineUsers()) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
|||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.event.DataComponentValue;
|
import net.kyori.adventure.text.event.DataComponentValue;
|
||||||
import net.kyori.adventure.text.event.HoverEvent;
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
|
||||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||||
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
|
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
|
||||||
import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent;
|
import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent;
|
||||||
@@ -90,9 +91,12 @@ import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider;
|
|||||||
import net.momirealms.craftengine.core.util.*;
|
import net.momirealms.craftengine.core.util.*;
|
||||||
import net.momirealms.craftengine.core.world.*;
|
import net.momirealms.craftengine.core.world.*;
|
||||||
import net.momirealms.craftengine.core.world.chunk.CEChunk;
|
import net.momirealms.craftengine.core.world.chunk.CEChunk;
|
||||||
import net.momirealms.craftengine.core.world.chunk.ChunkStatus;
|
|
||||||
import net.momirealms.craftengine.core.world.chunk.Palette;
|
import net.momirealms.craftengine.core.world.chunk.Palette;
|
||||||
import net.momirealms.craftengine.core.world.chunk.PalettedContainer;
|
import net.momirealms.craftengine.core.world.chunk.PalettedContainer;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.client.ClientChunk;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.client.ClientSection;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.client.PackedOcclusionStorage;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.client.SingularOcclusionStorage;
|
||||||
import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData;
|
import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData;
|
||||||
import net.momirealms.craftengine.core.world.chunk.packet.MCSection;
|
import net.momirealms.craftengine.core.world.chunk.packet.MCSection;
|
||||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||||
@@ -125,6 +129,7 @@ import java.time.Instant;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class BukkitNetworkManager implements NetworkManager, Listener, PluginMessageListener {
|
public class BukkitNetworkManager implements NetworkManager, Listener, PluginMessageListener {
|
||||||
private static BukkitNetworkManager instance;
|
private static BukkitNetworkManager instance;
|
||||||
@@ -288,7 +293,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerBlockStatePacketListeners(int[] blockStateMappings) {
|
public void registerBlockStatePacketListeners(int[] blockStateMappings, Predicate<Integer> occlusionPredicate) {
|
||||||
int stoneId = BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState);
|
int stoneId = BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState);
|
||||||
int vanillaBlocks = BlockStateUtils.vanillaBlockStateCount();
|
int vanillaBlocks = BlockStateUtils.vanillaBlockStateCount();
|
||||||
int[] newMappings = new int[blockStateMappings.length];
|
int[] newMappings = new int[blockStateMappings.length];
|
||||||
@@ -318,7 +323,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
newMappings,
|
newMappings,
|
||||||
newMappingsMOD,
|
newMappingsMOD,
|
||||||
newMappings.length,
|
newMappings.length,
|
||||||
RegistryUtils.currentBiomeRegistrySize()
|
RegistryUtils.currentBiomeRegistrySize(),
|
||||||
|
occlusionPredicate
|
||||||
), this.packetIds.clientboundLevelChunkWithLightPacket(), "ClientboundLevelChunkWithLightPacket");
|
), this.packetIds.clientboundLevelChunkWithLightPacket(), "ClientboundLevelChunkWithLightPacket");
|
||||||
registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket(), "ClientboundSectionBlocksUpdatePacket");
|
registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket(), "ClientboundSectionBlocksUpdatePacket");
|
||||||
registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket(), "ClientboundBlockUpdatePacket");
|
registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket(), "ClientboundBlockUpdatePacket");
|
||||||
@@ -1433,9 +1439,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
|
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
|
||||||
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
|
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16;
|
player.setClientSideWorld(BukkitAdaptors.adapt(world));
|
||||||
player.setClientSideSectionCount(sectionCount);
|
|
||||||
player.setClientSideDimension(Key.of(location.toString()));
|
|
||||||
} else {
|
} else {
|
||||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist");
|
CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist");
|
||||||
}
|
}
|
||||||
@@ -1463,10 +1467,9 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
|
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
|
||||||
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
|
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16;
|
player.setClientSideWorld(BukkitAdaptors.adapt(world));
|
||||||
player.setClientSideSectionCount(sectionCount);
|
|
||||||
player.setClientSideDimension(Key.of(location.toString()));
|
|
||||||
player.clearTrackedChunks();
|
player.clearTrackedChunks();
|
||||||
|
player.clearTrackedBlockEntities();
|
||||||
} else {
|
} else {
|
||||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist");
|
CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist");
|
||||||
}
|
}
|
||||||
@@ -1979,13 +1982,15 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
private final IntIdentityList biomeList;
|
private final IntIdentityList biomeList;
|
||||||
private final IntIdentityList blockList;
|
private final IntIdentityList blockList;
|
||||||
private final boolean needsDowngrade;
|
private final boolean needsDowngrade;
|
||||||
|
private final Predicate<Integer> occlusionPredicate;
|
||||||
|
|
||||||
public LevelChunkWithLightListener(int[] blockStateMapper, int[] modBlockStateMapper, int blockRegistrySize, int biomeRegistrySize) {
|
public LevelChunkWithLightListener(int[] blockStateMapper, int[] modBlockStateMapper, int blockRegistrySize, int biomeRegistrySize, Predicate<Integer> occlusionPredicate) {
|
||||||
this.blockStateMapper = blockStateMapper;
|
this.blockStateMapper = blockStateMapper;
|
||||||
this.modBlockStateMapper = modBlockStateMapper;
|
this.modBlockStateMapper = modBlockStateMapper;
|
||||||
this.biomeList = new IntIdentityList(biomeRegistrySize);
|
this.biomeList = new IntIdentityList(biomeRegistrySize);
|
||||||
this.blockList = new IntIdentityList(blockRegistrySize);
|
this.blockList = new IntIdentityList(blockRegistrySize);
|
||||||
this.needsDowngrade = MiscUtils.ceilLog2(BlockStateUtils.vanillaBlockStateCount()) != MiscUtils.ceilLog2(blockRegistrySize);
|
this.needsDowngrade = MiscUtils.ceilLog2(BlockStateUtils.vanillaBlockStateCount()) != MiscUtils.ceilLog2(blockRegistrySize);
|
||||||
|
this.occlusionPredicate = occlusionPredicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int remapBlockState(int stateId, boolean enableMod) {
|
public int remapBlockState(int stateId, boolean enableMod) {
|
||||||
@@ -2022,36 +2027,92 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
buf.readBytes(chunkDataBytes);
|
buf.readBytes(chunkDataBytes);
|
||||||
|
|
||||||
// 客户端侧section数量很重要,不能读取此时玩家所在的真实世界,包具有滞后性
|
// 客户端侧section数量很重要,不能读取此时玩家所在的真实世界,包具有滞后性
|
||||||
int count = player.clientSideSectionCount();
|
net.momirealms.craftengine.core.world.World clientSideWorld = player.clientSideWorld();
|
||||||
|
WorldHeight worldHeight = clientSideWorld.worldHeight();
|
||||||
|
int count = worldHeight.getSectionsCount();
|
||||||
MCSection[] sections = new MCSection[count];
|
MCSection[] sections = new MCSection[count];
|
||||||
FriendlyByteBuf chunkDataByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(chunkDataBytes));
|
FriendlyByteBuf chunkDataByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(chunkDataBytes));
|
||||||
|
|
||||||
boolean hasChangedAnyBlock = false;
|
boolean hasChangedAnyBlock = false;
|
||||||
boolean hasGlobalPalette = false;
|
boolean hasGlobalPalette = false;
|
||||||
|
|
||||||
|
// 创建客户端侧世界(只在开启实体情况下创建)
|
||||||
|
ClientSection[] clientSections = Config.enableEntityCulling() ? new ClientSection[count] : null;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList);
|
MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList);
|
||||||
mcSection.readPacket(chunkDataByteBuf);
|
mcSection.readPacket(chunkDataByteBuf);
|
||||||
|
|
||||||
PalettedContainer<Integer> container = mcSection.blockStateContainer();
|
PalettedContainer<Integer> container = mcSection.blockStateContainer();
|
||||||
|
// 重定向生物群系
|
||||||
if (remapBiomes(user, mcSection.biomeContainer())) {
|
if (remapBiomes(user, mcSection.biomeContainer())) {
|
||||||
hasChangedAnyBlock = true;
|
hasChangedAnyBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Palette<Integer> palette = container.data().palette();
|
Palette<Integer> palette = container.data().palette();
|
||||||
if (palette.canRemap()) {
|
if (palette.canRemap()) {
|
||||||
|
|
||||||
|
// 重定向方块
|
||||||
if (palette.remapAndCheck(s -> remapBlockState(s, user.clientModEnabled()))) {
|
if (palette.remapAndCheck(s -> remapBlockState(s, user.clientModEnabled()))) {
|
||||||
hasChangedAnyBlock = true;
|
hasChangedAnyBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理客户端侧哪些方块有阻挡
|
||||||
|
if (clientSections != null) {
|
||||||
|
int size = palette.getSize();
|
||||||
|
// 单个元素的情况下,使用优化的存储方案
|
||||||
|
if (size == 1) {
|
||||||
|
clientSections[i] = new ClientSection(new SingularOcclusionStorage(this.occlusionPredicate.test(palette.get(0))));
|
||||||
} else {
|
} else {
|
||||||
hasGlobalPalette = true;
|
boolean hasOcclusions = false;
|
||||||
|
boolean hasNoOcclusions = false;
|
||||||
|
for (int h = 0; h < size; h++) {
|
||||||
|
int entry = palette.get(h);
|
||||||
|
if (this.occlusionPredicate.test(entry)) {
|
||||||
|
hasOcclusions = true;
|
||||||
|
} else {
|
||||||
|
hasNoOcclusions = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 两种情况都有,那么需要一个个遍历处理视线遮挡数据
|
||||||
|
if (hasOcclusions && hasNoOcclusions) {
|
||||||
|
PackedOcclusionStorage storage = new PackedOcclusionStorage(false);
|
||||||
for (int j = 0; j < 4096; j++) {
|
for (int j = 0; j < 4096; j++) {
|
||||||
int state = container.get(j);
|
int state = container.get(j);
|
||||||
|
storage.set(j, this.occlusionPredicate.test(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 全遮蔽或全透视则使用优化存储方案
|
||||||
|
else {
|
||||||
|
clientSections[i] = new ClientSection(new SingularOcclusionStorage(hasOcclusions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hasGlobalPalette = true;
|
||||||
|
|
||||||
|
PackedOcclusionStorage storage = null;
|
||||||
|
if (clientSections != null) {
|
||||||
|
storage = new PackedOcclusionStorage(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < 4096; j++) {
|
||||||
|
int state = container.get(j);
|
||||||
|
|
||||||
|
// 重定向方块
|
||||||
int newState = remapBlockState(state, user.clientModEnabled());
|
int newState = remapBlockState(state, user.clientModEnabled());
|
||||||
if (newState != state) {
|
if (newState != state) {
|
||||||
container.set(j, newState);
|
container.set(j, newState);
|
||||||
hasChangedAnyBlock = true;
|
hasChangedAnyBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 写入视线遮挡数据
|
||||||
|
if (storage != null) {
|
||||||
|
storage.set(j, this.occlusionPredicate.test(state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sections[i] = mcSection;
|
sections[i] = mcSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2116,16 +2177,20 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 记录加载的区块
|
// 记录加载的区块
|
||||||
player.addTrackedChunk(chunkPos.longKey, new ChunkStatus());
|
player.addTrackedChunk(chunkPos.longKey, new ClientChunk(clientSections, worldHeight));
|
||||||
|
|
||||||
// 生成方块实体
|
// 生成方块实体
|
||||||
CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid());
|
CEWorld ceWorld = clientSideWorld.storageWorld();
|
||||||
|
// 世界可能被卸载,因为包滞后
|
||||||
|
if (ceWorld != null) {
|
||||||
CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos.longKey);
|
CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos.longKey);
|
||||||
if (ceChunk != null) {
|
if (ceChunk != null) {
|
||||||
|
// 生成方块实体
|
||||||
ceChunk.spawnBlockEntities(player);
|
ceChunk.spawnBlockEntities(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class SectionBlockUpdateListener implements ByteBufferPacketListener {
|
public static class SectionBlockUpdateListener implements ByteBufferPacketListener {
|
||||||
private final int[] blockStateMapper;
|
private final int[] blockStateMapper;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import net.momirealms.craftengine.core.advancement.AdvancementType;
|
|||||||
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
||||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||||
|
import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer;
|
||||||
import net.momirealms.craftengine.core.entity.data.EntityData;
|
import net.momirealms.craftengine.core.entity.data.EntityData;
|
||||||
import net.momirealms.craftengine.core.entity.player.GameMode;
|
import net.momirealms.craftengine.core.entity.player.GameMode;
|
||||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||||
@@ -39,7 +40,8 @@ import net.momirealms.craftengine.core.sound.SoundSource;
|
|||||||
import net.momirealms.craftengine.core.util.*;
|
import net.momirealms.craftengine.core.util.*;
|
||||||
import net.momirealms.craftengine.core.world.*;
|
import net.momirealms.craftengine.core.world.*;
|
||||||
import net.momirealms.craftengine.core.world.World;
|
import net.momirealms.craftengine.core.world.World;
|
||||||
import net.momirealms.craftengine.core.world.chunk.ChunkStatus;
|
import net.momirealms.craftengine.core.world.chunk.client.ClientChunk;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.client.VirtualCullableObject;
|
||||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.attribute.Attribute;
|
import org.bukkit.attribute.Attribute;
|
||||||
@@ -85,8 +87,7 @@ public class BukkitServerPlayer extends Player {
|
|||||||
private Reference<org.bukkit.entity.Player> playerRef;
|
private Reference<org.bukkit.entity.Player> playerRef;
|
||||||
private Reference<Object> serverPlayerRef;
|
private Reference<Object> serverPlayerRef;
|
||||||
// client side dimension info
|
// client side dimension info
|
||||||
private int sectionCount;
|
private World clientSideWorld;
|
||||||
private Key clientSideDimension;
|
|
||||||
// check main hand/offhand interaction
|
// check main hand/offhand interaction
|
||||||
private int lastSuccessfulInteraction;
|
private int lastSuccessfulInteraction;
|
||||||
// to prevent duplicated events
|
// to prevent duplicated events
|
||||||
@@ -124,7 +125,7 @@ public class BukkitServerPlayer extends Player {
|
|||||||
// cooldown data
|
// cooldown data
|
||||||
private CooldownData cooldownData;
|
private CooldownData cooldownData;
|
||||||
// tracked chunks
|
// tracked chunks
|
||||||
private ConcurrentLong2ReferenceChainedHashTable<ChunkStatus> trackedChunks;
|
private ConcurrentLong2ReferenceChainedHashTable<ClientChunk> trackedChunks;
|
||||||
// entity view
|
// entity view
|
||||||
private Map<Integer, EntityPacketHandler> entityTypeView;
|
private Map<Integer, EntityPacketHandler> entityTypeView;
|
||||||
// 通过指令或api设定的语言
|
// 通过指令或api设定的语言
|
||||||
@@ -138,6 +139,8 @@ public class BukkitServerPlayer extends Player {
|
|||||||
private boolean isHackedBreak;
|
private boolean isHackedBreak;
|
||||||
// 上一次停止挖掘包发出的时间
|
// 上一次停止挖掘包发出的时间
|
||||||
private int lastStopMiningTick;
|
private int lastStopMiningTick;
|
||||||
|
// 跟踪到的方块实体渲染器
|
||||||
|
private final Map<BlockPos, VirtualCullableObject> trackedBlockEntityRenderers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public BukkitServerPlayer(BukkitCraftEngine plugin, @Nullable Channel channel) {
|
public BukkitServerPlayer(BukkitCraftEngine plugin, @Nullable Channel channel) {
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
@@ -477,21 +480,13 @@ public class BukkitServerPlayer extends Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int clientSideSectionCount() {
|
public World clientSideWorld() {
|
||||||
return sectionCount;
|
return this.clientSideWorld;
|
||||||
}
|
|
||||||
|
|
||||||
public void setClientSideSectionCount(int sectionCount) {
|
|
||||||
this.sectionCount = sectionCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Key clientSideDimension() {
|
public void setClientSideWorld(World world) {
|
||||||
return clientSideDimension;
|
this.clientSideWorld = world;
|
||||||
}
|
|
||||||
|
|
||||||
public void setClientSideDimension(Key clientSideDimension) {
|
|
||||||
this.clientSideDimension = clientSideDimension;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConnectionState(ConnectionState connectionState) {
|
public void setConnectionState(ConnectionState connectionState) {
|
||||||
@@ -1180,12 +1175,12 @@ public class BukkitServerPlayer extends Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChunkStatus getTrackedChunk(long chunkPos) {
|
public ClientChunk getTrackedChunk(long chunkPos) {
|
||||||
return this.trackedChunks.get(chunkPos);
|
return this.trackedChunks.get(chunkPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTrackedChunk(long chunkPos, ChunkStatus chunkStatus) {
|
public void addTrackedChunk(long chunkPos, ClientChunk chunkStatus) {
|
||||||
this.trackedChunks.put(chunkPos, chunkStatus);
|
this.trackedChunks.put(chunkPos, chunkStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1300,4 +1295,26 @@ public class BukkitServerPlayer extends Player {
|
|||||||
public void sendTotemAnimation(Item<?> totem, @Nullable SoundData sound, boolean silent) {
|
public void sendTotemAnimation(Item<?> totem, @Nullable SoundData sound, boolean silent) {
|
||||||
PlayerUtils.sendTotemAnimation(this, totem, sound, silent);
|
PlayerUtils.sendTotemAnimation(this, totem, sound, silent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTrackedBlockEntities(Map<BlockPos, ConstantBlockEntityRenderer> renders) {
|
||||||
|
for (Map.Entry<BlockPos, ConstantBlockEntityRenderer> entry : renders.entrySet()) {
|
||||||
|
this.trackedBlockEntityRenderers.put(entry.getKey(), new VirtualCullableObject(entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeTrackedBlockEntities(Collection<BlockPos> renders) {
|
||||||
|
for (BlockPos render : renders) {
|
||||||
|
VirtualCullableObject remove = this.trackedBlockEntityRenderers.remove(render);
|
||||||
|
if (remove != null && remove.isShown()) {
|
||||||
|
remove.cullable().hide(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearTrackedBlockEntities() {
|
||||||
|
this.trackedBlockEntityRenderers.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class BukkitWorld implements World {
|
public class BukkitWorld implements World {
|
||||||
private final WeakReference<org.bukkit.World> world;
|
private final WeakReference<org.bukkit.World> world;
|
||||||
|
|||||||
@@ -552,11 +552,10 @@ chunk-system:
|
|||||||
remove: []
|
remove: []
|
||||||
convert: {}
|
convert: {}
|
||||||
|
|
||||||
#client-optimization:
|
client-optimization:
|
||||||
# # Using server-side ray tracing algorithms to hide certain entities and reduce client-side rendering pressure.
|
# Using server-side ray tracing algorithms to hide certain entities and reduce client-side rendering pressure.
|
||||||
# entity-culling:
|
entity-culling:
|
||||||
# enable: false
|
enable: false
|
||||||
# whitelist-entities: []
|
|
||||||
|
|
||||||
# Enables or disables debug mode
|
# Enables or disables debug mode
|
||||||
debug:
|
debug:
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ warning.config.type.quaternionf: "<yellow>Issue found in file <arg:0> - Failed t
|
|||||||
warning.config.type.vector3f: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to Vector3f type for option '<arg:3>'.</yellow>"
|
warning.config.type.vector3f: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to Vector3f type for option '<arg:3>'.</yellow>"
|
||||||
warning.config.type.vec3d: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to Vec3d type for option '<arg:3>'.</yellow>"
|
warning.config.type.vec3d: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to Vec3d type for option '<arg:3>'.</yellow>"
|
||||||
warning.config.type.map: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to Map type for option '<arg:3>'.</yellow>"
|
warning.config.type.map: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to Map type for option '<arg:3>'.</yellow>"
|
||||||
|
warning.config.type.aabb: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to AABB type for option '<arg:3>'.</yellow>"
|
||||||
warning.config.type.snbt.invalid_syntax: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Invalid snbt syntax '<arg:2>'.</yellow>"
|
warning.config.type.snbt.invalid_syntax: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Invalid snbt syntax '<arg:2>'.</yellow>"
|
||||||
warning.config.number.missing_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'type' argument for number argument.</yellow>"
|
warning.config.number.missing_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'type' argument for number argument.</yellow>"
|
||||||
warning.config.number.invalid_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid number argument type '<arg:2>'.</yellow>"
|
warning.config.number.invalid_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid number argument type '<arg:2>'.</yellow>"
|
||||||
|
|||||||
@@ -600,7 +600,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
|||||||
this.arrangeModelForStateAndVerify(visualBlockState, parseBlockModel(modelConfig));
|
this.arrangeModelForStateAndVerify(visualBlockState, parseBlockModel(modelConfig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BlockStateAppearance blockStateAppearance = new BlockStateAppearance(visualBlockState, parseBlockEntityRender(appearanceSection.get("entity-renderer")));
|
BlockStateAppearance blockStateAppearance = new BlockStateAppearance(
|
||||||
|
visualBlockState,
|
||||||
|
parseBlockEntityRender(appearanceSection.get("entity-renderer")),
|
||||||
|
ResourceConfigUtils.getAsAABB(appearanceSection.getOrDefault("aabb", 1), "aabb")
|
||||||
|
);
|
||||||
appearances.put(appearanceName, blockStateAppearance);
|
appearances.put(appearanceName, blockStateAppearance);
|
||||||
if (anyAppearance == null) {
|
if (anyAppearance == null) {
|
||||||
anyAppearance = blockStateAppearance;
|
anyAppearance = blockStateAppearance;
|
||||||
@@ -639,6 +643,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
|||||||
}
|
}
|
||||||
for (ImmutableBlockState possibleState : possibleStates) {
|
for (ImmutableBlockState possibleState : possibleStates) {
|
||||||
possibleState.setVisualBlockState(appearance.blockState());
|
possibleState.setVisualBlockState(appearance.blockState());
|
||||||
|
possibleState.setEstimatedBoundingBox(appearance.estimateAABB());
|
||||||
appearance.blockEntityRenderer().ifPresent(possibleState::setConstantRenderers);
|
appearance.blockEntityRenderer().ifPresent(possibleState::setConstantRenderers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -662,6 +667,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
|||||||
if (visualState == null) {
|
if (visualState == null) {
|
||||||
visualState = anyAppearance.blockState();
|
visualState = anyAppearance.blockState();
|
||||||
state.setVisualBlockState(visualState);
|
state.setVisualBlockState(visualState);
|
||||||
|
state.setEstimatedBoundingBox(anyAppearance.estimateAABB());
|
||||||
anyAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers);
|
anyAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers);
|
||||||
}
|
}
|
||||||
int appearanceId = visualState.registryId();
|
int appearanceId = visualState.registryId();
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ package net.momirealms.craftengine.core.block;
|
|||||||
|
|
||||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
|
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
|
||||||
|
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public record BlockStateAppearance(BlockStateWrapper blockState, Optional<BlockEntityElementConfig<? extends BlockEntityElement>[]> blockEntityRenderer) {
|
public record BlockStateAppearance(BlockStateWrapper blockState,
|
||||||
|
Optional<BlockEntityElementConfig<? extends BlockEntityElement>[]> blockEntityRenderer,
|
||||||
|
AABB estimateAABB) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import net.momirealms.craftengine.core.registry.Holder;
|
|||||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||||
import net.momirealms.craftengine.core.world.CEWorld;
|
import net.momirealms.craftengine.core.world.CEWorld;
|
||||||
import net.momirealms.craftengine.core.world.World;
|
import net.momirealms.craftengine.core.world.World;
|
||||||
|
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||||
import net.momirealms.sparrow.nbt.NBT;
|
import net.momirealms.sparrow.nbt.NBT;
|
||||||
import net.momirealms.sparrow.nbt.Tag;
|
import net.momirealms.sparrow.nbt.Tag;
|
||||||
@@ -42,6 +43,7 @@ public final class ImmutableBlockState {
|
|||||||
private BlockEntityType<? extends BlockEntity> blockEntityType;
|
private BlockEntityType<? extends BlockEntity> blockEntityType;
|
||||||
@Nullable
|
@Nullable
|
||||||
private BlockEntityElementConfig<? extends BlockEntityElement>[] renderers;
|
private BlockEntityElementConfig<? extends BlockEntityElement>[] renderers;
|
||||||
|
private AABB estimatedBoundingBox;
|
||||||
|
|
||||||
ImmutableBlockState(
|
ImmutableBlockState(
|
||||||
Holder.Reference<CustomBlock> owner,
|
Holder.Reference<CustomBlock> owner,
|
||||||
@@ -87,6 +89,14 @@ public final class ImmutableBlockState {
|
|||||||
this.renderers = renderers;
|
this.renderers = renderers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEstimatedBoundingBox(AABB aabb) {
|
||||||
|
this.estimatedBoundingBox = aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB estimatedBoundingBox() {
|
||||||
|
return estimatedBoundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasBlockEntity() {
|
public boolean hasBlockEntity() {
|
||||||
return this.blockEntityType != null;
|
return this.blockEntityType != null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,18 @@ package net.momirealms.craftengine.core.block.entity.render;
|
|||||||
|
|
||||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||||
import net.momirealms.craftengine.core.entity.player.Player;
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.world.Cullable;
|
||||||
|
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
@ApiStatus.Experimental
|
@ApiStatus.Experimental
|
||||||
public class ConstantBlockEntityRenderer {
|
public class ConstantBlockEntityRenderer implements Cullable {
|
||||||
private final BlockEntityElement[] elements;
|
private final BlockEntityElement[] elements;
|
||||||
|
public final AABB aabb;
|
||||||
|
|
||||||
public ConstantBlockEntityRenderer(BlockEntityElement[] elements) {
|
public ConstantBlockEntityRenderer(BlockEntityElement[] elements, AABB aabb) {
|
||||||
this.elements = elements;
|
this.elements = elements;
|
||||||
|
this.aabb = aabb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void show(Player player) {
|
public void show(Player player) {
|
||||||
@@ -47,4 +51,9 @@ public class ConstantBlockEntityRenderer {
|
|||||||
public BlockEntityElement[] elements() {
|
public BlockEntityElement[] elements() {
|
||||||
return this.elements;
|
return this.elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AABB aabb() {
|
||||||
|
return this.aabb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.entity.player;
|
|||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.momirealms.craftengine.core.advancement.AdvancementType;
|
import net.momirealms.craftengine.core.advancement.AdvancementType;
|
||||||
|
import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer;
|
||||||
import net.momirealms.craftengine.core.entity.AbstractEntity;
|
import net.momirealms.craftengine.core.entity.AbstractEntity;
|
||||||
import net.momirealms.craftengine.core.item.Item;
|
import net.momirealms.craftengine.core.item.Item;
|
||||||
import net.momirealms.craftengine.core.plugin.context.CooldownData;
|
import net.momirealms.craftengine.core.plugin.context.CooldownData;
|
||||||
@@ -9,14 +10,13 @@ import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
|||||||
import net.momirealms.craftengine.core.sound.SoundData;
|
import net.momirealms.craftengine.core.sound.SoundData;
|
||||||
import net.momirealms.craftengine.core.sound.SoundSource;
|
import net.momirealms.craftengine.core.sound.SoundSource;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
import net.momirealms.craftengine.core.world.BlockPos;
|
import net.momirealms.craftengine.core.world.*;
|
||||||
import net.momirealms.craftengine.core.world.Position;
|
|
||||||
import net.momirealms.craftengine.core.world.Vec3d;
|
|
||||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class Player extends AbstractEntity implements NetWorkUser {
|
public abstract class Player extends AbstractEntity implements NetWorkUser {
|
||||||
private static final Key TYPE = Key.of("minecraft:player");
|
private static final Key TYPE = Key.of("minecraft:player");
|
||||||
@@ -35,6 +35,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
|
|||||||
@Override
|
@Override
|
||||||
public abstract Object serverPlayer();
|
public abstract Object serverPlayer();
|
||||||
|
|
||||||
|
public abstract void setClientSideWorld(World world);
|
||||||
|
|
||||||
public abstract float getDestroyProgress(Object blockState, BlockPos pos);
|
public abstract float getDestroyProgress(Object blockState, BlockPos pos);
|
||||||
|
|
||||||
public abstract void setClientSideCanBreakBlock(boolean canBreak);
|
public abstract void setClientSideCanBreakBlock(boolean canBreak);
|
||||||
@@ -198,6 +200,12 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
|
|||||||
|
|
||||||
public abstract void sendTotemAnimation(Item<?> totem, @Nullable SoundData sound, boolean silent);
|
public abstract void sendTotemAnimation(Item<?> totem, @Nullable SoundData sound, boolean silent);
|
||||||
|
|
||||||
|
public abstract void addTrackedBlockEntities(Map<BlockPos, ConstantBlockEntityRenderer> renders);
|
||||||
|
|
||||||
|
public abstract void removeTrackedBlockEntities(Collection<BlockPos> renders);
|
||||||
|
|
||||||
|
public abstract void clearTrackedBlockEntities();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public void remove() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import net.momirealms.craftengine.core.plugin.compatibility.CompatibilityManager
|
|||||||
import net.momirealms.craftengine.core.plugin.compatibility.PluginTaskRegistry;
|
import net.momirealms.craftengine.core.plugin.compatibility.PluginTaskRegistry;
|
||||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||||
import net.momirealms.craftengine.core.plugin.config.template.TemplateManager;
|
import net.momirealms.craftengine.core.plugin.config.template.TemplateManager;
|
||||||
import net.momirealms.craftengine.core.plugin.config.template.TemplateManagerImpl;
|
|
||||||
import net.momirealms.craftengine.core.plugin.context.GlobalVariableManager;
|
import net.momirealms.craftengine.core.plugin.context.GlobalVariableManager;
|
||||||
import net.momirealms.craftengine.core.plugin.dependency.Dependencies;
|
import net.momirealms.craftengine.core.plugin.dependency.Dependencies;
|
||||||
import net.momirealms.craftengine.core.plugin.dependency.Dependency;
|
import net.momirealms.craftengine.core.plugin.dependency.Dependency;
|
||||||
|
|||||||
@@ -203,6 +203,8 @@ public class Config {
|
|||||||
protected boolean emoji$contexts$sign;
|
protected boolean emoji$contexts$sign;
|
||||||
protected int emoji$max_emojis_per_parse;
|
protected int emoji$max_emojis_per_parse;
|
||||||
|
|
||||||
|
protected boolean client_optimization$entity_culling$enable;
|
||||||
|
|
||||||
public Config(CraftEngine plugin) {
|
public Config(CraftEngine plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.configVersion = PluginProperties.getValue("config");
|
this.configVersion = PluginProperties.getValue("config");
|
||||||
@@ -562,6 +564,9 @@ public class Config {
|
|||||||
emoji$contexts$sign = config.getBoolean("emoji.contexts.sign", true);
|
emoji$contexts$sign = config.getBoolean("emoji.contexts.sign", true);
|
||||||
emoji$max_emojis_per_parse = config.getInt("emoji.max-emojis-per-parse", 32);
|
emoji$max_emojis_per_parse = config.getInt("emoji.max-emojis-per-parse", 32);
|
||||||
|
|
||||||
|
// client optimization
|
||||||
|
client_optimization$entity_culling$enable = config.getBoolean("client-optimization.entity-culling.enable", false);
|
||||||
|
|
||||||
firstTime = false;
|
firstTime = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,6 +1157,10 @@ public class Config {
|
|||||||
return instance.resource_pack$optimization$texture$zopfli_iterations;
|
return instance.resource_pack$optimization$texture$zopfli_iterations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean enableEntityCulling() {
|
||||||
|
return instance.client_optimization$entity_culling$enable;
|
||||||
|
}
|
||||||
|
|
||||||
public YamlDocument loadOrCreateYamlData(String fileName) {
|
public YamlDocument loadOrCreateYamlData(String fileName) {
|
||||||
Path path = this.plugin.dataFolderPath().resolve(fileName);
|
Path path = this.plugin.dataFolderPath().resolve(fileName);
|
||||||
if (!Files.exists(path)) {
|
if (!Files.exists(path)) {
|
||||||
|
|||||||
@@ -2,14 +2,7 @@ package net.momirealms.craftengine.core.plugin.config.template;
|
|||||||
|
|
||||||
import net.momirealms.craftengine.core.plugin.Manageable;
|
import net.momirealms.craftengine.core.plugin.Manageable;
|
||||||
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
|
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
|
||||||
import net.momirealms.craftengine.core.plugin.config.template.argument.TemplateArgument;
|
|
||||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
import net.momirealms.craftengine.core.util.SNBTReader;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface TemplateManager extends Manageable {
|
public interface TemplateManager extends Manageable {
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin.config.template.argument;
|
|||||||
import com.ezylang.evalex.Expression;
|
import com.ezylang.evalex.Expression;
|
||||||
import com.ezylang.evalex.data.EvaluationValue;
|
import com.ezylang.evalex.data.EvaluationValue;
|
||||||
import net.momirealms.craftengine.core.plugin.config.template.ArgumentString;
|
import net.momirealms.craftengine.core.plugin.config.template.ArgumentString;
|
||||||
import net.momirealms.craftengine.core.plugin.config.template.TemplateManager;
|
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import net.kyori.adventure.text.Component;
|
|||||||
import net.momirealms.craftengine.core.plugin.Plugin;
|
import net.momirealms.craftengine.core.plugin.Plugin;
|
||||||
import net.momirealms.craftengine.core.util.IntIdentityList;
|
import net.momirealms.craftengine.core.util.IntIdentityList;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
import net.momirealms.craftengine.core.world.chunk.ChunkStatus;
|
import net.momirealms.craftengine.core.world.World;
|
||||||
|
import net.momirealms.craftengine.core.world.chunk.client.ClientChunk;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -65,9 +66,7 @@ public interface NetWorkUser {
|
|||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
ConnectionState encoderState();
|
ConnectionState encoderState();
|
||||||
|
|
||||||
int clientSideSectionCount();
|
World clientSideWorld();
|
||||||
|
|
||||||
Key clientSideDimension();
|
|
||||||
|
|
||||||
Object serverPlayer();
|
Object serverPlayer();
|
||||||
|
|
||||||
@@ -89,9 +88,9 @@ public interface NetWorkUser {
|
|||||||
|
|
||||||
boolean isChunkTracked(long chunkPos);
|
boolean isChunkTracked(long chunkPos);
|
||||||
|
|
||||||
ChunkStatus getTrackedChunk(long chunkPos);
|
ClientChunk getTrackedChunk(long chunkPos);
|
||||||
|
|
||||||
void addTrackedChunk(long chunkPos, ChunkStatus chunkStatus);
|
void addTrackedChunk(long chunkPos, ClientChunk chunkStatus);
|
||||||
|
|
||||||
void clearTrackedChunks();
|
void clearTrackedChunks();
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
|
|||||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||||
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
|
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
|
||||||
import net.momirealms.craftengine.core.world.Vec3d;
|
import net.momirealms.craftengine.core.world.Vec3d;
|
||||||
|
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.joml.Quaternionf;
|
import org.joml.Quaternionf;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
@@ -341,4 +342,52 @@ public final class ResourceConfigUtils {
|
|||||||
}
|
}
|
||||||
TranslationManager.instance().log(e.node(), e.arguments());
|
TranslationManager.instance().log(e.node(), e.arguments());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AABB getAsAABB(Object o, String option) {
|
||||||
|
if (o == null) {
|
||||||
|
throw new LocalizedResourceConfigException("warning.config.type.aabb", "null", option);
|
||||||
|
}
|
||||||
|
if (o instanceof Number number) {
|
||||||
|
double min = -(number.doubleValue() / 2);
|
||||||
|
double max = number.doubleValue() / 2;
|
||||||
|
return new AABB(min, min, min, max, max, max);
|
||||||
|
} else {
|
||||||
|
double[] args;
|
||||||
|
if (o instanceof List<?> list) {
|
||||||
|
args = new double[list.size()];
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
if (list.get(i) instanceof Number number) {
|
||||||
|
args[i] = number.doubleValue();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
args[i] = Double.parseDouble(list.get(i).toString());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new LocalizedResourceConfigException("warning.config.type.aabb", o.toString(), option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String[] split = o.toString().split(",");
|
||||||
|
args = new double[split.length];
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
try {
|
||||||
|
args[i] = Double.parseDouble(split[i]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new LocalizedResourceConfigException("warning.config.type.aabb", o.toString(), option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (args.length == 1) {
|
||||||
|
return new AABB(-args[0]/2, -args[0]/2, -args[0]/2, args[0]/2, args[0]/2, args[0]/2);
|
||||||
|
} else if (args.length == 2) {
|
||||||
|
return new AABB(-args[0]/2, -args[1]/2, -args[0]/2, args[0]/2, args[1]/2, args[0]/2);
|
||||||
|
} else if (args.length == 3) {
|
||||||
|
return new AABB(-args[0]/2, -args[1]/2, -args[2]/2, args[0]/2, args[1]/2, args[2]/2);
|
||||||
|
} else if (args.length == 6) {
|
||||||
|
return new AABB(args[0], args[1], args[2], args[3], args[4], args[5]);
|
||||||
|
} else {
|
||||||
|
throw new LocalizedResourceConfigException("warning.config.type.aabb", o.toString(), option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package net.momirealms.craftengine.core.world;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||||
|
|
||||||
|
public interface Cullable {
|
||||||
|
|
||||||
|
AABB aabb();
|
||||||
|
|
||||||
|
void show(Player player);
|
||||||
|
|
||||||
|
void hide(Player player);
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@ import net.momirealms.craftengine.core.util.Direction;
|
|||||||
|
|
||||||
public class Vec3i implements Comparable<Vec3i> {
|
public class Vec3i implements Comparable<Vec3i> {
|
||||||
public static final Vec3i ZERO = new Vec3i(0, 0, 0);
|
public static final Vec3i ZERO = new Vec3i(0, 0, 0);
|
||||||
protected int x;
|
public final int x;
|
||||||
protected int y;
|
public final int y;
|
||||||
protected int z;
|
public final int z;
|
||||||
|
|
||||||
public Vec3i(int x, int y, int z) {
|
public Vec3i(int x, int y, int z) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
@@ -30,21 +30,6 @@ public class Vec3i implements Comparable<Vec3i> {
|
|||||||
return x == 0 && y == 0 && z == 0 ? this : new Vec3i(this.x() + x, this.y() + y, this.z() + z);
|
return x == 0 && y == 0 && z == 0 ? this : new Vec3i(this.x() + x, this.y() + y, this.z() + z);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Vec3i setX(int x) {
|
|
||||||
this.x = x;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vec3i setY(int y) {
|
|
||||||
this.y = y;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vec3i setZ(int z) {
|
|
||||||
this.z = z;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object object) {
|
public boolean equals(Object object) {
|
||||||
return this == object || object instanceof Vec3i vec3i && this.x == vec3i.x && this.y == vec3i.y && this.z == vec3i.z;
|
return this == object || object instanceof Vec3i vec3i && this.x == vec3i.x && this.y == vec3i.y && this.z == vec3i.z;
|
||||||
|
|||||||
@@ -77,15 +77,24 @@ public class ArrayPalette<T> implements Palette<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasAny(Predicate<T> predicate) {
|
public boolean hasAny(Predicate<T> predicate) {
|
||||||
for(int i = 0; i < this.size; ++i) {
|
for (int i = 0; i < this.size; ++i) {
|
||||||
if (predicate.test(this.array[i])) {
|
if (predicate.test(this.array[i])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allMatch(Predicate<T> predicate) {
|
||||||
|
for (int i = 0; i < this.size; ++i) {
|
||||||
|
if (!predicate.test(this.array[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get(int id) {
|
public T get(int id) {
|
||||||
if (id >= 0 && id < this.size) {
|
if (id >= 0 && id < this.size) {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public class BiMapPalette<T> implements Palette<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasAny(Predicate<T> predicate) {
|
public boolean hasAny(Predicate<T> predicate) {
|
||||||
for(int i = 0; i < this.getSize(); ++i) {
|
for (int i = 0; i < this.getSize(); ++i) {
|
||||||
if (predicate.test(this.map.get(i))) {
|
if (predicate.test(this.map.get(i))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -75,6 +75,16 @@ public class BiMapPalette<T> implements Palette<T> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allMatch(Predicate<T> predicate) {
|
||||||
|
for (int i = 0; i < this.getSize(); ++i) {
|
||||||
|
if (!predicate.test(this.map.get(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get(int id) {
|
public T get(int id) {
|
||||||
T object = this.map.get(id);
|
T object = this.map.get(id);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityEl
|
|||||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
|
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
|
||||||
import net.momirealms.craftengine.core.block.entity.tick.*;
|
import net.momirealms.craftengine.core.block.entity.tick.*;
|
||||||
import net.momirealms.craftengine.core.entity.player.Player;
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||||
import net.momirealms.craftengine.core.world.*;
|
import net.momirealms.craftengine.core.world.*;
|
||||||
import net.momirealms.craftengine.core.world.chunk.serialization.DefaultBlockEntityRendererSerializer;
|
import net.momirealms.craftengine.core.world.chunk.serialization.DefaultBlockEntityRendererSerializer;
|
||||||
@@ -91,9 +92,13 @@ public class CEChunk {
|
|||||||
public void spawnBlockEntities(Player player) {
|
public void spawnBlockEntities(Player player) {
|
||||||
try {
|
try {
|
||||||
this.renderLock.readLock().lock();
|
this.renderLock.readLock().lock();
|
||||||
|
if (Config.enableEntityCulling()) {
|
||||||
|
player.addTrackedBlockEntities(this.constantBlockEntityRenderers);
|
||||||
|
} else {
|
||||||
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
|
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
|
||||||
renderer.show(player);
|
renderer.show(player);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for (DynamicBlockEntityRenderer renderer : this.dynamicBlockEntityRenderers.values()) {
|
for (DynamicBlockEntityRenderer renderer : this.dynamicBlockEntityRenderers.values()) {
|
||||||
renderer.show(player);
|
renderer.show(player);
|
||||||
}
|
}
|
||||||
@@ -105,9 +110,13 @@ public class CEChunk {
|
|||||||
public void despawnBlockEntities(Player player) {
|
public void despawnBlockEntities(Player player) {
|
||||||
try {
|
try {
|
||||||
this.renderLock.readLock().lock();
|
this.renderLock.readLock().lock();
|
||||||
|
if (Config.enableEntityCulling()) {
|
||||||
|
player.removeTrackedBlockEntities(this.constantBlockEntityRenderers.keySet());
|
||||||
|
} else {
|
||||||
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
|
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
|
||||||
renderer.hide(player);
|
renderer.hide(player);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for (DynamicBlockEntityRenderer renderer : this.dynamicBlockEntityRenderers.values()) {
|
for (DynamicBlockEntityRenderer renderer : this.dynamicBlockEntityRenderers.values()) {
|
||||||
renderer.hide(player);
|
renderer.hide(player);
|
||||||
}
|
}
|
||||||
@@ -129,7 +138,7 @@ public class CEChunk {
|
|||||||
BlockEntityElementConfig<? extends BlockEntityElement>[] renderers = state.constantRenderers();
|
BlockEntityElementConfig<? extends BlockEntityElement>[] renderers = state.constantRenderers();
|
||||||
if (renderers != null && renderers.length > 0) {
|
if (renderers != null && renderers.length > 0) {
|
||||||
BlockEntityElement[] elements = new BlockEntityElement[renderers.length];
|
BlockEntityElement[] elements = new BlockEntityElement[renderers.length];
|
||||||
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements);
|
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements, state.estimatedBoundingBox().move(pos));
|
||||||
World wrappedWorld = this.world.world();
|
World wrappedWorld = this.world.world();
|
||||||
List<Player> trackedBy = getTrackedBy();
|
List<Player> trackedBy = getTrackedBy();
|
||||||
boolean hasTrackedBy = trackedBy != null && !trackedBy.isEmpty();
|
boolean hasTrackedBy = trackedBy != null && !trackedBy.isEmpty();
|
||||||
@@ -439,7 +448,7 @@ public class CEChunk {
|
|||||||
return Collections.unmodifiableCollection(this.blockEntities.values());
|
return Collections.unmodifiableCollection(this.blockEntities.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BlockPos> constantBlockEntityRenderers() {
|
public List<BlockPos> constantBlockEntityRendererPositions() {
|
||||||
try {
|
try {
|
||||||
this.renderLock.readLock().lock();
|
this.renderLock.readLock().lock();
|
||||||
return new ArrayList<>(this.constantBlockEntityRenderers.keySet());
|
return new ArrayList<>(this.constantBlockEntityRenderers.keySet());
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package net.momirealms.craftengine.core.world.chunk;
|
|
||||||
|
|
||||||
public class ChunkStatus {
|
|
||||||
|
|
||||||
public ChunkStatus() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,11 @@ public class IdListPalette<T> implements Palette<T> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allMatch(Predicate<T> predicate) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get(int id) {
|
public T get(int id) {
|
||||||
T object = this.idList.get(id);
|
T object = this.idList.get(id);
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ public interface Palette<T> {
|
|||||||
|
|
||||||
boolean hasAny(Predicate<T> predicate);
|
boolean hasAny(Predicate<T> predicate);
|
||||||
|
|
||||||
|
boolean allMatch(Predicate<T> predicate);
|
||||||
|
|
||||||
T get(int id);
|
T get(int id);
|
||||||
|
|
||||||
int getSize();
|
int getSize();
|
||||||
|
|||||||
@@ -45,6 +45,15 @@ public class SingularPalette<T> implements Palette<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allMatch(Predicate<T> predicate) {
|
||||||
|
if (this.entry == null) {
|
||||||
|
throw new IllegalStateException("Use of an uninitialized palette");
|
||||||
|
} else {
|
||||||
|
return predicate.test(this.entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get(int id) {
|
public T get(int id) {
|
||||||
if (this.entry != null && id == 0) {
|
if (this.entry != null && id == 0) {
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package net.momirealms.craftengine.core.world.chunk.client;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.world.SectionPos;
|
||||||
|
import net.momirealms.craftengine.core.world.WorldHeight;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class ClientChunk {
|
||||||
|
@Nullable
|
||||||
|
public final ClientSection[] sections;
|
||||||
|
private final WorldHeight worldHeight;
|
||||||
|
|
||||||
|
public ClientChunk(ClientSection[] sections, WorldHeight worldHeight) {
|
||||||
|
this.sections = sections;
|
||||||
|
this.worldHeight = worldHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ClientSection[] sections() {
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOccluding(int x, int y, int z) {
|
||||||
|
if (this.sections == null) return false;
|
||||||
|
int index = sectionIndex(SectionPos.blockToSectionCoord(y));
|
||||||
|
ClientSection section = this.sections[index];
|
||||||
|
if (section == null) return false;
|
||||||
|
return section.isOccluding((y & 15) << 8 | (z & 15) << 4 | x & 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sectionIndex(int sectionId) {
|
||||||
|
return sectionId - this.worldHeight.getMinSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package net.momirealms.craftengine.core.world.chunk.client;
|
||||||
|
|
||||||
|
public class ClientSection {
|
||||||
|
private ClientSectionOcclusionStorage storage;
|
||||||
|
|
||||||
|
public ClientSection(ClientSectionOcclusionStorage storage) {
|
||||||
|
this.storage = storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isOccluding(int x, int y, int z) {
|
||||||
|
return isOccluding((y << 4 | z) << 4 | x);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isOccluding(int index) {
|
||||||
|
return this.storage.isOccluding(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOccluding(int x, int y, int z, boolean value) {
|
||||||
|
this.setOccluding((y << 4 | z) << 4 | x, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOccluding(int index, boolean value) {
|
||||||
|
boolean wasOccluding = this.storage.isOccluding(index);
|
||||||
|
if (wasOccluding != value) {
|
||||||
|
if (this.storage instanceof PackedOcclusionStorage arrayStorage) {
|
||||||
|
arrayStorage.set(index, value);
|
||||||
|
} else {
|
||||||
|
PackedOcclusionStorage newStorage = new PackedOcclusionStorage(wasOccluding);
|
||||||
|
newStorage.set(index, value);
|
||||||
|
this.storage = newStorage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package net.momirealms.craftengine.core.world.chunk.client;
|
||||||
|
|
||||||
|
public interface ClientSectionOcclusionStorage {
|
||||||
|
|
||||||
|
boolean isOccluding(int index);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package net.momirealms.craftengine.core.world.chunk.client;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class PackedOcclusionStorage implements ClientSectionOcclusionStorage {
|
||||||
|
private static final int SIZE = 4096;
|
||||||
|
private static final int LONGS = SIZE / 64;
|
||||||
|
private final long[] data;
|
||||||
|
|
||||||
|
public PackedOcclusionStorage() {
|
||||||
|
this.data = new long[LONGS];
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackedOcclusionStorage(boolean defaultValue) {
|
||||||
|
this.data = new long[LONGS];
|
||||||
|
if (defaultValue) {
|
||||||
|
Arrays.fill(this.data, -1L); // 所有位设为1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOccluding(int index) {
|
||||||
|
int arrayIndex = index >>> 6; // index / 64
|
||||||
|
int bitIndex = index & 0x3F; // index % 64
|
||||||
|
return (this.data[arrayIndex] & (1L << bitIndex)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int index, boolean occlusion) {
|
||||||
|
int arrayIndex = index >>> 6; // index / 64
|
||||||
|
int bitIndex = index & 0x3F; // index % 64
|
||||||
|
if (occlusion) {
|
||||||
|
this.data[arrayIndex] |= (1L << bitIndex);
|
||||||
|
} else {
|
||||||
|
this.data[arrayIndex] &= ~(1L << bitIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package net.momirealms.craftengine.core.world.chunk.client;
|
||||||
|
|
||||||
|
public class SingularOcclusionStorage implements ClientSectionOcclusionStorage {
|
||||||
|
private final boolean isOccluding;
|
||||||
|
|
||||||
|
public SingularOcclusionStorage(boolean isOccluding) {
|
||||||
|
this.isOccluding = isOccluding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOccluding(int index) {
|
||||||
|
return this.isOccluding;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package net.momirealms.craftengine.core.world.chunk.client;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.world.Cullable;
|
||||||
|
|
||||||
|
public class VirtualCullableObject {
|
||||||
|
private final Cullable cullable;
|
||||||
|
private boolean isShown;
|
||||||
|
|
||||||
|
public VirtualCullableObject(Cullable cullable) {
|
||||||
|
this.cullable = cullable;
|
||||||
|
this.isShown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cullable cullable() {
|
||||||
|
return cullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShown() {
|
||||||
|
return isShown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShown(Player player, boolean shown) {
|
||||||
|
this.isShown = shown;
|
||||||
|
if (shown) {
|
||||||
|
this.cullable.show(player);
|
||||||
|
} else {
|
||||||
|
this.cullable.hide(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ public final class DefaultChunkSerializer {
|
|||||||
if (!blockEntities.isEmpty()) {
|
if (!blockEntities.isEmpty()) {
|
||||||
chunkNbt.put("block_entities", blockEntities);
|
chunkNbt.put("block_entities", blockEntities);
|
||||||
}
|
}
|
||||||
ListTag blockEntityRenders = DefaultBlockEntityRendererSerializer.serialize(chunk.constantBlockEntityRenderers());
|
ListTag blockEntityRenders = DefaultBlockEntityRendererSerializer.serialize(chunk.constantBlockEntityRendererPositions());
|
||||||
if (!blockEntityRenders.isEmpty()) {
|
if (!blockEntityRenders.isEmpty()) {
|
||||||
chunkNbt.put("block_entity_renderers", blockEntityRenders);
|
chunkNbt.put("block_entity_renderers", blockEntityRenders);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,17 @@ public class AABB {
|
|||||||
this.maxZ = Math.max(pos1.z, pos2.z);
|
this.maxZ = Math.max(pos1.z, pos2.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AABB move(BlockPos pos) {
|
||||||
|
return new AABB(
|
||||||
|
this.minX + pos.x + 0.5,
|
||||||
|
this.minY + pos.y + 0.5,
|
||||||
|
this.minZ + pos.z + 0.5,
|
||||||
|
this.maxX + pos.x + 0.5,
|
||||||
|
this.maxY + pos.y + 0.5,
|
||||||
|
this.maxZ + pos.z + 0.5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public AABB(BlockPos pos) {
|
public AABB(BlockPos pos) {
|
||||||
this(pos.x(), pos.y(), pos.z(), pos.x() + 1, pos.y() + 1, pos.z() + 1);
|
this(pos.x(), pos.y(), pos.z(), pos.x() + 1, pos.y() + 1, pos.z() + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user