HyCodeYourTale
classpublicPriority 3

FluidSystems

com.hypixel.hytale.builtin.fluid.FluidSystems

5

Methods

5

Public Methods

0

Fields

1

Constructors

Constants

Set<Dependency<ChunkStore>>DEPENDENCIES= Set.of(new SystemDependency<>(Order.AFTER, FluidSystems.MigrateFromColumn.class))
Set<Dependency<ChunkStore>>DEPENDENCIES= Set.of( new SystemDependency<>(Order.AFTER, ChunkBlockTickSystem.PreTick.class), new Sys...
HytaleLoggerLOGGER= HytaleLogger.forEnclosingClass()
intMAX_CHANGES_PER_PACKET= 1024
Query<ChunkStore>QUERY= Query.and(ChunkSection.getComponentType(), FluidSection.getComponentType())
Query<ChunkStore>QUERY= Query.and(ChunkSection.getComponentType(), FluidSection.getComponentType())
Query<ChunkStore>QUERY= Query.and(ChunkSection.getComponentType(), Query.not(FluidSection.getComponentType()))
Query<ChunkStore>QUERY= Query.and(FluidSection.getComponentType(), ChunkSection.getComponentType())

Constructors

public
FluidSystems()

Methods

Public Methods (5)

public
Set<Dependency<ChunkStore>> getDependencies()
@Nonnull@Override
public
Query<ChunkStore> getQuery()
@Nonnull@Override
public
boolean isParallel(int archetypeChunkSize, int taskCount)
@Override
public
void onEntityAdd(Holder<ChunkStore> holder, AddReason reason, Store<ChunkStore> store)
@Override
public
void onEntityRemoved(Holder<ChunkStore> holder, RemoveReason reason, Store<ChunkStore> store)
@Override

Related Classes

Source Code

package com.hypixel.hytale.builtin.fluid;

import com.hypixel.hytale.builtin.blocktick.system.ChunkBlockTickSystem;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.RemoveReason;
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.RootDependency;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.system.HolderSystem;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.component.system.tick.RunWhenPausedSystem;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.packets.world.ServerSetFluid;
import com.hypixel.hytale.protocol.packets.world.ServerSetFluids;
import com.hypixel.hytale.protocol.packets.world.SetFluidCmd;
import com.hypixel.hytale.server.core.asset.type.blocktick.BlockTickStrategy;
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.modules.LegacyModule;
import com.hypixel.hytale.server.core.modules.entity.player.ChunkTracker;
import com.hypixel.hytale.server.core.modules.migrations.ChunkColumnMigrationSystem;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.World;
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.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 it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.logging.Level;
import javax.annotation.Nonnull;

public class FluidSystems {
   @Nonnull
   private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   private static final int MAX_CHANGES_PER_PACKET = 1024;

   public FluidSystems() {
   }

   public static class EnsureFluidSection extends HolderSystem<ChunkStore> {
      @Nonnull
      private static final Query<ChunkStore> QUERY = Query.and(ChunkSection.getComponentType(), Query.not(FluidSection.getComponentType()));

      public EnsureFluidSection() {
      }

      @Override
      public void onEntityAdd(@Nonnull Holder<ChunkStore> holder, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store) {
         holder.addComponent(FluidSection.getComponentType(), new FluidSection());
      }

      @Override
      public void onEntityRemoved(@Nonnull Holder<ChunkStore> holder, @Nonnull RemoveReason reason, @Nonnull Store<ChunkStore> store) {
      }

      @Nonnull
      @Override
      public Query<ChunkStore> getQuery() {
         return QUERY;
      }

      @Nonnull
      @Override
      public Set<Dependency<ChunkStore>> getDependencies() {
         return RootDependency.firstSet();
      }
   }

   public static class LoadPacketGenerator extends ChunkStore.LoadFuturePacketDataQuerySystem {
      public LoadPacketGenerator() {
      }

      public void fetch(
         int index,
         @Nonnull ArchetypeChunk<ChunkStore> archetypeChunk,
         Store<ChunkStore> store,
         @Nonnull CommandBuffer<ChunkStore> commandBuffer,
         PlayerRef query,
         @Nonnull List<CompletableFuture<Packet>> results
      ) {
         ChunkColumn chunkColumnComponent = archetypeChunk.getComponent(index, ChunkColumn.getComponentType());

         assert chunkColumnComponent != null;

         for (Ref<ChunkStore> sectionRef : chunkColumnComponent.getSections()) {
            FluidSection fluidSectionComponent = commandBuffer.getComponent(sectionRef, FluidSection.getComponentType());
            if (fluidSectionComponent != null) {
               results.add(fluidSectionComponent.getCachedPacket().exceptionally(throwable -> {
                  if (throwable != null) {
                     ((HytaleLogger.Api)FluidSystems.LOGGER.at(Level.SEVERE).withCause(throwable)).log("Exception when compressing chunk fluids:");
                  }

                  return null;
               }).thenApply(Function.identity()));
            }
         }
      }

      @Override
      public Query<ChunkStore> getQuery() {
         return ChunkColumn.getComponentType();
      }
   }

   public static class MigrateFromColumn extends ChunkColumnMigrationSystem {
      @Nonnull
      private final Query<ChunkStore> QUERY = Query.and(ChunkColumn.getComponentType(), BlockChunk.getComponentType());
      @Nonnull
      private final Set<Dependency<ChunkStore>> DEPENDENCIES = Set.of(new SystemDependency<>(Order.BEFORE, LegacyModule.MigrateLegacySections.class));

      public MigrateFromColumn() {
      }

      @Override
      public void onEntityAdd(@Nonnull Holder<ChunkStore> holder, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store) {
         ChunkColumn chunkColumnComponent = holder.getComponent(ChunkColumn.getComponentType());

         assert chunkColumnComponent != null;

         BlockChunk blockChunkComponent = holder.getComponent(BlockChunk.getComponentType());

         assert blockChunkComponent != null;

         Holder<ChunkStore>[] sections = chunkColumnComponent.getSectionHolders();
         BlockSection[] legacySections = blockChunkComponent.getMigratedSections();
         if (legacySections != null) {
            for (int i = 0; i < sections.length; i++) {
               Holder<ChunkStore> section = sections[i];
               BlockSection paletteSection = legacySections[i];
               if (section != null && paletteSection != null) {
                  FluidSection fluid = paletteSection.takeMigratedFluid();
                  if (fluid != null) {
                     section.putComponent(FluidSection.getComponentType(), fluid);
                     blockChunkComponent.markNeedsSaving();
                  }
               }
            }
         }
      }

      @Override
      public void onEntityRemoved(@Nonnull Holder<ChunkStore> holder, @Nonnull RemoveReason reason, @Nonnull Store<ChunkStore> store) {
      }

      @Nonnull
      @Override
      public Query<ChunkStore> getQuery() {
         return this.QUERY;
      }

      @Nonnull
      @Override
      public Set<Dependency<ChunkStore>> getDependencies() {
         return this.DEPENDENCIES;
      }
   }

   public static class ReplicateChanges extends EntityTickingSystem<ChunkStore> implements RunWhenPausedSystem<ChunkStore> {
      @Nonnull
      private static final Query<ChunkStore> QUERY = Query.and(ChunkSection.getComponentType(), FluidSection.getComponentType());

      public ReplicateChanges() {
      }

      @Override
      public boolean isParallel(int archetypeChunkSize, int taskCount) {
         return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
      }

      @Override
      public void tick(
         float dt,
         int index,
         @Nonnull ArchetypeChunk<ChunkStore> archetypeChunk,
         @Nonnull Store<ChunkStore> store,
         @Nonnull CommandBuffer<ChunkStore> commandBuffer
      ) {
         FluidSection fluidSectionComponent = archetypeChunk.getComponent(index, FluidSection.getComponentType());

         assert fluidSectionComponent != null;

         IntOpenHashSet changes = fluidSectionComponent.getAndClearChangedPositions();
         if (!changes.isEmpty()) {
            ChunkSection chunkSectionComponent = archetypeChunk.getComponent(index, ChunkSection.getComponentType());

            assert chunkSectionComponent != null;

            World world = commandBuffer.getExternalData().getWorld();
            WorldChunk worldChunkComponent = commandBuffer.getComponent(chunkSectionComponent.getChunkColumnReference(), WorldChunk.getComponentType());
            int sectionY = chunkSectionComponent.getY();
            world.execute(() -> {
               if (worldChunkComponent != null && worldChunkComponent.getWorld() != null) {
                  worldChunkComponent.getWorld().getChunkLighting().invalidateLightInChunkSection(worldChunkComponent, sectionY);
               }
            });
            Collection<PlayerRef> playerRefs = store.getExternalData().getWorld().getPlayerRefs();
            if (playerRefs.isEmpty()) {
               changes.clear();
            } else {
               long chunkIndex = ChunkUtil.indexChunk(fluidSectionComponent.getX(), fluidSectionComponent.getZ());
               if (changes.size() >= 1024) {
                  ObjectArrayList<PlayerRef> playersCopy = new ObjectArrayList(playerRefs);
                  fluidSectionComponent.getCachedPacket().whenComplete((packetx, throwable) -> {
                     if (throwable != null) {
                        ((HytaleLogger.Api)FluidSystems.LOGGER.at(Level.SEVERE).withCause(throwable)).log("Exception when compressing chunk fluids:");
                     } else {
                        Iterator i$ = playersCopy.iterator();

                        while (i$.hasNext()) {
                           PlayerRef playerRefx = (PlayerRef)i$.next();
                           Ref<EntityStore> refx = playerRefx.getReference();
                           if (refx != null && refx.isValid()) {
                              ChunkTracker trackerx = playerRefx.getChunkTracker();
                              if (trackerx.isLoaded(chunkIndex)) {
                                 playerRefx.getPacketHandler().writeNoCache(packetx);
                              }
                           }
                        }
                     }
                  });
                  changes.clear();
               } else {
                  if (changes.size() == 1) {
                     int change = changes.iterator().nextInt();
                     int x = ChunkUtil.minBlock(fluidSectionComponent.getX()) + ChunkUtil.xFromIndex(change);
                     int y = ChunkUtil.minBlock(fluidSectionComponent.getY()) + ChunkUtil.yFromIndex(change);
                     int z = ChunkUtil.minBlock(fluidSectionComponent.getZ()) + ChunkUtil.zFromIndex(change);
                     int fluid = fluidSectionComponent.getFluidId(change);
                     byte level = fluidSectionComponent.getFluidLevel(change);
                     ServerSetFluid packet = new ServerSetFluid(x, y, z, fluid, level);

                     for (PlayerRef playerRef : playerRefs) {
                        Ref<EntityStore> ref = playerRef.getReference();
                        if (ref != null && ref.isValid()) {
                           ChunkTracker tracker = playerRef.getChunkTracker();
                           if (tracker.isLoaded(chunkIndex)) {
                              playerRef.getPacketHandler().writeNoCache(packet);
                           }
                        }
                     }
                  } else {
                     SetFluidCmd[] cmds = new SetFluidCmd[changes.size()];
                     IntIterator iter = changes.intIterator();
                     int i = 0;

                     while (iter.hasNext()) {
                        int change = iter.nextInt();
                        int fluid = fluidSectionComponent.getFluidId(change);
                        byte level = fluidSectionComponent.getFluidLevel(change);
                        cmds[i++] = new SetFluidCmd((short)change, fluid, level);
                     }

                     ServerSetFluids packet = new ServerSetFluids(
                        fluidSectionComponent.getX(), fluidSectionComponent.getY(), fluidSectionComponent.getZ(), cmds
                     );

                     for (PlayerRef playerRefx : playerRefs) {
                        Ref<EntityStore> ref = playerRefx.getReference();
                        if (ref != null && ref.isValid()) {
                           ChunkTracker tracker = playerRefx.getChunkTracker();
                           if (tracker.isLoaded(chunkIndex)) {
                              playerRefx.getPacketHandler().writeNoCache(packet);
                           }
                        }
                     }
                  }

                  changes.clear();
               }
            }
         }
      }

      @Nonnull
      @Override
      public Query<ChunkStore> getQuery() {
         return QUERY;
      }

      @Nonnull
      @Override
      public Set<Dependency<ChunkStore>> getDependencies() {
         return RootDependency.lastSet();
      }
   }

   public static class SetupSection extends HolderSystem<ChunkStore> {
      @Nonnull
      private static final Query<ChunkStore> QUERY = Query.and(ChunkSection.getComponentType(), FluidSection.getComponentType());
      @Nonnull
      private static final Set<Dependency<ChunkStore>> DEPENDENCIES = Set.of(new SystemDependency<>(Order.AFTER, FluidSystems.MigrateFromColumn.class));

      public SetupSection() {
      }

      @Override
      public void onEntityAdd(@Nonnull Holder<ChunkStore> holder, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store) {
         ChunkSection chunkSectionComponent = holder.getComponent(ChunkSection.getComponentType());

         assert chunkSectionComponent != null;

         FluidSection fluidSectionComponent = holder.getComponent(FluidSection.getComponentType());

         assert fluidSectionComponent != null;

         fluidSectionComponent.load(chunkSectionComponent.getX(), chunkSectionComponent.getY(), chunkSectionComponent.getZ());
      }

      @Override
      public void onEntityRemoved(@Nonnull Holder<ChunkStore> holder, @Nonnull RemoveReason reason, @Nonnull Store<ChunkStore> store) {
      }

      @Nonnull
      @Override
      public Query<ChunkStore> getQuery() {
         return QUERY;
      }

      @Nonnull
      @Override
      public Set<Dependency<ChunkStore>> getDependencies() {
         return DEPENDENCIES;
      }
   }

   public static class Ticking extends EntityTickingSystem<ChunkStore> {
      @Nonnull
      private static final Query<ChunkStore> QUERY = Query.and(FluidSection.getComponentType(), ChunkSection.getComponentType());
      @Nonnull
      private static final Set<Dependency<ChunkStore>> DEPENDENCIES = Set.of(
         new SystemDependency<>(Order.AFTER, ChunkBlockTickSystem.PreTick.class), new SystemDependency<>(Order.BEFORE, ChunkBlockTickSystem.Ticking.class)
      );

      public Ticking() {
      }

      @Override
      public boolean isParallel(int archetypeChunkSize, int taskCount) {
         return EntityTickingSystem.useParallel(archetypeChunkSize, taskCount);
      }

      @Override
      public void tick(
         float dt,
         int index,
         @Nonnull ArchetypeChunk<ChunkStore> archetypeChunk,
         @Nonnull Store<ChunkStore> store,
         @Nonnull CommandBuffer<ChunkStore> commandBuffer
      ) {
         ChunkSection chunkSectionComponent = archetypeChunk.getComponent(index, ChunkSection.getComponentType());

         assert chunkSectionComponent != null;

         FluidSection fluidSectionComponent = archetypeChunk.getComponent(index, FluidSection.getComponentType());

         assert fluidSectionComponent != null;

         Ref<ChunkStore> chunkRef = chunkSectionComponent.getChunkColumnReference();
         BlockChunk blockChunkComponent = commandBuffer.getComponent(chunkRef, BlockChunk.getComponentType());

         assert blockChunkComponent != null;

         BlockSection blockSection = blockChunkComponent.getSectionAtIndex(fluidSectionComponent.getY());
         if (blockSection != null) {
            if (blockSection.getTickingBlocksCountCopy() != 0) {
               FluidTicker.CachedAccessor accessor = FluidTicker.CachedAccessor.of(commandBuffer, fluidSectionComponent, blockSection, 5);
               blockSection.forEachTicking(accessor, commandBuffer, fluidSectionComponent.getY(), (accessor1, commandBuffer1, x, y, z, block) -> {
                  FluidSection fluidSection1 = accessor1.selfFluidSection;
                  BlockSection blockSection1 = accessor1.selfBlockSection;
                  int fluidId = fluidSection1.getFluidId(x, y, z);
                  if (fluidId == 0) {
                     return BlockTickStrategy.IGNORED;
                  } else {
                     Fluid fluid = Fluid.getAssetMap().getAsset(fluidId);
                     int blockX = fluidSection1.getX() << 5 | x;
                     int blockZ = fluidSection1.getZ() << 5 | z;
                     return fluid.getTicker().tick(commandBuffer1, accessor1, fluidSection1, blockSection1, fluid, fluidId, blockX, y, blockZ);
                  }
               });
            }
         }
      }

      @Nonnull
      @Override
      public Query<ChunkStore> getQuery() {
         return QUERY;
      }

      @Nonnull
      @Override
      public Set<Dependency<ChunkStore>> getDependencies() {
         return DEPENDENCIES;
      }
   }
}