mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-28 19:39:11 +00:00
优化实体剔除
This commit is contained in:
@@ -31,6 +31,7 @@ import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||
@@ -38,6 +39,7 @@ import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.registry.Holder;
|
||||
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import org.incendo.cloud.suggestion.Suggestion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -52,6 +54,7 @@ import java.util.concurrent.ExecutionException;
|
||||
|
||||
public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager {
|
||||
private static final JsonElement EMPTY_VARIANT_MODEL = MiscUtils.init(new JsonObject(), o -> o.addProperty("model", "minecraft:block/empty"));
|
||||
private static final AABB DEFAULT_BLOCK_ENTITY_AABB = new AABB(-.5, -.5, -.5, .5, .5, .5);
|
||||
protected final BlockParser blockParser;
|
||||
protected final BlockStateMappingParser blockStateMappingParser;
|
||||
// 根据id获取自定义方块
|
||||
@@ -603,7 +606,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
||||
BlockStateAppearance blockStateAppearance = new BlockStateAppearance(
|
||||
visualBlockState,
|
||||
parseBlockEntityRender(appearanceSection.get("entity-renderer")),
|
||||
ResourceConfigUtils.getAsAABB(appearanceSection.getOrDefault("aabb", 1), "aabb")
|
||||
parseCullingData(appearanceSection.get("entity-culling"))
|
||||
);
|
||||
appearances.put(appearanceName, blockStateAppearance);
|
||||
if (anyAppearance == null) {
|
||||
@@ -643,7 +646,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
||||
}
|
||||
for (ImmutableBlockState possibleState : possibleStates) {
|
||||
possibleState.setVisualBlockState(appearance.blockState());
|
||||
possibleState.setEstimatedBoundingBox(appearance.estimateAABB());
|
||||
possibleState.setCullingData(appearance.cullingData());
|
||||
appearance.blockEntityRenderer().ifPresent(possibleState::setConstantRenderers);
|
||||
}
|
||||
}
|
||||
@@ -667,7 +670,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
||||
if (visualState == null) {
|
||||
visualState = anyAppearance.blockState();
|
||||
state.setVisualBlockState(visualState);
|
||||
state.setEstimatedBoundingBox(anyAppearance.estimateAABB());
|
||||
state.setCullingData(anyAppearance.cullingData());
|
||||
anyAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers);
|
||||
}
|
||||
int appearanceId = visualState.registryId();
|
||||
@@ -707,6 +710,21 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
||||
}, () -> GsonHelper.get().toJson(section)));
|
||||
}
|
||||
|
||||
private CullingData parseCullingData(Object arguments) {
|
||||
if (arguments instanceof Boolean b && !b) {
|
||||
return null;
|
||||
}
|
||||
if (!(arguments instanceof Map)) {
|
||||
return new CullingData(DEFAULT_BLOCK_ENTITY_AABB, Config.entityCullingViewDistance(), 0.5);
|
||||
}
|
||||
Map<String, Object> argumentsMap = ResourceConfigUtils.getAsMap(arguments, "entity-culling");
|
||||
return new CullingData(
|
||||
ResourceConfigUtils.getAsAABB(argumentsMap.getOrDefault("aabb", 1), "aabb"),
|
||||
ResourceConfigUtils.getAsInt(argumentsMap.getOrDefault("view-distance", Config.entityCullingViewDistance()), "view-distance"),
|
||||
ResourceConfigUtils.getAsDouble(argumentsMap.getOrDefault("aabb-expansion", 0.5), "aabb-expansion")
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Optional<BlockEntityElementConfig<? extends BlockEntityElement>[]> parseBlockEntityRender(Object arguments) {
|
||||
if (arguments == null) return Optional.empty();
|
||||
|
||||
@@ -2,11 +2,12 @@ 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.BlockEntityElementConfig;
|
||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record BlockStateAppearance(BlockStateWrapper blockState,
|
||||
Optional<BlockEntityElementConfig<? extends BlockEntityElement>[]> blockEntityRenderer,
|
||||
AABB estimateAABB) {
|
||||
@Nullable CullingData cullingData) {
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.loot.LootTable;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
|
||||
import net.momirealms.craftengine.core.registry.Holder;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
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.NBT;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
@@ -43,7 +43,8 @@ public final class ImmutableBlockState {
|
||||
private BlockEntityType<? extends BlockEntity> blockEntityType;
|
||||
@Nullable
|
||||
private BlockEntityElementConfig<? extends BlockEntityElement>[] renderers;
|
||||
private AABB estimatedBoundingBox;
|
||||
@Nullable
|
||||
private CullingData cullingData;
|
||||
|
||||
ImmutableBlockState(
|
||||
Holder.Reference<CustomBlock> owner,
|
||||
@@ -89,12 +90,13 @@ public final class ImmutableBlockState {
|
||||
this.renderers = renderers;
|
||||
}
|
||||
|
||||
public void setEstimatedBoundingBox(AABB aabb) {
|
||||
this.estimatedBoundingBox = aabb;
|
||||
@Nullable
|
||||
public CullingData cullingData() {
|
||||
return cullingData;
|
||||
}
|
||||
|
||||
public AABB estimatedBoundingBox() {
|
||||
return estimatedBoundingBox;
|
||||
public void setCullingData(@Nullable CullingData cullingData) {
|
||||
this.cullingData = cullingData;
|
||||
}
|
||||
|
||||
public boolean hasBlockEntity() {
|
||||
|
||||
@@ -2,18 +2,19 @@ package net.momirealms.craftengine.core.block.entity.render;
|
||||
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
|
||||
import net.momirealms.craftengine.core.world.Cullable;
|
||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public class ConstantBlockEntityRenderer implements Cullable {
|
||||
private final BlockEntityElement[] elements;
|
||||
public final AABB aabb;
|
||||
public final CullingData cullingData;
|
||||
|
||||
public ConstantBlockEntityRenderer(BlockEntityElement[] elements, AABB aabb) {
|
||||
public ConstantBlockEntityRenderer(BlockEntityElement[] elements, @Nullable CullingData cullingData) {
|
||||
this.elements = elements;
|
||||
this.aabb = aabb;
|
||||
this.cullingData = cullingData;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,7 +56,11 @@ public class ConstantBlockEntityRenderer implements Cullable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AABB aabb() {
|
||||
return this.aabb;
|
||||
public CullingData cullingData() {
|
||||
return this.cullingData;
|
||||
}
|
||||
|
||||
public boolean canCull() {
|
||||
return this.cullingData != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
|
||||
|
||||
public abstract void addTrackedBlockEntities(Map<BlockPos, ConstantBlockEntityRenderer> renders);
|
||||
|
||||
public abstract void addTrackedBlockEntity(BlockPos blockPos, ConstantBlockEntityRenderer renderer);
|
||||
public abstract VirtualCullableObject addTrackedBlockEntity(BlockPos blockPos, ConstantBlockEntityRenderer renderer);
|
||||
|
||||
public abstract VirtualCullableObject getTrackedBlockEntity(BlockPos blockPos);
|
||||
|
||||
|
||||
@@ -204,6 +204,7 @@ public class Config {
|
||||
protected int emoji$max_emojis_per_parse;
|
||||
|
||||
protected boolean client_optimization$entity_culling$enable;
|
||||
protected int client_optimization$entity_culling$view_distance;
|
||||
|
||||
public Config(CraftEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -566,6 +567,7 @@ public class Config {
|
||||
|
||||
// client optimization
|
||||
client_optimization$entity_culling$enable = config.getBoolean("client-optimization.entity-culling.enable", false);
|
||||
client_optimization$entity_culling$view_distance = config.getInt("client-optimization.entity-culling.view-distance", 64);
|
||||
|
||||
firstTime = false;
|
||||
}
|
||||
@@ -1161,6 +1163,10 @@ public class Config {
|
||||
return instance.client_optimization$entity_culling$enable;
|
||||
}
|
||||
|
||||
public static int entityCullingViewDistance() {
|
||||
return instance.client_optimization$entity_culling$view_distance;
|
||||
}
|
||||
|
||||
public YamlDocument loadOrCreateYamlData(String fileName) {
|
||||
Path path = this.plugin.dataFolderPath().resolve(fileName);
|
||||
if (!Files.exists(path)) {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.momirealms.craftengine.core.plugin.entityculling;
|
||||
|
||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||
|
||||
public final class CullingData {
|
||||
public final AABB aabb;
|
||||
public final int maxDistance;
|
||||
public final double aabbExpansion;
|
||||
|
||||
public CullingData(AABB aabb, int maxDistance, double aabbExpansion) {
|
||||
this.aabb = aabb;
|
||||
this.maxDistance = maxDistance;
|
||||
this.aabbExpansion = aabbExpansion;
|
||||
}
|
||||
|
||||
public AABB aabb() {
|
||||
return aabb;
|
||||
}
|
||||
|
||||
public int maxDistance() {
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
public double aabbExpansion() {
|
||||
return aabbExpansion;
|
||||
}
|
||||
}
|
||||
@@ -13,38 +13,42 @@ import java.util.Arrays;
|
||||
public final class EntityCulling {
|
||||
public static final int MAX_SAMPLES = 14;
|
||||
private final Player player;
|
||||
private final int maxDistance;
|
||||
private final double aabbExpansion;
|
||||
private final boolean[] dotSelectors = new boolean[MAX_SAMPLES];
|
||||
private final MutableVec3d[] targetPoints = new MutableVec3d[MAX_SAMPLES];
|
||||
private final int[] lastHitBlock = new int[MAX_SAMPLES * 3];
|
||||
private final boolean[] canCheckLastHitBlock = new boolean[MAX_SAMPLES];
|
||||
// 相机附近的点位大概率会多次重复获取
|
||||
private final long[] occlusionCache = new long[32 * 32 * 32 / 32];
|
||||
private int hitBlockCount = 0;
|
||||
private int lastVisitChunkX = Integer.MAX_VALUE;
|
||||
private int lastVisitChunkZ = Integer.MAX_VALUE;
|
||||
private ClientChunk lastVisitChunk = null;
|
||||
|
||||
public EntityCulling(Player player, int maxDistance, double aabbExpansion) {
|
||||
public EntityCulling(Player player) {
|
||||
this.player = player;
|
||||
this.maxDistance = maxDistance;
|
||||
this.aabbExpansion = aabbExpansion;
|
||||
for (int i = 0; i < MAX_SAMPLES; i++) {
|
||||
this.targetPoints[i] = new MutableVec3d(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isVisible(AABB aabb, Vec3d cameraPos) {
|
||||
public void resetCache() {
|
||||
Arrays.fill(this.occlusionCache, 0);
|
||||
}
|
||||
|
||||
public boolean isVisible(CullingData cullable, Vec3d cameraPos, Vec3d playerHeadPos) {
|
||||
// 情空标志位
|
||||
Arrays.fill(this.canCheckLastHitBlock, false);
|
||||
this.hitBlockCount = 0;
|
||||
AABB aabb = cullable.aabb;
|
||||
double aabbExpansion = cullable.aabbExpansion;
|
||||
|
||||
// 根据AABB获取能包裹此AABB的最小长方体
|
||||
int minX = MiscUtils.floor(aabb.minX - this.aabbExpansion);
|
||||
int minY = MiscUtils.floor(aabb.minY - this.aabbExpansion);
|
||||
int minZ = MiscUtils.floor(aabb.minZ - this.aabbExpansion);
|
||||
int maxX = MiscUtils.ceil(aabb.maxX + this.aabbExpansion);
|
||||
int maxY = MiscUtils.ceil(aabb.maxY + this.aabbExpansion);
|
||||
int maxZ = MiscUtils.ceil(aabb.maxZ + this.aabbExpansion);
|
||||
int minX = MiscUtils.floor(aabb.minX - aabbExpansion);
|
||||
int minY = MiscUtils.floor(aabb.minY - aabbExpansion);
|
||||
int minZ = MiscUtils.floor(aabb.minZ - aabbExpansion);
|
||||
int maxX = MiscUtils.ceil(aabb.maxX + aabbExpansion);
|
||||
int maxY = MiscUtils.ceil(aabb.maxY + aabbExpansion);
|
||||
int maxZ = MiscUtils.ceil(aabb.maxZ + aabbExpansion);
|
||||
|
||||
double cameraX = cameraPos.x;
|
||||
double cameraY = cameraPos.y;
|
||||
@@ -60,7 +64,8 @@ public final class EntityCulling {
|
||||
}
|
||||
|
||||
// 如果设置了最大距离
|
||||
if (this.maxDistance > 0) {
|
||||
int maxDistance = cullable.maxDistance;
|
||||
if (maxDistance > 0) {
|
||||
// 计算AABB到相机的最小距离
|
||||
double distanceSq = 0.0;
|
||||
// 计算XYZ轴方向的距离
|
||||
@@ -68,7 +73,7 @@ public final class EntityCulling {
|
||||
distanceSq += distanceSq(minY, maxY, cameraY, relY);
|
||||
distanceSq += distanceSq(minZ, maxZ, cameraZ, relZ);
|
||||
// 检查距离是否超过最大值
|
||||
double maxDistanceSq = this.maxDistance * this.maxDistance;
|
||||
double maxDistanceSq = maxDistance * maxDistance;
|
||||
// 超过最大距离,剔除
|
||||
if (distanceSq > maxDistanceSq) {
|
||||
return false;
|
||||
@@ -277,21 +282,76 @@ public final class EntityCulling {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean stepRay(int currentBlockX, int currentBlockY, int currentBlockZ,
|
||||
// 0 = 没缓存
|
||||
// 1 = 没遮挡
|
||||
// 2 = 有遮挡
|
||||
private int getCacheState(int index) {
|
||||
int arrayIndex = index / 32; // 获取数组下标
|
||||
int offset = (index % 32) * 2; // 每个状态占2bit,计算位偏移
|
||||
if (arrayIndex >= 0 && arrayIndex < this.occlusionCache.length) {
|
||||
long cacheValue = this.occlusionCache[arrayIndex];
|
||||
// 提取2bit的状态值 (0-3)
|
||||
return (int) ((cacheValue >> offset) & 0b11);
|
||||
}
|
||||
return 0; // 索引越界时返回默认状态
|
||||
}
|
||||
|
||||
private void setCacheState(int index, int state) {
|
||||
long[] cache = this.occlusionCache;
|
||||
int arrayIndex = index / 32;
|
||||
int offset = (index % 32) * 2;
|
||||
|
||||
if (arrayIndex >= 0 && arrayIndex < cache.length) {
|
||||
long mask = ~(0b11L << offset); // 创建清除掩码
|
||||
long newValue = (cache[arrayIndex] & mask) | ((state & 0b11L) << offset);
|
||||
cache[arrayIndex] = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean stepRay(int startingX, int startingY, int startingZ,
|
||||
double stepSizeX, double stepSizeY, double stepSizeZ,
|
||||
int remainingSteps, int stepDirectionX, int stepDirectionY,
|
||||
int stepDirectionZ, double nextStepTimeY, double nextStepTimeX,
|
||||
double nextStepTimeZ) {
|
||||
int remainingSteps,
|
||||
int stepDirectionX, int stepDirectionY, int stepDirectionZ,
|
||||
double nextStepTimeY, double nextStepTimeX, double nextStepTimeZ) {
|
||||
|
||||
int currentBlockX = startingX;
|
||||
int currentBlockY = startingY;
|
||||
int currentBlockZ = startingZ;
|
||||
|
||||
// 遍历射线路径上的所有方块(跳过最后一个目标方块)
|
||||
for (; remainingSteps > 1; remainingSteps--) {
|
||||
|
||||
int cacheIndex = getCacheIndex(currentBlockX, currentBlockY, currentBlockZ, startingX, startingY, startingZ);
|
||||
if (cacheIndex != -1) {
|
||||
int cacheState = getCacheState(cacheIndex);
|
||||
// 没遮挡
|
||||
if (cacheState == 1) {
|
||||
continue;
|
||||
}
|
||||
// 有遮挡
|
||||
else if (cacheState == 2) {
|
||||
this.lastHitBlock[this.hitBlockCount * 3] = currentBlockX;
|
||||
this.lastHitBlock[this.hitBlockCount * 3 + 1] = currentBlockY;
|
||||
this.lastHitBlock[this.hitBlockCount * 3 + 2] = currentBlockZ;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查当前方块是否遮挡视线
|
||||
if (isOccluding(currentBlockX, currentBlockY, currentBlockZ)) {
|
||||
this.lastHitBlock[this.hitBlockCount * 3] = currentBlockX;
|
||||
this.lastHitBlock[this.hitBlockCount * 3 + 1] = currentBlockY;
|
||||
this.lastHitBlock[this.hitBlockCount * 3 + 2] = currentBlockZ;
|
||||
// 设置缓存
|
||||
if (cacheIndex != -1) {
|
||||
setCacheState(cacheIndex, 2);
|
||||
}
|
||||
return false; // 视线被遮挡,立即返回
|
||||
} else {
|
||||
// 设置缓存
|
||||
if (cacheIndex != -1) {
|
||||
setCacheState(cacheIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 基于时间参数选择下一个要遍历的方块方向
|
||||
@@ -315,6 +375,22 @@ public final class EntityCulling {
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getCacheIndex(int x, int y, int z, int startX, int startY, int startZ) {
|
||||
int deltaX = startX + 16 - x;
|
||||
if (deltaX < 0 || deltaX >= 32) {
|
||||
return -1;
|
||||
}
|
||||
int deltaY = startY + 16 - y;
|
||||
if (deltaY < 0 || deltaY >= 32) {
|
||||
return -1;
|
||||
}
|
||||
int deltaZ = startZ + 16 - z;
|
||||
if (deltaZ < 0 || deltaZ >= 32) {
|
||||
return -1;
|
||||
}
|
||||
return deltaX + 32 * deltaY + 32 * 32 * deltaZ;
|
||||
}
|
||||
|
||||
private double distanceSq(int min, int max, double camera, Relative rel) {
|
||||
if (rel == Relative.NEGATIVE) {
|
||||
double dx = camera - max;
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -46,6 +47,13 @@ public abstract class AbstractJavaScheduler<T> implements SchedulerAdapter<T> {
|
||||
return new AsyncTask(future);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncRepeating(Consumer<SchedulerTask> task, long delay, long interval, TimeUnit unit) {
|
||||
LazyAsyncTask asyncTask = new LazyAsyncTask();
|
||||
asyncTask.future = this.scheduler.scheduleAtFixedRate(() -> this.worker.execute(() -> task.accept(asyncTask)), delay, interval, unit);
|
||||
return asyncTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdownScheduler() {
|
||||
this.scheduler.shutdown();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package net.momirealms.craftengine.core.plugin.scheduler;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
public class LazyAsyncTask implements SchedulerTask {
|
||||
|
||||
public ScheduledFuture<?> future;
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (future != null) {
|
||||
future.cancel(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelled() {
|
||||
if (future == null) return false;
|
||||
return future.isCancelled();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.plugin.scheduler;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface SchedulerAdapter<W> {
|
||||
|
||||
@@ -25,6 +26,8 @@ public interface SchedulerAdapter<W> {
|
||||
|
||||
SchedulerTask asyncRepeating(Runnable task, long delay, long interval, TimeUnit unit);
|
||||
|
||||
SchedulerTask asyncRepeating(Consumer<SchedulerTask> task, long delay, long interval, TimeUnit unit);
|
||||
|
||||
void shutdownScheduler();
|
||||
|
||||
void shutdownExecutor();
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package net.momirealms.craftengine.core.world;
|
||||
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface Cullable {
|
||||
|
||||
AABB aabb();
|
||||
|
||||
void show(Player player);
|
||||
|
||||
void hide(Player player);
|
||||
|
||||
@Nullable
|
||||
CullingData cullingData();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityEl
|
||||
import net.momirealms.craftengine.core.block.entity.tick.*;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.entityculling.CullingData;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||
import net.momirealms.craftengine.core.world.*;
|
||||
import net.momirealms.craftengine.core.world.chunk.client.VirtualCullableObject;
|
||||
@@ -139,7 +140,12 @@ public class CEChunk {
|
||||
BlockEntityElementConfig<? extends BlockEntityElement>[] renderers = state.constantRenderers();
|
||||
if (renderers != null && renderers.length > 0) {
|
||||
BlockEntityElement[] elements = new BlockEntityElement[renderers.length];
|
||||
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements, state.estimatedBoundingBox().move(pos));
|
||||
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(
|
||||
elements,
|
||||
Optional.ofNullable(state.cullingData())
|
||||
.map(data -> new CullingData(data.aabb.move(pos), data.maxDistance, data.aabbExpansion))
|
||||
.orElse(null)
|
||||
);
|
||||
World wrappedWorld = this.world.world();
|
||||
List<Player> trackedBy = getTrackedBy();
|
||||
boolean hasTrackedBy = trackedBy != null && !trackedBy.isEmpty();
|
||||
@@ -159,7 +165,7 @@ public class CEChunk {
|
||||
// 如果启用实体剔除,那么只对已经渲染的进行变换
|
||||
if (Config.enableEntityCulling()) {
|
||||
for (Player player : trackedBy) {
|
||||
VirtualCullableObject trackedBlockEntity = player.getTrackedBlockEntity(pos);
|
||||
VirtualCullableObject trackedBlockEntity = player.addTrackedBlockEntity(pos, renderer);
|
||||
if (trackedBlockEntity == null || trackedBlockEntity.isShown()) {
|
||||
element.transform(player);
|
||||
}
|
||||
@@ -207,7 +213,7 @@ public class CEChunk {
|
||||
// 如果启用实体剔除,那么只对已经渲染的进行变换
|
||||
if (Config.enableEntityCulling()) {
|
||||
for (Player player : trackedBy) {
|
||||
VirtualCullableObject trackedBlockEntity = player.getTrackedBlockEntity(pos);
|
||||
VirtualCullableObject trackedBlockEntity = player.addTrackedBlockEntity(pos, renderer);
|
||||
if (trackedBlockEntity == null || trackedBlockEntity.isShown()) {
|
||||
newElement.transform(player);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user