package com.hypixel.hytale.builtin.buildertools.scriptedbrushes; import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap; import com.hypixel.hytale.builtin.buildertools.BuilderToolsPlugin; import com.hypixel.hytale.builtin.buildertools.utils.Material; import com.hypixel.hytale.math.block.BlockUtil; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.prefab.selection.mask.BlockMask; import com.hypixel.hytale.server.core.prefab.selection.standard.BlockSelection; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntMaps; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2IntMap.Entry; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectIterator; import javax.annotation.Nonnull; public class BrushConfigEditStore { @Nonnull private final BrushConfig brushConfig; @Nonnull private final BrushConfigChunkAccessor accessor; @Nonnull private final BlockSelection before; @Nonnull private final BlockSelection previous; private BlockSelection current; private final LongOpenHashSet packedPlacedBlockPositions; public BrushConfigEditStore(LongOpenHashSet packedPlacedBlockPositions, @Nonnull BrushConfig brushConfig, World world) { this.brushConfig = brushConfig; this.packedPlacedBlockPositions = packedPlacedBlockPositions; Vector3i origin = brushConfig.getOrigin(); int shapeWidth = brushConfig.getShapeWidth(); int shapeHeight = brushConfig.getShapeHeight(); int halfWidth = shapeWidth / 2; int halfHeight = shapeHeight / 2; this.accessor = BrushConfigChunkAccessor.atWorldCoords(this, world, origin.x, origin.z, shapeWidth * 2); this.before = new BlockSelection(); this.before.setPosition(origin.x, origin.y, origin.z); this.before .setSelectionArea( new Vector3i(origin.x - halfWidth, origin.y - halfHeight, origin.z - halfWidth), new Vector3i(origin.x + halfWidth, origin.y + halfHeight, origin.z + halfWidth) ); this.previous = new BlockSelection(this.before); this.current = new BlockSelection(this.before); } @Nonnull public BrushConfigChunkAccessor getAccessor() { return this.accessor; } public int getOriginalBlock(int x, int y, int z) { return this.accessor.getBlockIgnoringHistory(x, y, z); } public int getBlock(int x, int y, int z) { return this.previous.hasBlockAtWorldPos(x, y, z) ? this.previous.getBlockAtWorldPos(x, y, z) : this.getOriginalBlock(x, y, z); } public int getBlockIncludingCurrent(int x, int y, int z) { return this.current.hasBlockAtWorldPos(x, y, z) ? this.current.getBlockAtWorldPos(x, y, z) : this.getBlock(x, y, z); } public boolean setBlock(int x, int y, int z, int blockId) { boolean hasHistory = this.previous.hasBlockAtWorldPos(x, y, z) || this.previous.getFluidAtWorldPos(x, y, z) >= 0; switch (this.brushConfig.getHistoryMask()) { case Only: if (!hasHistory) { return false; } break; case Not: if (hasHistory) { return false; } } if (this.brushConfig.getRandom().nextInt(100) >= this.brushConfig.getDensity()) { return false; } else { if (this.getOriginalBlock(x, y, z) == 0) { this.packedPlacedBlockPositions.add(BlockUtil.pack(x, y, z)); } int currentBlock = this.getBlock(x, y, z); int currentFluid = this.getFluid(x, y, z); BlockMask blockMask = this.brushConfig.getBlockMask(); if (blockMask != null && blockMask.isExcluded(this.accessor, x, y, z, null, null, currentBlock, currentFluid)) { return false; } else { if (!this.before.hasBlockAtWorldPos(x, y, z)) { WorldChunk blocks = this.accessor.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(x, z)); if (blocks != null) { this.before .addBlockAtWorldPos( x, y, z, currentBlock, blocks.getRotationIndex(x, y, z), blocks.getFiller(x, y, z), blocks.getSupportValue(x, y, z), blocks.getBlockComponentHolder(x, y, z) ); } } this.current.addBlockAtWorldPos(x, y, z, blockId, 0, 0, 0); return true; } } } private boolean setFluid(int x, int y, int z, int fluidId, byte fluidLevel) { boolean hasHistory = this.previous.hasBlockAtWorldPos(x, y, z) || this.previous.getFluidAtWorldPos(x, y, z) >= 0; switch (this.brushConfig.getHistoryMask()) { case Only: if (!hasHistory) { return false; } break; case Not: if (hasHistory) { return false; } } if (this.brushConfig.getRandom().nextInt(100) >= this.brushConfig.getDensity()) { return false; } else { int currentBlock = this.getBlock(x, y, z); int currentFluid = this.getFluid(x, y, z); BlockMask blockMask = this.brushConfig.getBlockMask(); if (blockMask != null && blockMask.isExcluded(this.accessor, x, y, z, null, null, currentBlock, currentFluid)) { return false; } else { int beforeFluid = this.before.getFluidAtWorldPos(x, y, z); if (beforeFluid < 0) { WorldChunk chunk = this.accessor.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(x, z)); if (chunk != null) { int originalFluidId = chunk.getFluidId(x, y, z); byte originalFluidLevel = chunk.getFluidLevel(x, y, z); this.before.addFluidAtWorldPos(x, y, z, originalFluidId, originalFluidLevel); } } this.current.addFluidAtWorldPos(x, y, z, fluidId, fluidLevel); return true; } } } private int getOriginalFluid(int x, int y, int z) { WorldChunk chunk = this.accessor.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(x, z)); return chunk != null ? chunk.getFluidId(x, y, z) : 0; } public int getFluid(int x, int y, int z) { int previousFluid = this.previous.getFluidAtWorldPos(x, y, z); return previousFluid >= 0 ? previousFluid : this.getOriginalFluid(x, y, z); } public boolean setMaterial(int x, int y, int z, @Nonnull Material material) { if (material.isFluid()) { return this.setFluid(x, y, z, material.getFluidId(), material.getFluidLevel()); } else { boolean result = this.setBlock(x, y, z, material.getBlockId()); if (result && material.isEmpty()) { this.setFluid(x, y, z, 0, (byte)0); } return result; } } @Nonnull public BuilderToolsPlugin.BuilderState.BlocksSampleData getBlockSampledataIncludingPreviousStages(int x, int y, int z, int radius) { BuilderToolsPlugin.BuilderState.BlocksSampleData data = new BuilderToolsPlugin.BuilderState.BlocksSampleData(); Int2IntMap blockCounts = new Int2IntOpenHashMap(); for (int ix = x - radius; ix <= x + radius; ix++) { for (int iz = z - radius; iz <= z + radius; iz++) { for (int iy = y - radius; iy <= y + radius; iy++) { int currentBlock = this.getBlock(ix, iy, iz); blockCounts.put(currentBlock, blockCounts.getOrDefault(currentBlock, 0) + 1); } } } BlockTypeAssetMap assetMap = BlockType.getAssetMap(); ObjectIterator var14 = Int2IntMaps.fastIterable(blockCounts).iterator(); while (var14.hasNext()) { Entry pair = (Entry)var14.next(); int block = pair.getIntKey(); int count = pair.getIntValue(); if (count > data.mainBlockCount) { data.mainBlock = block; data.mainBlockCount = count; } BlockType blockType = assetMap.getAsset(block); if (count > data.mainBlockNotAirCount && block != 0) { data.mainBlockNotAir = block; data.mainBlockNotAirCount = count; } } return data; } public void flushCurrentEditsToPrevious() { this.previous.add(this.current); this.current = new BlockSelection(); this.current.setPosition(this.brushConfig.getOrigin().x, this.brushConfig.getOrigin().y, this.brushConfig.getOrigin().z); } @Nonnull public BlockSelection getAfter() { return this.previous; } @Nonnull public BlockSelection getBefore() { return this.before; } }