package com.hypixel.hytale.builtin.blockphysics; import com.hypixel.hytale.builtin.blocktick.system.ChunkBlockTickSystem; import com.hypixel.hytale.component.ArchetypeChunk; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.DisableProcessingAssert; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.dependency.Dependency; import com.hypixel.hytale.component.dependency.Order; import com.hypixel.hytale.component.dependency.SystemDependency; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.server.core.asset.type.blocktick.BlockTickStrategy; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.blocktype.component.BlockPhysics; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.chunk.AbstractCachedAccessor; import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection; import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection; import com.hypixel.hytale.server.core.universe.world.chunk.section.FluidSection; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.util.Set; import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockPhysicsSystems { private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static final int MAX_SUPPORT_RADIUS = 14; public static class CachedAccessor extends AbstractCachedAccessor { private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(BlockPhysicsSystems.CachedAccessor::new); private static final int PHYSICS_COMPONENT = 0; private static final int FLUID_COMPONENT = 1; private static final int BLOCK_COMPONENT = 2; protected BlockSection selfBlockSection; protected BlockPhysics selfPhysics; protected FluidSection selfFluidSection; protected CachedAccessor() { super(3); } @Nonnull public static BlockPhysicsSystems.CachedAccessor of( ComponentAccessor commandBuffer, BlockSection blockSection, BlockPhysics section, FluidSection fluidSection, int cx, int cy, int cz, int radius ) { BlockPhysicsSystems.CachedAccessor accessor = THREAD_LOCAL.get(); accessor.init(commandBuffer, cx, cy, cz, radius); accessor.insertSectionComponent(0, section, cx, cy, cz); accessor.insertSectionComponent(1, fluidSection, cx, cy, cz); accessor.insertSectionComponent(2, blockSection, cx, cy, cz); accessor.selfBlockSection = blockSection; accessor.selfPhysics = section; accessor.selfFluidSection = fluidSection; return accessor; } @Nullable public BlockPhysics getBlockPhysics(int cx, int cy, int cz) { return this.getComponentSection(cx, cy, cz, 0, BlockPhysics.getComponentType()); } @Nullable public FluidSection getFluidSection(int cx, int cy, int cz) { return this.getComponentSection(cx, cy, cz, 1, FluidSection.getComponentType()); } @Nullable public BlockSection getBlockSection(int cx, int cy, int cz) { return this.getComponentSection(cx, cy, cz, 2, BlockSection.getComponentType()); } public void performBlockUpdate(int x, int y, int z, int maxSupportDistance) { for (int ix = -1; ix < 2; ix++) { int wx = x + ix; for (int iz = -1; iz < 2; iz++) { int wz = z + iz; for (int iy = -1; iy < 2; iy++) { int wy = y + iy; BlockPhysics physics = this.getBlockPhysics(ChunkUtil.chunkCoordinate(wx), ChunkUtil.chunkCoordinate(wy), ChunkUtil.chunkCoordinate(wz)); int support = physics != null ? physics.get(wx, wy, wz) : 0; if (support <= maxSupportDistance) { BlockSection blockChunk = this.getBlockSection(ChunkUtil.chunkCoordinate(wx), ChunkUtil.chunkCoordinate(wy), ChunkUtil.chunkCoordinate(wz)); if (blockChunk != null) { blockChunk.setTicking(wx, wy, wz, true); } } } } } } public void performBlockUpdate(int x, int y, int z) { for (int ix = -1; ix < 2; ix++) { int wx = x + ix; for (int iz = -1; iz < 2; iz++) { int wz = z + iz; for (int iy = -1; iy < 2; iy++) { int wy = y + iy; BlockSection blockChunk = this.getBlockSection(ChunkUtil.chunkCoordinate(wx), ChunkUtil.chunkCoordinate(wy), ChunkUtil.chunkCoordinate(wz)); if (blockChunk != null) { blockChunk.setTicking(wx, wy, wz, true); } } } } } } public static class Ticking extends EntityTickingSystem implements DisableProcessingAssert { private static final Query QUERY = Query.and( ChunkSection.getComponentType(), BlockSection.getComponentType(), BlockPhysics.getComponentType(), FluidSection.getComponentType() ); private static final Set> DEPENDENCIES = Set.of( new SystemDependency<>(Order.AFTER, ChunkBlockTickSystem.PreTick.class), new SystemDependency<>(Order.BEFORE, ChunkBlockTickSystem.Ticking.class) ); @Nonnull @Override public Query getQuery() { return QUERY; } @Nonnull @Override public Set> getDependencies() { return DEPENDENCIES; } @Override public void tick( float dt, int index, @Nonnull ArchetypeChunk archetypeChunk, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { ChunkSection section = archetypeChunk.getComponent(index, ChunkSection.getComponentType()); assert section != null; try { BlockSection blockSection = archetypeChunk.getComponent(index, BlockSection.getComponentType()); assert blockSection != null; if (blockSection.getTickingBlocksCountCopy() <= 0) { return; } BlockPhysics blockPhysics = archetypeChunk.getComponent(index, BlockPhysics.getComponentType()); assert blockPhysics != null; FluidSection fluidSection = archetypeChunk.getComponent(index, FluidSection.getComponentType()); assert fluidSection != null; WorldChunk worldChunk = commandBuffer.getComponent(section.getChunkColumnReference(), WorldChunk.getComponentType()); BlockPhysicsSystems.CachedAccessor accessor = BlockPhysicsSystems.CachedAccessor.of( commandBuffer, blockSection, blockPhysics, fluidSection, section.getX(), section.getY(), section.getZ(), 14 ); blockSection.forEachTicking( worldChunk, accessor, section.getY(), (wc, accessor1, localX, localY, localZ, blockId) -> { BlockPhysics phys = accessor1.selfPhysics; boolean isDeco = phys.isDeco(localX, localY, localZ); BlockType blockType = BlockType.getAssetMap().getAsset(blockId); if (blockType == null || blockId == 0) { return BlockTickStrategy.IGNORED; } else if (blockType.canBePlacedAsDeco() && isDeco) { return BlockTickStrategy.IGNORED; } else { World world = wc.getWorld(); Store entityStore = world.getEntityStore().getStore(); int blockX = wc.getX() << 5 | localX; int blockZ = wc.getZ() << 5 | localZ; int filler = accessor1.selfBlockSection.getFiller(localX, localY, localZ); int rotation = accessor1.selfBlockSection.getRotationIndex(localX, localY, localZ); return switch (BlockPhysicsUtil.applyBlockPhysics( entityStore, wc.getReference(), accessor, accessor1.selfBlockSection, accessor1.selfPhysics, accessor1.selfFluidSection, blockX, localY, blockZ, blockType, rotation, filler )) { case WAITING_CHUNK -> BlockTickStrategy.WAIT_FOR_ADJACENT_CHUNK_LOAD; case VALID -> BlockTickStrategy.IGNORED; case INVALID -> BlockTickStrategy.SLEEP; }; } } ); } catch (Exception var12) { ((HytaleLogger.Api)BlockPhysicsSystems.LOGGER.at(Level.SEVERE).withCause(var12)).log("Failed to tick chunk: %s", section); } } } }