package com.hypixel.hytale.builtin.fluid;
import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap;
import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap;
import com.hypixel.hytale.codec.lookup.Priority;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.event.EventPriority;
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.asset.type.fluid.DefaultFluidTicker;
import com.hypixel.hytale.server.core.asset.type.fluid.FiniteFluidTicker;
import com.hypixel.hytale.server.core.asset.type.fluid.Fluid;
import com.hypixel.hytale.server.core.asset.type.fluid.FluidTicker;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.ChunkColumn;
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.FluidSection;
import com.hypixel.hytale.server.core.universe.world.events.ChunkPreLoadProcessEvent;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import java.time.Instant;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class FluidPlugin extends JavaPlugin {
private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
private static FluidPlugin instance;
public static FluidPlugin get() {
return instance;
}
public FluidPlugin(@Nonnull JavaPluginInit init) {
super(init);
instance = this;
}
protected void setup() {
FluidTicker.CODEC.register(Priority.DEFAULT, (String)"Default", DefaultFluidTicker.class, DefaultFluidTicker.CODEC);
FluidTicker.CODEC.register((String)"Finite", FiniteFluidTicker.class, FiniteFluidTicker.CODEC);
this.getChunkStoreRegistry().registerSystem(new FluidSystems.EnsureFluidSection());
this.getChunkStoreRegistry().registerSystem(new FluidSystems.MigrateFromColumn());
this.getChunkStoreRegistry().registerSystem(new FluidSystems.SetupSection());
this.getChunkStoreRegistry().registerSystem(new FluidSystems.LoadPacketGenerator());
this.getChunkStoreRegistry().registerSystem(new FluidSystems.ReplicateChanges());
this.getChunkStoreRegistry().registerSystem(new FluidSystems.Ticking());
this.getEventRegistry().registerGlobal(EventPriority.FIRST, ChunkPreLoadProcessEvent.class, FluidPlugin::onChunkPreProcess);
this.getCommandRegistry().registerCommand(new FluidCommand());
}
private static void onChunkPreProcess(@Nonnull ChunkPreLoadProcessEvent event) {
if (event.isNewlyGenerated()) {
WorldChunk wc = event.getChunk();
Holder<ChunkStore> holder = event.getHolder();
ChunkColumn column = (ChunkColumn)holder.getComponent(ChunkColumn.getComponentType());
if (column != null) {
BlockChunk blockChunk = (BlockChunk)holder.getComponent(BlockChunk.getComponentType());
if (blockChunk != null) {
IndexedLookupTableAssetMap<String, Fluid> fluidMap = Fluid.getAssetMap();
BlockTypeAssetMap<String, BlockType> blockMap = BlockType.getAssetMap();
Holder<ChunkStore>[] sections = column.getSectionHolders();
if (sections != null) {
for(int i = 0; i < sections.length && i < 10; ++i) {
Holder<ChunkStore> section = sections[i];
FluidSection fluid = (FluidSection)section.getComponent(FluidSection.getComponentType());
if (fluid != null && !fluid.isEmpty()) {
BlockSection blockSection = (BlockSection)section.ensureAndGetComponent(BlockSection.getComponentType());
for(int idx = 0; idx < 32768; ++idx) {
int fluidId = fluid.getFluidId(idx);
if (fluidId != 0) {
Fluid fluidType = fluidMap.getAsset(fluidId);
if (fluidType == null) {
LOGGER.at(Level.WARNING).log("Invalid fluid found in chunk section: %d, %d %d with id %d", fluid.getX(), fluid.getY(), fluid.getZ(), fluid);
fluid.setFluid(idx, 0, (byte)0);
} else {
FluidTicker ticker = fluidType.getTicker();
if (FluidTicker.isSolid(blockMap.getAsset(blockSection.get(idx)))) {
fluid.setFluid(idx, 0, (byte)0);
} else {
if (!ticker.canDemote()) {
int x = ChunkUtil.minBlock(fluid.getX()) + ChunkUtil.xFromIndex(idx);
int y = ChunkUtil.minBlock(fluid.getY()) + ChunkUtil.yFromIndex(idx);
int z = ChunkUtil.minBlock(fluid.getZ()) + ChunkUtil.zFromIndex(idx);
boolean canSpread = ChunkUtil.isBorderBlock(x, z) || fluid.getFluidId(x - 1, y, z) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x - 1, y, z))) || fluid.getFluidId(x + 1, y, z) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x + 1, y, z))) || fluid.getFluidId(x, y, z - 1) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x, y, z - 1))) || fluid.getFluidId(x, y, z + 1) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x, y, z + 1)));
if (y > 0) {
if (ChunkUtil.chunkCoordinate(y) == ChunkUtil.chunkCoordinate(y - 1)) {
canSpread |= fluid.getFluidId(x, y - 1, z) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x, y - 1, z)));
} else {
FluidSection fluidSection2 = (FluidSection)sections[i - 1].getComponent(FluidSection.getComponentType());
canSpread |= fluidSection2.getFluidId(x, y - 1, z) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockChunk.getBlock(x, y - 1, z)));
}
}
if (!canSpread) {
blockSection.setTicking(idx, false);
continue;
}
}
blockSection.setTicking(idx, true);
}
}
}
}
}
}
int tickingBlocks = blockChunk.getTickingBlocksCount();
if (tickingBlocks != 0) {
PreprocesorAccessor accessor = new PreprocesorAccessor(wc, blockChunk, sections);
do {
blockChunk.preTick(Instant.MIN);
for(int i = 0; i < sections.length; ++i) {
Holder<ChunkStore> section = sections[i];
FluidSection fluidSection = (FluidSection)section.getComponent(FluidSection.getComponentType());
if (fluidSection != null && !fluidSection.isEmpty()) {
BlockSection blockSection = (BlockSection)section.ensureAndGetComponent(BlockSection.getComponentType());
fluidSection.preload(wc.getX(), i, wc.getZ());
accessor.blockSection = blockSection;
blockSection.forEachTicking(accessor, fluidSection, i, (preprocesorAccessor, fluidSection1, xx, yx, zx, block) -> {
int fluidId = fluidSection1.getFluidId(xx, yx, zx);
if (fluidId == 0) {
return BlockTickStrategy.IGNORED;
} else {
Fluid fluid = (Fluid)Fluid.getAssetMap().getAsset(fluidId);
int blockX = fluidSection1.getX() << 5 | xx;
int blockZ = fluidSection1.getZ() << 5 | zx;
return fluid.getTicker().process(preprocesorAccessor.worldChunk.getWorld(), preprocesorAccessor.tick, preprocesorAccessor, fluidSection1, accessor.blockSection, fluid, fluidId, blockX, yx, blockZ);
}
});
}
}
tickingBlocks = blockChunk.getTickingBlocksCount();
++accessor.tick;
} while(tickingBlocks != 0 && accessor.tick <= 100L);
blockChunk.mergeTickingBlocks();
}
}
}
}
}
}
public static class PreprocesorAccessor implements FluidTicker.Accessor {
private final WorldChunk worldChunk;
private final BlockChunk blockChunk;
private final Holder<ChunkStore>[] sections;
public long tick;
public BlockSection blockSection;
public PreprocesorAccessor(WorldChunk worldChunk, BlockChunk blockChunk, Holder<ChunkStore>[] sections) {
this.worldChunk = worldChunk;
this.blockChunk = blockChunk;
this.sections = sections;
}
@Nullable
public FluidSection getFluidSection(int cx, int cy, int cz) {
return this.blockChunk.getX() == cx && this.blockChunk.getZ() == cz && cy >= 0 && cy < this.sections.length ? (FluidSection)this.sections[cy].getComponent(FluidSection.getComponentType()) : null;
}
@Nullable
public BlockSection getBlockSection(int cx, int cy, int cz) {
if (cy >= 0 && cy < 10) {
return this.blockChunk.getX() == cx && this.blockChunk.getZ() == cz ? this.blockChunk.getSectionAtIndex(cy) : null;
} else {
return null;
}
}
public void setBlock(int x, int y, int z, int blockId) {
if (this.worldChunk.getX() == ChunkUtil.chunkCoordinate(x) || this.worldChunk.getZ() == ChunkUtil.chunkCoordinate(z)) {
this.worldChunk.setBlock(x, y, z, blockId, 157);
}
}
}
}