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 BlockPhysicsSystems() {
}
public static class Ticking extends EntityTickingSystem<ChunkStore> implements DisableProcessingAssert {
private static final Query<ChunkStore> QUERY = Query.<ChunkStore>and(ChunkSection.getComponentType(), BlockSection.getComponentType(), BlockPhysics.getComponentType(), FluidSection.getComponentType());
private static final Set<Dependency<ChunkStore>> DEPENDENCIES;
public Ticking() {
}
@Nonnull
public Query<ChunkStore> getQuery() {
return QUERY;
}
@Nonnull
public Set<Dependency<ChunkStore>> getDependencies() {
return DEPENDENCIES;
}
public void tick(float dt, int index, @Nonnull ArchetypeChunk<ChunkStore> archetypeChunk, @Nonnull Store<ChunkStore> store, @Nonnull CommandBuffer<ChunkStore> commandBuffer) {
ChunkSection section = (ChunkSection)archetypeChunk.getComponent(index, ChunkSection.getComponentType());
assert section != null;
try {
BlockSection blockSection = (BlockSection)archetypeChunk.getComponent(index, BlockSection.getComponentType());
assert blockSection != null;
if (blockSection.getTickingBlocksCountCopy() <= 0) {
return;
}
BlockPhysics blockPhysics = (BlockPhysics)archetypeChunk.getComponent(index, BlockPhysics.getComponentType());
assert blockPhysics != null;
FluidSection fluidSection = (FluidSection)archetypeChunk.getComponent(index, FluidSection.getComponentType());
assert fluidSection != null;
WorldChunk worldChunk = (WorldChunk)commandBuffer.getComponent(section.getChunkColumnReference(), WorldChunk.getComponentType());
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)BlockType.getAssetMap().getAsset(blockId);
if (blockType != null && blockId != 0) {
if (blockType.canBePlacedAsDeco() && isDeco) {
return BlockTickStrategy.IGNORED;
} else {
World world = wc.getWorld();
Store<EntityStore> 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);
BlockTickStrategy var10000;
switch (BlockPhysicsUtil.applyBlockPhysics(entityStore, wc.getReference(), accessor, accessor1.selfBlockSection, accessor1.selfPhysics, accessor1.selfFluidSection, blockX, localY, blockZ, blockType, rotation, filler)) {
case WAITING_CHUNK -> var10000 = BlockTickStrategy.WAIT_FOR_ADJACENT_CHUNK_LOAD;
case VALID -> var10000 = BlockTickStrategy.IGNORED;
case INVALID -> var10000 = BlockTickStrategy.SLEEP;
default -> throw new MatchException((String)null, (Throwable)null);
}
return var10000;
}
} else {
return BlockTickStrategy.IGNORED;
}
});
} catch (Exception t) {
((HytaleLogger.Api)BlockPhysicsSystems.LOGGER.at(Level.SEVERE).withCause(t)).log("Failed to tick chunk: %s", section);
}
}
static {
DEPENDENCIES = Set.of(new SystemDependency(Order.AFTER, ChunkBlockTickSystem.PreTick.class), new SystemDependency(Order.BEFORE, ChunkBlockTickSystem.Ticking.class));
}
}
public static class CachedAccessor extends AbstractCachedAccessor {
private static final ThreadLocal<CachedAccessor> THREAD_LOCAL = ThreadLocal.withInitial(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 CachedAccessor of(ComponentAccessor<ChunkStore> commandBuffer, BlockSection blockSection, BlockPhysics section, FluidSection fluidSection, int cx, int cy, int cz, int radius) {
CachedAccessor accessor = (CachedAccessor)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 (BlockPhysics)this.getComponentSection(cx, cy, cz, 0, BlockPhysics.getComponentType());
}
@Nullable
public FluidSection getFluidSection(int cx, int cy, int cz) {
return (FluidSection)this.getComponentSection(cx, cy, cz, 1, FluidSection.getComponentType());
}
@Nullable
public BlockSection getBlockSection(int cx, int cy, int cz) {
return (BlockSection)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);
}
}
}
}
}
}
}