9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-26 02:19:23 +00:00

实体剔除前置

This commit is contained in:
XiaoMoMi
2025-11-28 02:57:59 +08:00
parent 9bce13475f
commit bced7bfda6
34 changed files with 470 additions and 100 deletions

View File

@@ -600,7 +600,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
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);
if (anyAppearance == null) {
anyAppearance = blockStateAppearance;
@@ -639,6 +643,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
}
for (ImmutableBlockState possibleState : possibleStates) {
possibleState.setVisualBlockState(appearance.blockState());
possibleState.setEstimatedBoundingBox(appearance.estimateAABB());
appearance.blockEntityRenderer().ifPresent(possibleState::setConstantRenderers);
}
}
@@ -662,6 +667,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
if (visualState == null) {
visualState = anyAppearance.blockState();
state.setVisualBlockState(visualState);
state.setEstimatedBoundingBox(anyAppearance.estimateAABB());
anyAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers);
}
int appearanceId = visualState.registryId();

View File

@@ -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.BlockEntityElementConfig;
import net.momirealms.craftengine.core.world.collision.AABB;
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) {
}

View File

@@ -17,6 +17,7 @@ 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;
@@ -42,6 +43,7 @@ public final class ImmutableBlockState {
private BlockEntityType<? extends BlockEntity> blockEntityType;
@Nullable
private BlockEntityElementConfig<? extends BlockEntityElement>[] renderers;
private AABB estimatedBoundingBox;
ImmutableBlockState(
Holder.Reference<CustomBlock> owner,
@@ -87,6 +89,14 @@ public final class ImmutableBlockState {
this.renderers = renderers;
}
public void setEstimatedBoundingBox(AABB aabb) {
this.estimatedBoundingBox = aabb;
}
public AABB estimatedBoundingBox() {
return estimatedBoundingBox;
}
public boolean hasBlockEntity() {
return this.blockEntityType != null;
}

View File

@@ -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.entity.player.Player;
import net.momirealms.craftengine.core.world.Cullable;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
public class ConstantBlockEntityRenderer {
public class ConstantBlockEntityRenderer implements Cullable {
private final BlockEntityElement[] elements;
public final AABB aabb;
public ConstantBlockEntityRenderer(BlockEntityElement[] elements) {
public ConstantBlockEntityRenderer(BlockEntityElement[] elements, AABB aabb) {
this.elements = elements;
this.aabb = aabb;
}
public void show(Player player) {
@@ -47,4 +51,9 @@ public class ConstantBlockEntityRenderer {
public BlockEntityElement[] elements() {
return this.elements;
}
@Override
public AABB aabb() {
return this.aabb;
}
}

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.entity.player;
import net.kyori.adventure.text.Component;
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.item.Item;
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.SoundSource;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Position;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
public abstract class Player extends AbstractEntity implements NetWorkUser {
private static final Key TYPE = Key.of("minecraft:player");
@@ -35,6 +35,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
@Override
public abstract Object serverPlayer();
public abstract void setClientSideWorld(World world);
public abstract float getDestroyProgress(Object blockState, BlockPos pos);
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 addTrackedBlockEntities(Map<BlockPos, ConstantBlockEntityRenderer> renders);
public abstract void removeTrackedBlockEntities(Collection<BlockPos> renders);
public abstract void clearTrackedBlockEntities();
@Override
public void remove() {
}

View File

@@ -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.config.Config;
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.dependency.Dependencies;
import net.momirealms.craftengine.core.plugin.dependency.Dependency;

View File

@@ -203,6 +203,8 @@ public class Config {
protected boolean emoji$contexts$sign;
protected int emoji$max_emojis_per_parse;
protected boolean client_optimization$entity_culling$enable;
public Config(CraftEngine plugin) {
this.plugin = plugin;
this.configVersion = PluginProperties.getValue("config");
@@ -562,6 +564,9 @@ public class Config {
emoji$contexts$sign = config.getBoolean("emoji.contexts.sign", true);
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;
}
@@ -1152,6 +1157,10 @@ public class Config {
return instance.resource_pack$optimization$texture$zopfli_iterations;
}
public static boolean enableEntityCulling() {
return instance.client_optimization$entity_culling$enable;
}
public YamlDocument loadOrCreateYamlData(String fileName) {
Path path = this.plugin.dataFolderPath().resolve(fileName);
if (!Files.exists(path)) {

View File

@@ -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.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.SNBTReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public interface TemplateManager extends Manageable {

View File

@@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin.config.template.argument;
import com.ezylang.evalex.Expression;
import com.ezylang.evalex.data.EvaluationValue;
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 java.util.Locale;

View File

@@ -6,7 +6,8 @@ import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.core.plugin.Plugin;
import net.momirealms.craftengine.core.util.IntIdentityList;
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.Nullable;
@@ -65,9 +66,7 @@ public interface NetWorkUser {
@ApiStatus.Internal
ConnectionState encoderState();
int clientSideSectionCount();
Key clientSideDimension();
World clientSideWorld();
Object serverPlayer();
@@ -89,9 +88,9 @@ public interface NetWorkUser {
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();

View File

@@ -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.TranslationManager;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3f;
@@ -341,4 +342,52 @@ public final class ResourceConfigUtils {
}
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);
}
}
}
}

View File

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

View File

@@ -4,9 +4,9 @@ import net.momirealms.craftengine.core.util.Direction;
public class Vec3i implements Comparable<Vec3i> {
public static final Vec3i ZERO = new Vec3i(0, 0, 0);
protected int x;
protected int y;
protected int z;
public final int x;
public final int y;
public final int z;
public Vec3i(int x, int y, int z) {
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);
}
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
public boolean equals(Object object) {
return this == object || object instanceof Vec3i vec3i && this.x == vec3i.x && this.y == vec3i.y && this.z == vec3i.z;

View File

@@ -77,15 +77,24 @@ public class ArrayPalette<T> implements Palette<T> {
@Override
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])) {
return true;
}
}
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
public T get(int id) {
if (id >= 0 && id < this.size) {

View File

@@ -67,7 +67,7 @@ public class BiMapPalette<T> implements Palette<T> {
@Override
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))) {
return true;
}
@@ -75,6 +75,16 @@ public class BiMapPalette<T> implements Palette<T> {
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
public T get(int id) {
T object = this.map.get(id);

View File

@@ -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.tick.*;
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.world.*;
import net.momirealms.craftengine.core.world.chunk.serialization.DefaultBlockEntityRendererSerializer;
@@ -91,8 +92,12 @@ public class CEChunk {
public void spawnBlockEntities(Player player) {
try {
this.renderLock.readLock().lock();
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
renderer.show(player);
if (Config.enableEntityCulling()) {
player.addTrackedBlockEntities(this.constantBlockEntityRenderers);
} else {
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
renderer.show(player);
}
}
for (DynamicBlockEntityRenderer renderer : this.dynamicBlockEntityRenderers.values()) {
renderer.show(player);
@@ -105,8 +110,12 @@ public class CEChunk {
public void despawnBlockEntities(Player player) {
try {
this.renderLock.readLock().lock();
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
renderer.hide(player);
if (Config.enableEntityCulling()) {
player.removeTrackedBlockEntities(this.constantBlockEntityRenderers.keySet());
} else {
for (ConstantBlockEntityRenderer renderer : this.constantBlockEntityRenderers.values()) {
renderer.hide(player);
}
}
for (DynamicBlockEntityRenderer renderer : this.dynamicBlockEntityRenderers.values()) {
renderer.hide(player);
@@ -129,7 +138,7 @@ 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);
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(elements, state.estimatedBoundingBox().move(pos));
World wrappedWorld = this.world.world();
List<Player> trackedBy = getTrackedBy();
boolean hasTrackedBy = trackedBy != null && !trackedBy.isEmpty();
@@ -439,7 +448,7 @@ public class CEChunk {
return Collections.unmodifiableCollection(this.blockEntities.values());
}
public List<BlockPos> constantBlockEntityRenderers() {
public List<BlockPos> constantBlockEntityRendererPositions() {
try {
this.renderLock.readLock().lock();
return new ArrayList<>(this.constantBlockEntityRenderers.keySet());

View File

@@ -1,7 +0,0 @@
package net.momirealms.craftengine.core.world.chunk;
public class ChunkStatus {
public ChunkStatus() {
}
}

View File

@@ -29,6 +29,11 @@ public class IdListPalette<T> implements Palette<T> {
return true;
}
@Override
public boolean allMatch(Predicate<T> predicate) {
return true;
}
@Override
public T get(int id) {
T object = this.idList.get(id);

View File

@@ -13,6 +13,8 @@ public interface Palette<T> {
boolean hasAny(Predicate<T> predicate);
boolean allMatch(Predicate<T> predicate);
T get(int id);
int getSize();

View File

@@ -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
public T get(int id) {
if (this.entry != null && id == 0) {

View File

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

View File

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

View File

@@ -0,0 +1,6 @@
package net.momirealms.craftengine.core.world.chunk.client;
public interface ClientSectionOcclusionStorage {
boolean isOccluding(int index);
}

View File

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

View File

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

View File

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

View File

@@ -32,7 +32,7 @@ public final class DefaultChunkSerializer {
if (!blockEntities.isEmpty()) {
chunkNbt.put("block_entities", blockEntities);
}
ListTag blockEntityRenders = DefaultBlockEntityRendererSerializer.serialize(chunk.constantBlockEntityRenderers());
ListTag blockEntityRenders = DefaultBlockEntityRendererSerializer.serialize(chunk.constantBlockEntityRendererPositions());
if (!blockEntityRenders.isEmpty()) {
chunkNbt.put("block_entity_renderers", blockEntityRenders);
}

View File

@@ -35,6 +35,17 @@ public class AABB {
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) {
this(pos.x(), pos.y(), pos.z(), pos.x() + 1, pos.y() + 1, pos.z() + 1);
}