package com.hypixel.hytale.server.core.modules;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
import com.hypixel.hytale.codec.store.StoredCodec;
import com.hypixel.hytale.common.plugin.PluginManifest;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.component.Component;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.component.Holder;
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.logger.HytaleLogger;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.server.core.modules.migrations.ChunkColumnMigrationSystem;
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.BlockComponentChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.ChunkColumn;
import com.hypixel.hytale.server.core.universe.world.chunk.EntityChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.environment.EnvironmentChunk;
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.chunk.section.blockpositions.BlockPositionProvider;
import com.hypixel.hytale.server.core.universe.world.chunk.systems.ChunkSystems;
import com.hypixel.hytale.server.core.universe.world.meta.BlockState;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.Set;
import java.util.logging.Level;
import javax.annotation.Nonnull;
public class LegacyModule extends JavaPlugin {
public static final PluginManifest MANIFEST = PluginManifest.corePlugin(LegacyModule.class).build();
private static LegacyModule instance;
private ComponentType<ChunkStore, WorldChunk> worldChunkComponentType;
private ComponentType<ChunkStore, BlockChunk> blockChunkComponentType;
private ComponentType<ChunkStore, EntityChunk> entityChunkComponentType;
private ComponentType<ChunkStore, BlockComponentChunk> blockComponentChunkComponentType;
private ComponentType<ChunkStore, EnvironmentChunk> environmentChunkComponentType;
private ComponentType<ChunkStore, ChunkColumn> chunkColumnComponentType;
private ComponentType<ChunkStore, ChunkSection> chunkSectionComponentType;
private ComponentType<ChunkStore, BlockSection> blockSectionComponentType;
private ComponentType<ChunkStore, FluidSection> fluidSectionComponentType;
private ComponentType<ChunkStore, BlockPositionProvider> blockPositionProviderComponentType;
public static LegacyModule get() {
return instance;
}
public LegacyModule(@Nonnull JavaPluginInit init) {
super(init);
instance = this;
}
protected void setup() {
this.worldChunkComponentType = this.getChunkStoreRegistry().registerComponent(WorldChunk.class, "WorldChunk", WorldChunk.CODEC);
this.blockChunkComponentType = this.getChunkStoreRegistry().registerComponent(BlockChunk.class, "BlockChunk", BlockChunk.CODEC);
this.entityChunkComponentType = this.getChunkStoreRegistry().registerComponent(EntityChunk.class, "EntityChunk", EntityChunk.CODEC);
this.blockComponentChunkComponentType = this.getChunkStoreRegistry().registerComponent(BlockComponentChunk.class, "BlockComponentChunk", BlockComponentChunk.CODEC);
this.environmentChunkComponentType = this.getChunkStoreRegistry().registerComponent(EnvironmentChunk.class, "EnvironmentChunk", EnvironmentChunk.CODEC);
this.chunkColumnComponentType = this.getChunkStoreRegistry().registerComponent(ChunkColumn.class, "ChunkColumn", ChunkColumn.CODEC);
this.chunkSectionComponentType = this.getChunkStoreRegistry().registerComponent(ChunkSection.class, "ChunkSection", ChunkSection.CODEC);
this.blockSectionComponentType = this.getChunkStoreRegistry().registerComponent(BlockSection.class, "Block", BlockSection.CODEC);
this.fluidSectionComponentType = this.getChunkStoreRegistry().registerComponent(FluidSection.class, "Fluid", FluidSection.CODEC);
this.blockPositionProviderComponentType = this.getChunkStoreRegistry().registerComponent(BlockPositionProvider.class, () -> {
throw new UnsupportedOperationException("BlockPositionProvider cannot be constructed");
});
this.getChunkStoreRegistry().registerSystem(new ChunkSystems.OnNewChunk());
this.getChunkStoreRegistry().registerSystem(new ChunkSystems.OnChunkLoad());
this.getChunkStoreRegistry().registerSystem(new ChunkSystems.OnNonTicking());
this.getChunkStoreRegistry().registerSystem(new ChunkSystems.EnsureBlockSection());
this.getChunkStoreRegistry().registerSystem(new MigrateLegacySections());
this.getChunkStoreRegistry().registerSystem(new ChunkSystems.LoadBlockSection());
this.getChunkStoreRegistry().registerSystem(new ChunkSystems.ReplicateChanges());
this.getChunkStoreRegistry().registerSystem(new BlockChunk.LoadBlockChunkPacketSystem(this.blockChunkComponentType));
this.getChunkStoreRegistry().registerSystem(new EntityChunk.EntityChunkLoadingSystem());
this.getChunkStoreRegistry().registerSystem(new BlockComponentChunk.BlockComponentChunkLoadingSystem());
this.getChunkStoreRegistry().registerSystem(new BlockComponentChunk.LoadBlockComponentPacketSystem(this.blockComponentChunkComponentType));
this.getChunkStoreRegistry().registerSystem(new BlockComponentChunk.UnloadBlockComponentPacketSystem(this.blockComponentChunkComponentType));
ComponentType<ChunkStore, LegacyBlockStateChunk> legacyBlockStateComponentType = this.getChunkStoreRegistry().registerComponent(LegacyBlockStateChunk.class, "BlockStateChunk", LegacyModule.LegacyBlockStateChunk.CODEC, true);
this.getChunkStoreRegistry().registerSystem(new MigrateLegacyBlockStateChunkSystem(legacyBlockStateComponentType, this.blockComponentChunkComponentType));
}
public ComponentType<ChunkStore, WorldChunk> getWorldChunkComponentType() {
return this.worldChunkComponentType;
}
public ComponentType<ChunkStore, BlockChunk> getBlockChunkComponentType() {
return this.blockChunkComponentType;
}
public ComponentType<ChunkStore, EntityChunk> getEntityChunkComponentType() {
return this.entityChunkComponentType;
}
public ComponentType<ChunkStore, BlockComponentChunk> getBlockComponentChunkComponentType() {
return this.blockComponentChunkComponentType;
}
public ComponentType<ChunkStore, EnvironmentChunk> getEnvironmentChunkComponentType() {
return this.environmentChunkComponentType;
}
public ComponentType<ChunkStore, ChunkColumn> getChunkColumnComponentType() {
return this.chunkColumnComponentType;
}
public ComponentType<ChunkStore, ChunkSection> getChunkSectionComponentType() {
return this.chunkSectionComponentType;
}
public ComponentType<ChunkStore, BlockSection> getBlockSectionComponentType() {
return this.blockSectionComponentType;
}
public ComponentType<ChunkStore, FluidSection> getFluidSectionComponentType() {
return this.fluidSectionComponentType;
}
public ComponentType<ChunkStore, BlockPositionProvider> getBlockPositionProviderComponentType() {
return this.blockPositionProviderComponentType;
}
private static class LegacyBlockStateChunk implements Component<ChunkStore> {
public static final BuilderCodec<LegacyBlockStateChunk> CODEC;
public Holder<ChunkStore>[] holders;
public LegacyBlockStateChunk() {
}
public LegacyBlockStateChunk(Holder<ChunkStore>[] holders) {
this.holders = holders;
}
@Nonnull
public Component<ChunkStore> clone() {
Holder<ChunkStore>[] newHolders = new Holder[this.holders.length];
for(int i = 0; i < this.holders.length; ++i) {
newHolders[i] = this.holders[i].clone();
}
return new LegacyBlockStateChunk(newHolders);
}
static {
CODEC = ((BuilderCodec.Builder)BuilderCodec.builder(LegacyBlockStateChunk.class, LegacyBlockStateChunk::new).addField(new KeyedCodec("States", new ArrayCodec(new StoredCodec(ChunkStore.HOLDER_CODEC_KEY), (x$0) -> new Holder[x$0])), (entityChunk, array) -> entityChunk.holders = array, (entityChunk) -> {
throw new UnsupportedOperationException("Serialise is not allowed for BlockStateChunk");
})).build();
}
}
@Deprecated(
forRemoval = true
)
public static class MigrateLegacySections extends ChunkColumnMigrationSystem {
private final Query<ChunkStore> QUERY = Query.<ChunkStore>and(ChunkColumn.getComponentType(), BlockChunk.getComponentType());
private final Set<Dependency<ChunkStore>> DEPENDENCIES;
public MigrateLegacySections() {
this.DEPENDENCIES = Set.of(new SystemDependency(Order.AFTER, ChunkSystems.OnNewChunk.class), RootDependency.first());
}
public void onEntityAdd(@Nonnull Holder<ChunkStore> holder, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store) {
ChunkColumn column = (ChunkColumn)holder.getComponent(ChunkColumn.getComponentType());
assert column != null;
BlockChunk blockChunk = (BlockChunk)holder.getComponent(BlockChunk.getComponentType());
assert blockChunk != null;
Holder<ChunkStore>[] sections = column.getSectionHolders();
BlockSection[] migratedSections = blockChunk.takeMigratedSections();
if (migratedSections != null) {
for(int i = 0; i < sections.length; ++i) {
Holder<ChunkStore> section = sections[i];
BlockSection blockSection = migratedSections[i];
if (section != null && blockSection != null) {
section.putComponent(BlockSection.getComponentType(), blockSection);
blockChunk.markNeedsSaving();
}
}
}
}
public void onEntityRemoved(@Nonnull Holder<ChunkStore> holder, @Nonnull RemoveReason reason, @Nonnull Store<ChunkStore> store) {
}
@Nonnull
public Query<ChunkStore> getQuery() {
return this.QUERY;
}
@Nonnull
public Set<Dependency<ChunkStore>> getDependencies() {
return this.DEPENDENCIES;
}
}
private static class MigrateLegacyBlockStateChunkSystem extends ChunkColumnMigrationSystem {
private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
private final ComponentType<ChunkStore, LegacyBlockStateChunk> legacyComponentType;
private final ComponentType<ChunkStore, BlockComponentChunk> componentType;
private final Archetype<ChunkStore> archetype;
public MigrateLegacyBlockStateChunkSystem(ComponentType<ChunkStore, LegacyBlockStateChunk> legacyComponentType, ComponentType<ChunkStore, BlockComponentChunk> componentType) {
this.legacyComponentType = legacyComponentType;
this.componentType = componentType;
this.archetype = Archetype.of(legacyComponentType, WorldChunk.getComponentType());
}
public Query<ChunkStore> getQuery() {
return this.archetype;
}
public void onEntityAdd(@Nonnull Holder<ChunkStore> holder, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store) {
LegacyBlockStateChunk component = (LegacyBlockStateChunk)holder.getComponent(this.legacyComponentType);
assert component != null;
holder.removeComponent(this.legacyComponentType);
Int2ObjectOpenHashMap<Holder<ChunkStore>> holders = new Int2ObjectOpenHashMap<Holder<ChunkStore>>();
for(Holder<ChunkStore> blockComponentHolder : component.holders) {
BlockState blockState = BlockState.getBlockState(blockComponentHolder);
Vector3i position = blockState.__internal_getPosition();
if (position == null) {
LOGGER.at(Level.SEVERE).log("Skipping migration for BlockState with null position!", blockComponentHolder);
} else {
holders.put(blockState.getIndex(), blockComponentHolder);
}
}
BlockComponentChunk blockComponentChunk = new BlockComponentChunk(holders, new Int2ObjectOpenHashMap());
holder.addComponent(this.componentType, blockComponentChunk);
((WorldChunk)holder.getComponent(WorldChunk.getComponentType())).setBlockComponentChunk(blockComponentChunk);
}
public void onEntityRemoved(@Nonnull Holder<ChunkStore> holder, @Nonnull RemoveReason reason, @Nonnull Store<ChunkStore> store) {
}
@Nonnull
public Set<Dependency<ChunkStore>> getDependencies() {
return RootDependency.firstSet();
}
}
}