hytale-server/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerPlugin.java

199 lines
9.7 KiB
Java

package com.hypixel.hytale.builtin.blockspawner;
import com.hypixel.hytale.assetstore.AssetRegistry;
import com.hypixel.hytale.assetstore.map.DefaultAssetMap;
import com.hypixel.hytale.builtin.blockspawner.command.BlockSpawnerCommand;
import com.hypixel.hytale.builtin.blockspawner.state.BlockSpawner;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ComponentType;
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.data.unknown.UnknownComponents;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.system.RefSystem;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.math.Axis;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.util.HashUtil;
import com.hypixel.hytale.protocol.GameMode;
import com.hypixel.hytale.server.core.asset.HytaleAssetStore;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.Rotation;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.VariantRotation;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import com.hypixel.hytale.server.core.modules.block.BlockModule;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.hypixel.hytale.server.core.universe.world.WorldConfig;
import com.hypixel.hytale.server.core.universe.world.chunk.BlockRotationUtil;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class BlockSpawnerPlugin extends JavaPlugin {
private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
private ComponentType<ChunkStore, BlockSpawner> blockSpawnerComponentType;
private static BlockSpawnerPlugin INSTANCE;
public static BlockSpawnerPlugin get() {
return INSTANCE;
}
public BlockSpawnerPlugin(@Nonnull JavaPluginInit init) {
super(init);
INSTANCE = this;
}
@Override
protected void setup() {
this.getCommandRegistry().registerCommand(new BlockSpawnerCommand());
AssetRegistry.register(
((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder(
BlockSpawnerTable.class, new DefaultAssetMap()
)
.setPath("Item/Block/Spawners"))
.setCodec(BlockSpawnerTable.CODEC))
.setKeyFunction(BlockSpawnerTable::getId))
.loadsAfter(Item.class, BlockType.class))
.build()
);
this.blockSpawnerComponentType = this.getChunkStoreRegistry().registerComponent(BlockSpawner.class, "BlockSpawner", BlockSpawner.CODEC);
this.getChunkStoreRegistry().registerSystem(new BlockSpawnerPlugin.BlockSpawnerSystem());
this.getChunkStoreRegistry().registerSystem(new BlockSpawnerPlugin.MigrateBlockSpawner());
}
public ComponentType<ChunkStore, BlockSpawner> getBlockSpawnerComponentType() {
return this.blockSpawnerComponentType;
}
private static class BlockSpawnerSystem extends RefSystem<ChunkStore> {
private static final ComponentType<ChunkStore, BlockSpawner> COMPONENT_TYPE = BlockSpawner.getComponentType();
private static final ComponentType<ChunkStore, BlockModule.BlockStateInfo> BLOCK_INFO_COMPONENT_TYPE = BlockModule.BlockStateInfo.getComponentType();
private static final Query<ChunkStore> QUERY = Query.and(COMPONENT_TYPE, BLOCK_INFO_COMPONENT_TYPE);
public BlockSpawnerSystem() {
}
@Override
public Query<ChunkStore> getQuery() {
return QUERY;
}
@Override
public void onEntityAdded(
@Nonnull Ref<ChunkStore> ref, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store, @Nonnull CommandBuffer<ChunkStore> commandBuffer
) {
WorldConfig worldConfig = store.getExternalData().getWorld().getWorldConfig();
if (worldConfig.getGameMode() != GameMode.Creative) {
BlockSpawner state = commandBuffer.getComponent(ref, COMPONENT_TYPE);
assert state != null;
BlockModule.BlockStateInfo info = commandBuffer.getComponent(ref, BLOCK_INFO_COMPONENT_TYPE);
assert info != null;
String blockSpawnerId = state.getBlockSpawnerId();
if (blockSpawnerId != null) {
BlockSpawnerTable table = BlockSpawnerTable.getAssetMap().getAsset(blockSpawnerId);
if (table == null) {
BlockSpawnerPlugin.LOGGER.at(Level.WARNING).log("Failed to find BlockSpawner Asset by name: %s", blockSpawnerId);
} else {
Ref<ChunkStore> chunk = info.getChunkRef();
if (chunk != null) {
WorldChunk wc = commandBuffer.getComponent(chunk, WorldChunk.getComponentType());
int x = ChunkUtil.worldCoordFromLocalCoord(wc.getX(), ChunkUtil.xFromBlockInColumn(info.getIndex()));
int y = ChunkUtil.yFromBlockInColumn(info.getIndex());
int z = ChunkUtil.worldCoordFromLocalCoord(wc.getZ(), ChunkUtil.zFromBlockInColumn(info.getIndex()));
long seed = worldConfig.getSeed();
double randomRnd = HashUtil.random(x, y, z, seed + -1699164769L);
BlockSpawnerEntry entry = table.getEntries().get(randomRnd);
if (entry != null) {
String blockKey = entry.getBlockName();
RotationTuple rotation = switch (entry.getRotationMode()) {
case NONE -> RotationTuple.NONE;
case RANDOM -> {
String key = entry.getBlockName();
VariantRotation variantRotation = BlockType.getAssetMap().getAsset(key).getVariantRotation();
if (variantRotation == VariantRotation.None) {
yield RotationTuple.NONE;
} else {
int randomHash = (int)HashUtil.rehash(x, y, z, seed + -1699164769L);
Rotation rotationYaw = Rotation.NORMAL[(randomHash & 65535) % Rotation.NORMAL.length];
yield BlockRotationUtil.getRotated(RotationTuple.NONE, Axis.Y, rotationYaw, variantRotation);
}
}
case INHERIT -> {
String key = entry.getBlockName();
VariantRotation variantRotation = BlockType.getAssetMap().getAsset(key).getVariantRotation();
if (variantRotation == VariantRotation.None) {
yield RotationTuple.NONE;
} else {
RotationTuple spawnerRotation = RotationTuple.get(wc.getRotationIndex(x, y, z));
Rotation spawnerYaw = spawnerRotation.yaw();
yield BlockRotationUtil.getRotated(RotationTuple.NONE, Axis.Y, spawnerYaw, variantRotation);
}
}
};
Holder<ChunkStore> holder = entry.getBlockComponents();
commandBuffer.removeEntity(ref, RemoveReason.REMOVE);
commandBuffer.run(_store -> {
int flags = 4;
if (holder != null) {
flags |= 2;
}
int blockId = BlockType.getAssetMap().getIndex(blockKey);
BlockType blockType = BlockType.getAssetMap().getAsset(blockId);
wc.setBlock(x, y, z, blockId, blockType, rotation.index(), 0, flags);
if (holder != null) {
wc.setState(x, y, z, holder.clone());
}
});
}
}
}
}
}
}
@Override
public void onEntityRemove(
@Nonnull Ref<ChunkStore> ref, @Nonnull RemoveReason reason, @Nonnull Store<ChunkStore> store, @Nonnull CommandBuffer<ChunkStore> commandBuffer
) {
}
}
@Deprecated(forRemoval = true)
public static class MigrateBlockSpawner extends BlockModule.MigrationSystem {
@Override
public void onEntityAdd(@Nonnull Holder<ChunkStore> holder, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store) {
UnknownComponents<ChunkStore> unknown = holder.getComponent(ChunkStore.REGISTRY.getUnknownComponentType());
assert unknown != null;
BlockSpawner blockSpawner = unknown.removeComponent("blockspawner", BlockSpawner.CODEC);
if (blockSpawner != null) {
holder.putComponent(BlockSpawner.getComponentType(), blockSpawner);
}
}
@Override
public void onEntityRemoved(@Nonnull Holder<ChunkStore> holder, @Nonnull RemoveReason reason, @Nonnull Store<ChunkStore> store) {
}
@Nullable
@Override
public Query<ChunkStore> getQuery() {
return ChunkStore.REGISTRY.getUnknownComponentType();
}
}
}