diff --git a/_decomp/decomp.ps1 b/_decomp/decomp.ps1 index 439a98f5..8d6f4f46 100644 --- a/_decomp/decomp.ps1 +++ b/_decomp/decomp.ps1 @@ -1,10 +1,12 @@ $ErrorActionPreference = "Stop" +$branch = git rev-parse --abbrev-ref HEAD + # Move to the git root if we arn't already there git rev-parse --show-toplevel | Set-Location # get the server jar from the install directory ( in future support pre-release ) -$server_jar = resolve-path "$env:APPDATA/Hytale/install/release/package/game/latest/Server/HytaleServer.jar" +$server_jar = resolve-path "$env:APPDATA/Hytale/install/$branch/package/game/latest/Server/HytaleServer.jar" # clear the source directory Get-ChildItem -Path "src" | Remove-Item -Recurse -Force -Confirm:$false diff --git a/src/com/hypixel/hytale/builtin/adventure/camera/CameraPlugin.java b/src/com/hypixel/hytale/builtin/adventure/camera/CameraPlugin.java index a922b754..8adb4fc6 100644 --- a/src/com/hypixel/hytale/builtin/adventure/camera/CameraPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/camera/CameraPlugin.java @@ -20,6 +20,7 @@ import com.hypixel.hytale.server.core.plugin.registry.AssetRegistry; import javax.annotation.Nonnull; public class CameraPlugin extends JavaPlugin { + @Nonnull private static final String CODEC_CAMERA_SHAKE = "CameraShake"; public CameraPlugin(@Nonnull JavaPluginInit init) { diff --git a/src/com/hypixel/hytale/builtin/adventure/camera/asset/CameraShakeConfig.java b/src/com/hypixel/hytale/builtin/adventure/camera/asset/CameraShakeConfig.java index c0724030..1f4ec79d 100644 --- a/src/com/hypixel/hytale/builtin/adventure/camera/asset/CameraShakeConfig.java +++ b/src/com/hypixel/hytale/builtin/adventure/camera/asset/CameraShakeConfig.java @@ -9,6 +9,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; public class CameraShakeConfig implements NetworkSerializable { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CameraShakeConfig.class, CameraShakeConfig::new) .appendInherited(new KeyedCodec<>("Duration", Codec.FLOAT), (o, v) -> o.duration = v, o -> o.duration, (o, p) -> o.duration = p.duration) .documentation("The time period that the camera will shake at full intensity for") @@ -73,6 +74,7 @@ public class CameraShakeConfig implements NetworkSerializable { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CameraShakeConfig.OffsetNoise.class, CameraShakeConfig.OffsetNoise::new ) @@ -89,6 +91,7 @@ public class CameraShakeConfig implements NetworkSerializable { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CameraShakeConfig.RotationNoise.class, CameraShakeConfig.RotationNoise::new ) @@ -129,6 +133,7 @@ public class CameraShakeConfig implements NetworkSerializable assetMap, @Nonnull Map assets) { + protected static Packet toCachedPacket( + @Nonnull UpdateType type, @Nonnull IndexedAssetMap assetMap, @Nonnull Map assets + ) { Int2ObjectOpenHashMap profiles = new Int2ObjectOpenHashMap<>(); for (Entry entry : assets.entrySet()) { diff --git a/src/com/hypixel/hytale/builtin/adventure/camera/asset/viewbobbing/ViewBobbingPacketGenerator.java b/src/com/hypixel/hytale/builtin/adventure/camera/asset/viewbobbing/ViewBobbingPacketGenerator.java index dd50293e..82384cad 100644 --- a/src/com/hypixel/hytale/builtin/adventure/camera/asset/viewbobbing/ViewBobbingPacketGenerator.java +++ b/src/com/hypixel/hytale/builtin/adventure/camera/asset/viewbobbing/ViewBobbingPacketGenerator.java @@ -41,7 +41,7 @@ public class ViewBobbingPacketGenerator extends SimpleAssetPacketGenerator assets) { + protected static Packet toCachedPacket(@Nonnull UpdateType type, @Nonnull Map assets) { UpdateViewBobbing packet = new UpdateViewBobbing(); packet.type = type; packet.profiles = new EnumMap<>(MovementType.class); diff --git a/src/com/hypixel/hytale/builtin/adventure/camera/command/CameraEffectCommand.java b/src/com/hypixel/hytale/builtin/adventure/camera/command/CameraEffectCommand.java index c601e877..138a1e5c 100644 --- a/src/com/hypixel/hytale/builtin/adventure/camera/command/CameraEffectCommand.java +++ b/src/com/hypixel/hytale/builtin/adventure/camera/command/CameraEffectCommand.java @@ -80,7 +80,6 @@ public class CameraEffectCommand extends AbstractCommandCollection { } protected static class DebugCommand extends AbstractTargetPlayerCommand { - private static final String MESSAGE_SUCCESS = "server.commands.camshake.debug.success"; @Nonnull protected final RequiredArg effectArg = this.withRequiredArg( "effect", "server.commands.camshake.effect.desc", CameraEffectCommand.CAMERA_EFFECT_ARGUMENT_TYPE diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/FarmingPlugin.java b/src/com/hypixel/hytale/builtin/adventure/farming/FarmingPlugin.java index 6adcf927..34d66899 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/FarmingPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/FarmingPlugin.java @@ -23,6 +23,7 @@ import com.hypixel.hytale.builtin.adventure.farming.states.FarmingBlock; import com.hypixel.hytale.builtin.adventure.farming.states.FarmingBlockState; import com.hypixel.hytale.builtin.adventure.farming.states.TilledSoilBlock; import com.hypixel.hytale.builtin.tagset.config.NPCGroup; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.event.EventPriority; @@ -34,6 +35,7 @@ import com.hypixel.hytale.server.core.asset.type.weather.config.Weather; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; +import com.hypixel.hytale.server.core.plugin.registry.AssetRegistry; import com.hypixel.hytale.server.core.universe.world.chunk.BlockComponentChunk; import com.hypixel.hytale.server.core.universe.world.events.ChunkPreLoadProcessEvent; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; @@ -60,28 +62,29 @@ public class FarmingPlugin extends JavaPlugin { @Override protected void setup() { instance = this; - this.getAssetRegistry() - .register( - ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( - GrowthModifierAsset.class, new DefaultAssetMap() - ) - .setPath("Farming/Modifiers")) - .setCodec(GrowthModifierAsset.CODEC)) - .loadsAfter(Weather.class)) - .setKeyFunction(GrowthModifierAsset::getId)) - .build() - ); - this.getAssetRegistry() - .register( - ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( - FarmingCoopAsset.class, new DefaultAssetMap() - ) - .setPath("Farming/Coops")) - .setCodec(FarmingCoopAsset.CODEC)) - .loadsAfter(ItemDropList.class, NPCGroup.class)) - .setKeyFunction(FarmingCoopAsset::getId)) - .build() - ); + AssetRegistry assetRegistry = this.getAssetRegistry(); + ComponentRegistryProxy chunkStoreRegistry = this.getChunkStoreRegistry(); + ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); + assetRegistry.register( + ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( + GrowthModifierAsset.class, new DefaultAssetMap() + ) + .setPath("Farming/Modifiers")) + .setCodec(GrowthModifierAsset.CODEC)) + .loadsAfter(Weather.class)) + .setKeyFunction(GrowthModifierAsset::getId)) + .build() + ); + assetRegistry.register( + ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( + FarmingCoopAsset.class, new DefaultAssetMap() + ) + .setPath("Farming/Coops")) + .setCodec(FarmingCoopAsset.CODEC)) + .loadsAfter(ItemDropList.class, NPCGroup.class)) + .setKeyFunction(FarmingCoopAsset::getId)) + .build() + ); this.getCodecRegistry(Interaction.CODEC) .register("HarvestCrop", HarvestCropInteraction.class, HarvestCropInteraction.CODEC) .register("FertilizeSoil", FertilizeSoilInteraction.class, FertilizeSoilInteraction.CODEC) @@ -97,23 +100,22 @@ public class FarmingPlugin extends JavaPlugin { this.getCodecRegistry(FarmingStageData.CODEC).register("Prefab", PrefabFarmingStageData.class, PrefabFarmingStageData.CODEC); this.getCodecRegistry(FarmingStageData.CODEC).register("Spread", SpreadFarmingStageData.class, SpreadFarmingStageData.CODEC); this.getCodecRegistry(SpreadGrowthBehaviour.CODEC).register("Directional", DirectionalGrowthBehaviour.class, DirectionalGrowthBehaviour.CODEC); - this.tiledSoilBlockComponentType = this.getChunkStoreRegistry().registerComponent(TilledSoilBlock.class, "TilledSoil", TilledSoilBlock.CODEC); - this.farmingBlockComponentType = this.getChunkStoreRegistry().registerComponent(FarmingBlock.class, "FarmingBlock", FarmingBlock.CODEC); - this.farmingBlockStateComponentType = this.getChunkStoreRegistry().registerComponent(FarmingBlockState.class, "Farming", FarmingBlockState.CODEC); - this.coopBlockStateComponentType = this.getChunkStoreRegistry().registerComponent(CoopBlock.class, "Coop", CoopBlock.CODEC); - this.coopResidentComponentType = this.getEntityStoreRegistry() - .registerComponent(CoopResidentComponent.class, "CoopResident", CoopResidentComponent.CODEC); - this.getChunkStoreRegistry().registerSystem(new FarmingSystems.OnSoilAdded()); - this.getChunkStoreRegistry().registerSystem(new FarmingSystems.OnFarmBlockAdded()); - this.getChunkStoreRegistry().registerSystem(new FarmingSystems.Ticking()); - this.getChunkStoreRegistry().registerSystem(new FarmingSystems.MigrateFarming()); - this.getChunkStoreRegistry().registerSystem(new FarmingSystems.OnCoopAdded()); - this.getEntityStoreRegistry().registerSystem(new FarmingSystems.CoopResidentEntitySystem()); - this.getEntityStoreRegistry().registerSystem(new FarmingSystems.CoopResidentTicking()); + this.tiledSoilBlockComponentType = chunkStoreRegistry.registerComponent(TilledSoilBlock.class, "TilledSoil", TilledSoilBlock.CODEC); + this.farmingBlockComponentType = chunkStoreRegistry.registerComponent(FarmingBlock.class, "FarmingBlock", FarmingBlock.CODEC); + this.farmingBlockStateComponentType = chunkStoreRegistry.registerComponent(FarmingBlockState.class, "Farming", FarmingBlockState.CODEC); + this.coopBlockStateComponentType = chunkStoreRegistry.registerComponent(CoopBlock.class, "Coop", CoopBlock.CODEC); + this.coopResidentComponentType = entityStoreRegistry.registerComponent(CoopResidentComponent.class, "CoopResident", CoopResidentComponent.CODEC); + chunkStoreRegistry.registerSystem(new FarmingSystems.OnSoilAdded()); + chunkStoreRegistry.registerSystem(new FarmingSystems.OnFarmBlockAdded()); + chunkStoreRegistry.registerSystem(new FarmingSystems.Ticking()); + chunkStoreRegistry.registerSystem(new FarmingSystems.MigrateFarming()); + chunkStoreRegistry.registerSystem(new FarmingSystems.OnCoopAdded()); + entityStoreRegistry.registerSystem(new FarmingSystems.CoopResidentEntitySystem()); + entityStoreRegistry.registerSystem(new FarmingSystems.CoopResidentTicking()); this.getEventRegistry().registerGlobal(EventPriority.LAST, ChunkPreLoadProcessEvent.class, FarmingPlugin::preventSpreadOnNew); } - private static void preventSpreadOnNew(ChunkPreLoadProcessEvent event) { + private static void preventSpreadOnNew(@Nonnull ChunkPreLoadProcessEvent event) { if (event.isNewlyGenerated()) { BlockComponentChunk components = event.getHolder().getComponent(BlockComponentChunk.getComponentType()); if (components != null) { diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/FarmingSystems.java b/src/com/hypixel/hytale/builtin/adventure/farming/FarmingSystems.java index fea5d544..56662f69 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/FarmingSystems.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/FarmingSystems.java @@ -42,13 +42,14 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.core.util.TargetUtil; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Map; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class FarmingSystems { - private static boolean hasCropAbove(BlockChunk blockChunk, int x, int y, int z) { + private static boolean hasCropAbove(@Nonnull BlockChunk blockChunk, int x, int y, int z) { if (y + 1 >= 320) { return false; } else { @@ -67,35 +68,42 @@ public class FarmingSystems { } } - private static boolean updateSoilDecayTime(CommandBuffer commandBuffer, TilledSoilBlock soilBlock, BlockType blockType) { - if (blockType != null && blockType.getFarming() != null && blockType.getFarming().getSoilConfig() != null) { - FarmingData.SoilConfig soilConfig = blockType.getFarming().getSoilConfig(); - Rangef range = soilConfig.getLifetime(); - if (range == null) { - return false; - } else { - double baseDuration = range.min + (range.max - range.min) * ThreadLocalRandom.current().nextDouble(); - Instant currentTime = commandBuffer.getExternalData() - .getWorld() - .getEntityStore() - .getStore() - .getResource(WorldTimeResource.getResourceType()) - .getGameTime(); - Instant endTime = currentTime.plus(Math.round(baseDuration), ChronoUnit.SECONDS); - soilBlock.setDecayTime(endTime); - return true; - } - } else { + private static boolean updateSoilDecayTime( + @Nonnull CommandBuffer commandBuffer, @Nonnull TilledSoilBlock soilBlock, @Nullable BlockType blockType + ) { + if (blockType == null) { return false; + } else { + FarmingData farming = blockType.getFarming(); + if (farming != null && farming.getSoilConfig() != null) { + FarmingData.SoilConfig soilConfig = farming.getSoilConfig(); + Rangef range = soilConfig.getLifetime(); + if (range == null) { + return false; + } else { + double baseDuration = range.min + (range.max - range.min) * ThreadLocalRandom.current().nextDouble(); + Instant currentTime = commandBuffer.getExternalData() + .getWorld() + .getEntityStore() + .getStore() + .getResource(WorldTimeResource.getResourceType()) + .getGameTime(); + Instant endTime = currentTime.plus(Math.round(baseDuration), ChronoUnit.SECONDS); + soilBlock.setDecayTime(endTime); + return true; + } + } else { + return false; + } } } public static class CoopResidentEntitySystem extends RefSystem { - private static final ComponentType componentType = CoopResidentComponent.getComponentType(); + private static final ComponentType COMPONENT_TYPE_COOP_RESIDENT = CoopResidentComponent.getComponentType(); @Override public Query getQuery() { - return componentType; + return COMPONENT_TYPE_COOP_RESIDENT; } @Override @@ -112,23 +120,23 @@ public class FarmingSystems { UUIDComponent uuidComponent = commandBuffer.getComponent(ref, UUIDComponent.getComponentType()); if (uuidComponent != null) { UUID uuid = uuidComponent.getUuid(); - CoopResidentComponent coopResidentComponent = commandBuffer.getComponent(ref, componentType); + CoopResidentComponent coopResidentComponent = commandBuffer.getComponent(ref, COMPONENT_TYPE_COOP_RESIDENT); if (coopResidentComponent != null) { Vector3i coopPosition = coopResidentComponent.getCoopLocation(); World world = commandBuffer.getExternalData().getWorld(); long chunkIndex = ChunkUtil.indexChunkFromBlock(coopPosition.x, coopPosition.z); - WorldChunk chunk = world.getChunkIfLoaded(chunkIndex); - if (chunk != null) { - Ref chunkReference = world.getChunkStore().getChunkReference(chunkIndex); - if (chunkReference != null && chunkReference.isValid()) { + WorldChunk worldChunkComponent = world.getChunkIfLoaded(chunkIndex); + if (worldChunkComponent != null) { + Ref chunkRef = world.getChunkStore().getChunkReference(chunkIndex); + if (chunkRef != null && chunkRef.isValid()) { Store chunkStore = world.getChunkStore().getStore(); - ChunkColumn chunkColumnComponent = chunkStore.getComponent(chunkReference, ChunkColumn.getComponentType()); + ChunkColumn chunkColumnComponent = chunkStore.getComponent(chunkRef, ChunkColumn.getComponentType()); if (chunkColumnComponent != null) { - BlockChunk blockChunkComponent = chunkStore.getComponent(chunkReference, BlockChunk.getComponentType()); + BlockChunk blockChunkComponent = chunkStore.getComponent(chunkRef, BlockChunk.getComponentType()); if (blockChunkComponent != null) { Ref sectionRef = chunkColumnComponent.getSection(ChunkUtil.chunkCoordinate(coopPosition.y)); if (sectionRef != null && sectionRef.isValid()) { - BlockComponentChunk blockComponentChunk = chunkStore.getComponent(chunkReference, BlockComponentChunk.getComponentType()); + BlockComponentChunk blockComponentChunk = chunkStore.getComponent(chunkRef, BlockComponentChunk.getComponentType()); if (blockComponentChunk != null) { int blockIndexColumn = ChunkUtil.indexBlockInColumn(coopPosition.x, coopPosition.y, coopPosition.z); Ref coopEntityReference = blockComponentChunk.getEntityReference(blockIndexColumn); @@ -151,11 +159,11 @@ public class FarmingSystems { } public static class CoopResidentTicking extends EntityTickingSystem { - private static final ComponentType componentType = CoopResidentComponent.getComponentType(); + private static final ComponentType COMPONENT_TYPE_COOP_RESIDENT = CoopResidentComponent.getComponentType(); @Override public Query getQuery() { - return componentType; + return COMPONENT_TYPE_COOP_RESIDENT; } @Override @@ -200,32 +208,34 @@ public class FarmingSystems { } public static class OnCoopAdded extends RefSystem { + @Nonnull private static final Query QUERY = Query.and(BlockModule.BlockStateInfo.getComponentType(), CoopBlock.getComponentType()); @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - CoopBlock coopBlock = commandBuffer.getComponent(ref, CoopBlock.getComponentType()); - if (coopBlock != null) { - WorldTimeResource worldTimeResource = commandBuffer.getExternalData() - .getWorld() - .getEntityStore() - .getStore() - .getResource(WorldTimeResource.getResourceType()); - BlockModule.BlockStateInfo info = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + CoopBlock coopBlockComponent = commandBuffer.getComponent(ref, CoopBlock.getComponentType()); - assert info != null; + assert coopBlockComponent != null; - int x = ChunkUtil.xFromBlockInColumn(info.getIndex()); - int y = ChunkUtil.yFromBlockInColumn(info.getIndex()); - int z = ChunkUtil.zFromBlockInColumn(info.getIndex()); - BlockChunk blockChunk = commandBuffer.getComponent(info.getChunkRef(), BlockChunk.getComponentType()); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); - assert blockChunk != null; + assert blockStateInfoComponent != null; - BlockSection blockSection = blockChunk.getSectionAtBlockY(y); - blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), coopBlock.getNextScheduledTick(worldTimeResource)); + World world = commandBuffer.getExternalData().getWorld(); + Store entityStore = world.getEntityStore().getStore(); + WorldTimeResource worldTimeResource = entityStore.getResource(WorldTimeResource.getResourceType()); + int x = ChunkUtil.xFromBlockInColumn(blockStateInfoComponent.getIndex()); + int y = ChunkUtil.yFromBlockInColumn(blockStateInfoComponent.getIndex()); + int z = ChunkUtil.zFromBlockInColumn(blockStateInfoComponent.getIndex()); + Ref chunkRef = blockStateInfoComponent.getChunkRef(); + if (chunkRef.isValid()) { + BlockChunk blockChunkComponent = commandBuffer.getComponent(chunkRef, BlockChunk.getComponentType()); + if (blockChunkComponent != null) { + BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(y); + blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), coopBlockComponent.getNextScheduledTick(worldTimeResource)); + } } } @@ -234,43 +244,45 @@ public class FarmingSystems { @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { if (reason != RemoveReason.UNLOAD) { - CoopBlock coop = commandBuffer.getComponent(ref, CoopBlock.getComponentType()); - if (coop != null) { - BlockModule.BlockStateInfo info = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + CoopBlock coopBlockComponent = commandBuffer.getComponent(ref, CoopBlock.getComponentType()); - assert info != null; + assert coopBlockComponent != null; - Store entityStore = commandBuffer.getExternalData().getWorld().getEntityStore().getStore(); - int x = ChunkUtil.xFromBlockInColumn(info.getIndex()); - int y = ChunkUtil.yFromBlockInColumn(info.getIndex()); - int z = ChunkUtil.zFromBlockInColumn(info.getIndex()); - BlockChunk blockChunk = commandBuffer.getComponent(info.getChunkRef(), BlockChunk.getComponentType()); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); - assert blockChunk != null; + assert blockStateInfoComponent != null; - ChunkColumn column = commandBuffer.getComponent(info.getChunkRef(), ChunkColumn.getComponentType()); + int index = blockStateInfoComponent.getIndex(); + int x = ChunkUtil.xFromBlockInColumn(index); + int y = ChunkUtil.yFromBlockInColumn(index); + int z = ChunkUtil.zFromBlockInColumn(index); + BlockChunk blockChunkComponent = commandBuffer.getComponent(blockStateInfoComponent.getChunkRef(), BlockChunk.getComponentType()); - assert column != null; + assert blockChunkComponent != null; - Ref sectionRef = column.getSection(ChunkUtil.chunkCoordinate(y)); + ChunkColumn chunkColumnComponent = commandBuffer.getComponent(blockStateInfoComponent.getChunkRef(), ChunkColumn.getComponentType()); - assert sectionRef != null; + assert chunkColumnComponent != null; - BlockSection blockSection = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); + Ref sectionRef = chunkColumnComponent.getSection(ChunkUtil.chunkCoordinate(y)); - assert blockSection != null; + assert sectionRef != null; - ChunkSection chunkSection = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + BlockSection blockSectionComponent = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); - assert chunkSection != null; + assert blockSectionComponent != null; - int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSection.getX(), x); - int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSection.getY(), y); - int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSection.getZ(), z); - World world = commandBuffer.getExternalData().getWorld(); - WorldTimeResource worldTimeResource = world.getEntityStore().getStore().getResource(WorldTimeResource.getResourceType()); - coop.handleBlockBroken(world, worldTimeResource, entityStore, worldX, worldY, worldZ); - } + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + + assert chunkSectionComponent != null; + + int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getX(), x); + int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getY(), y); + int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getZ(), z); + World world = commandBuffer.getExternalData().getWorld(); + Store entityStore = world.getEntityStore().getStore(); + WorldTimeResource worldTimeResource = entityStore.getResource(WorldTimeResource.getResourceType()); + coopBlockComponent.handleBlockBroken(world, worldTimeResource, entityStore, worldX, worldY, worldZ); } } @@ -282,99 +294,125 @@ public class FarmingSystems { } public static class OnFarmBlockAdded extends RefSystem { + @Nonnull private static final Query QUERY = Query.and(BlockModule.BlockStateInfo.getComponentType(), FarmingBlock.getComponentType()); @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - FarmingBlock farmingBlock = commandBuffer.getComponent(ref, FarmingBlock.getComponentType()); + FarmingBlock farmingBlockComponent = commandBuffer.getComponent(ref, FarmingBlock.getComponentType()); - assert farmingBlock != null; + assert farmingBlockComponent != null; - BlockModule.BlockStateInfo info = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); - assert info != null; + assert blockStateInfoComponent != null; - BlockChunk blockChunk = commandBuffer.getComponent(info.getChunkRef(), BlockChunk.getComponentType()); - if (farmingBlock.getLastTickGameTime() == null) { - int blockId = blockChunk.getBlock( - ChunkUtil.xFromBlockInColumn(info.getIndex()), ChunkUtil.yFromBlockInColumn(info.getIndex()), ChunkUtil.zFromBlockInColumn(info.getIndex()) - ); - BlockType blockType = BlockType.getAssetMap().getAsset(blockId); - if (blockType.getFarming() == null) { - return; - } + Ref chunkRef = blockStateInfoComponent.getChunkRef(); + if (chunkRef.isValid()) { + BlockChunk blockChunkComponent = commandBuffer.getComponent(chunkRef, BlockChunk.getComponentType()); - farmingBlock.setCurrentStageSet(blockType.getFarming().getStartingStageSet()); - farmingBlock.setLastTickGameTime( - store.getExternalData().getWorld().getEntityStore().getStore().getResource(WorldTimeResource.getResourceType()).getGameTime() - ); - blockChunk.markNeedsSaving(); - if (blockType.getFarming().getStages() != null) { - FarmingStageData[] stages = blockType.getFarming().getStages().get(blockType.getFarming().getStartingStageSet()); - if (stages != null && stages.length > 0) { - boolean found = false; + assert blockChunkComponent != null; - for (int i = 0; i < stages.length; i++) { - FarmingStageData stage = stages[i]; - switch (stage) { - case BlockTypeFarmingStageData data: - if (data.getBlock().equals(blockType.getId())) { - farmingBlock.setGrowthProgress(i); - found = true; - } - break; - case BlockStateFarmingStageData datax: - BlockType stateBlockType = blockType.getBlockForState(datax.getState()); - if (stateBlockType != null && stateBlockType.getId().equals(blockType.getId())) { - farmingBlock.setGrowthProgress(i); - found = true; - } - break; - default: + World world = store.getExternalData().getWorld(); + Store entityStore = world.getEntityStore().getStore(); + WorldTimeResource worldTimeResource = entityStore.getResource(WorldTimeResource.getResourceType()); + if (farmingBlockComponent.getLastTickGameTime() == null) { + int index = blockStateInfoComponent.getIndex(); + int blockId = blockChunkComponent.getBlock( + ChunkUtil.xFromBlockInColumn(index), ChunkUtil.yFromBlockInColumn(index), ChunkUtil.zFromBlockInColumn(index) + ); + BlockType blockType = BlockType.getAssetMap().getAsset(blockId); + if (blockType == null) { + return; + } + + FarmingData blockTypeFarming = blockType.getFarming(); + if (blockTypeFarming == null) { + return; + } + + String startingStageSet = blockTypeFarming.getStartingStageSet(); + farmingBlockComponent.setCurrentStageSet(startingStageSet); + farmingBlockComponent.setLastTickGameTime(worldTimeResource.getGameTime()); + blockChunkComponent.markNeedsSaving(); + Map farmingStages = blockTypeFarming.getStages(); + if (farmingStages != null) { + FarmingStageData[] stages = farmingStages.get(startingStageSet); + if (stages != null && stages.length > 0) { + boolean found = false; + + for (int i = 0; i < stages.length; i++) { + FarmingStageData stage = stages[i]; + switch (stage) { + case BlockTypeFarmingStageData data: + if (data.getBlock().equals(blockType.getId())) { + farmingBlockComponent.setGrowthProgress(i); + found = true; + } + break; + case BlockStateFarmingStageData datax: + BlockType stateBlockType = blockType.getBlockForState(datax.getState()); + if (stateBlockType != null && stateBlockType.getId().equals(blockType.getId())) { + farmingBlockComponent.setGrowthProgress(i); + found = true; + } + break; + default: + } } - } - if (!found) { - Ref sectionRef = commandBuffer.getComponent(info.getChunkRef(), ChunkColumn.getComponentType()) - .getSection(ChunkUtil.chunkCoordinate(ChunkUtil.yFromBlockInColumn(info.getIndex()))); - stages[0] - .apply( - commandBuffer, - sectionRef, - ref, - ChunkUtil.xFromBlockInColumn(info.getIndex()), - ChunkUtil.yFromBlockInColumn(info.getIndex()), - ChunkUtil.zFromBlockInColumn(info.getIndex()), - null - ); + if (!found) { + ChunkColumn chunkColumnComponent = commandBuffer.getComponent(chunkRef, ChunkColumn.getComponentType()); + + assert chunkColumnComponent != null; + + int chunkCoordinate = ChunkUtil.chunkCoordinate(ChunkUtil.yFromBlockInColumn(index)); + Ref sectionRef = chunkColumnComponent.getSection(chunkCoordinate); + if (sectionRef != null && sectionRef.isValid()) { + stages[0] + .apply( + commandBuffer, + sectionRef, + ref, + ChunkUtil.xFromBlockInColumn(index), + ChunkUtil.yFromBlockInColumn(index), + ChunkUtil.zFromBlockInColumn(index), + null + ); + } + } } } } + + if (farmingBlockComponent.getLastTickGameTime() == null) { + farmingBlockComponent.setLastTickGameTime(worldTimeResource.getGameTime()); + blockChunkComponent.markNeedsSaving(); + } + + int indexx = blockStateInfoComponent.getIndex(); + int x = ChunkUtil.xFromBlockInColumn(indexx); + int y = ChunkUtil.yFromBlockInColumn(indexx); + int z = ChunkUtil.zFromBlockInColumn(indexx); + BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunkRef, BlockComponentChunk.getComponentType()); + + assert blockComponentChunk != null; + + ChunkColumn chunkColumnComponentx = commandBuffer.getComponent(chunkRef, ChunkColumn.getComponentType()); + + assert chunkColumnComponentx != null; + + Ref section = chunkColumnComponentx.getSection(ChunkUtil.chunkCoordinate(y)); + if (section != null) { + BlockSection blockSectionComponent = commandBuffer.getComponent(section, BlockSection.getComponentType()); + + assert blockSectionComponent != null; + + FarmingUtil.tickFarming(commandBuffer, blockChunkComponent, blockSectionComponent, section, ref, farmingBlockComponent, x, y, z, true); + } } - - if (farmingBlock.getLastTickGameTime() == null) { - farmingBlock.setLastTickGameTime( - store.getExternalData().getWorld().getEntityStore().getStore().getResource(WorldTimeResource.getResourceType()).getGameTime() - ); - blockChunk.markNeedsSaving(); - } - - int x = ChunkUtil.xFromBlockInColumn(info.getIndex()); - int y = ChunkUtil.yFromBlockInColumn(info.getIndex()); - int z = ChunkUtil.zFromBlockInColumn(info.getIndex()); - BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(info.getChunkRef(), BlockComponentChunk.getComponentType()); - - assert blockComponentChunk != null; - - ChunkColumn column = commandBuffer.getComponent(info.getChunkRef(), ChunkColumn.getComponentType()); - - assert column != null; - - Ref section = column.getSection(ChunkUtil.chunkCoordinate(y)); - BlockSection blockSection = commandBuffer.getComponent(section, BlockSection.getComponentType()); - FarmingUtil.tickFarming(commandBuffer, blockChunk, blockSection, section, ref, farmingBlock, x, y, z, true); } @Override @@ -391,43 +429,46 @@ public class FarmingSystems { } public static class OnSoilAdded extends RefSystem { + @Nonnull private static final Query QUERY = Query.and(BlockModule.BlockStateInfo.getComponentType(), TilledSoilBlock.getComponentType()); @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - TilledSoilBlock soil = commandBuffer.getComponent(ref, TilledSoilBlock.getComponentType()); + TilledSoilBlock soilComponent = commandBuffer.getComponent(ref, TilledSoilBlock.getComponentType()); - assert soil != null; + assert soilComponent != null; - BlockModule.BlockStateInfo info = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); - assert info != null; + assert blockStateInfoComponent != null; - if (!soil.isPlanted()) { - int x = ChunkUtil.xFromBlockInColumn(info.getIndex()); - int y = ChunkUtil.yFromBlockInColumn(info.getIndex()); - int z = ChunkUtil.zFromBlockInColumn(info.getIndex()); + Ref chunkRef = blockStateInfoComponent.getChunkRef(); + if (chunkRef.isValid()) { + if (!soilComponent.isPlanted()) { + int index = blockStateInfoComponent.getIndex(); + int x = ChunkUtil.xFromBlockInColumn(index); + int y = ChunkUtil.yFromBlockInColumn(index); + int z = ChunkUtil.zFromBlockInColumn(index); + BlockChunk blockChunkComponent = commandBuffer.getComponent(chunkRef, BlockChunk.getComponentType()); - assert info.getChunkRef() != null; + assert blockChunkComponent != null; - BlockChunk blockChunk = commandBuffer.getComponent(info.getChunkRef(), BlockChunk.getComponentType()); + BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(y); + Instant decayTime = soilComponent.getDecayTime(); + if (decayTime == null) { + int blockId = blockSection.get(x, y, z); + BlockType blockType = BlockType.getAssetMap().getAsset(blockId); + FarmingSystems.updateSoilDecayTime(commandBuffer, soilComponent, blockType); + } - assert blockChunk != null; + if (decayTime == null) { + return; + } - BlockSection blockSection = blockChunk.getSectionAtBlockY(y); - Instant decayTime = soil.getDecayTime(); - if (decayTime == null) { - BlockType blockType = BlockType.getAssetMap().getAsset(blockSection.get(x, y, z)); - FarmingSystems.updateSoilDecayTime(commandBuffer, soil, blockType); + blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), decayTime); } - - if (decayTime == null) { - return; - } - - blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), decayTime); } } @@ -445,6 +486,7 @@ public class FarmingSystems { } public static class Ticking extends EntityTickingSystem { + @Nonnull private static final Query QUERY = Query.and(BlockSection.getComponentType(), ChunkSection.getComponentType()); @Override @@ -455,44 +497,50 @@ public class FarmingSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - BlockSection blocks = archetypeChunk.getComponent(index, BlockSection.getComponentType()); + BlockSection blockSectionComponent = archetypeChunk.getComponent(index, BlockSection.getComponentType()); - assert blocks != null; + assert blockSectionComponent != null; - if (blocks.getTickingBlocksCountCopy() != 0) { - ChunkSection section = archetypeChunk.getComponent(index, ChunkSection.getComponentType()); + if (blockSectionComponent.getTickingBlocksCountCopy() != 0) { + ChunkSection chunkSectionComponent = archetypeChunk.getComponent(index, ChunkSection.getComponentType()); - assert section != null; + assert chunkSectionComponent != null; - if (section.getChunkColumnReference() != null && section.getChunkColumnReference().isValid()) { - BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(section.getChunkColumnReference(), BlockComponentChunk.getComponentType()); + Ref chunkColumnRef = chunkSectionComponent.getChunkColumnReference(); + if (chunkColumnRef != null && chunkColumnRef.isValid()) { + BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunkColumnRef, BlockComponentChunk.getComponentType()); assert blockComponentChunk != null; Ref ref = archetypeChunk.getReferenceTo(index); - BlockChunk blockChunk = commandBuffer.getComponent(section.getChunkColumnReference(), BlockChunk.getComponentType()); + BlockChunk blockChunk = commandBuffer.getComponent(chunkColumnRef, BlockChunk.getComponentType()); assert blockChunk != null; - blocks.forEachTicking( - blockComponentChunk, commandBuffer, section.getY(), (blockComponentChunk1, commandBuffer1, localX, localY, localZ, blockId) -> { + blockSectionComponent.forEachTicking( + blockComponentChunk, + commandBuffer, + chunkSectionComponent.getY(), + (blockComponentChunk1, commandBuffer1, localX, localY, localZ, blockId) -> { Ref blockRef = blockComponentChunk1.getEntityReference(ChunkUtil.indexBlockInColumn(localX, localY, localZ)); if (blockRef == null) { return BlockTickStrategy.IGNORED; } else { - FarmingBlock farming = commandBuffer1.getComponent(blockRef, FarmingBlock.getComponentType()); - if (farming != null) { - FarmingUtil.tickFarming(commandBuffer1, blockChunk, blocks, ref, blockRef, farming, localX, localY, localZ, false); + FarmingBlock farmingBlockComponent = commandBuffer1.getComponent(blockRef, FarmingBlock.getComponentType()); + if (farmingBlockComponent != null) { + FarmingUtil.tickFarming( + commandBuffer1, blockChunk, blockSectionComponent, ref, blockRef, farmingBlockComponent, localX, localY, localZ, false + ); return BlockTickStrategy.SLEEP; } else { - TilledSoilBlock soil = commandBuffer1.getComponent(blockRef, TilledSoilBlock.getComponentType()); - if (soil != null) { - tickSoil(commandBuffer1, blockComponentChunk1, blockRef, soil); + TilledSoilBlock tilledSoilBlockComponent = commandBuffer1.getComponent(blockRef, TilledSoilBlock.getComponentType()); + if (tilledSoilBlockComponent != null) { + tickSoil(commandBuffer1, blockRef, tilledSoilBlockComponent); return BlockTickStrategy.SLEEP; } else { - CoopBlock coop = commandBuffer1.getComponent(blockRef, CoopBlock.getComponentType()); - if (coop != null) { - tickCoop(commandBuffer1, blockComponentChunk1, blockRef, coop); + CoopBlock coopBlockComponent = commandBuffer1.getComponent(blockRef, CoopBlock.getComponentType()); + if (coopBlockComponent != null) { + tickCoop(commandBuffer1, blockRef, coopBlockComponent); return BlockTickStrategy.SLEEP; } else { return BlockTickStrategy.IGNORED; @@ -506,122 +554,128 @@ public class FarmingSystems { } } - private static void tickSoil( - CommandBuffer commandBuffer, BlockComponentChunk blockComponentChunk, Ref blockRef, TilledSoilBlock soilBlock - ) { - BlockModule.BlockStateInfo info = commandBuffer.getComponent(blockRef, BlockModule.BlockStateInfo.getComponentType()); + private static void tickSoil(@Nonnull CommandBuffer commandBuffer, @Nonnull Ref blockRef, @Nonnull TilledSoilBlock soilBlock) { + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(blockRef, BlockModule.BlockStateInfo.getComponentType()); - assert info != null; + assert blockStateInfoComponent != null; - int x = ChunkUtil.xFromBlockInColumn(info.getIndex()); - int y = ChunkUtil.yFromBlockInColumn(info.getIndex()); - int z = ChunkUtil.zFromBlockInColumn(info.getIndex()); + int index = blockStateInfoComponent.getIndex(); + int x = ChunkUtil.xFromBlockInColumn(index); + int y = ChunkUtil.yFromBlockInColumn(index); + int z = ChunkUtil.zFromBlockInColumn(index); if (y < 320) { - assert info.getChunkRef() != null; - - BlockChunk blockChunk = commandBuffer.getComponent(info.getChunkRef(), BlockChunk.getComponentType()); - - assert blockChunk != null; - - BlockSection blockSection = blockChunk.getSectionAtBlockY(y); - boolean hasCrop = FarmingSystems.hasCropAbove(blockChunk, x, y, z); - BlockType blockType = BlockType.getAssetMap().getAsset(blockSection.get(x, y, z)); - Instant currentTime = commandBuffer.getExternalData() - .getWorld() - .getEntityStore() - .getStore() - .getResource(WorldTimeResource.getResourceType()) - .getGameTime(); - Instant decayTime = soilBlock.getDecayTime(); - if (soilBlock.isPlanted() && !hasCrop) { - if (!FarmingSystems.updateSoilDecayTime(commandBuffer, soilBlock, blockType)) { - return; - } - - if (decayTime != null) { - blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), decayTime); - } - } else if (!soilBlock.isPlanted() && !hasCrop) { - if (decayTime == null || !decayTime.isAfter(currentTime)) { - assert info.getChunkRef() != null; - - if (blockType != null && blockType.getFarming() != null && blockType.getFarming().getSoilConfig() != null) { - FarmingData.SoilConfig soilConfig = blockType.getFarming().getSoilConfig(); - String targetBlock = soilConfig.getTargetBlock(); - if (targetBlock == null) { - return; - } else { - int targetBlockId = BlockType.getAssetMap().getIndex(targetBlock); - if (targetBlockId == Integer.MIN_VALUE) { - return; - } else { - BlockType targetBlockType = BlockType.getAssetMap().getAsset(targetBlockId); - int rotation = blockSection.getRotationIndex(x, y, z); - WorldChunk worldChunk = commandBuffer.getComponent(info.getChunkRef(), WorldChunk.getComponentType()); - commandBuffer.run(_store -> worldChunk.setBlock(x, y, z, targetBlockId, targetBlockType, rotation, 0, 0)); + Ref chunkRef = blockStateInfoComponent.getChunkRef(); + if (chunkRef.isValid()) { + BlockChunk blockChunkComponent = commandBuffer.getComponent(chunkRef, BlockChunk.getComponentType()); + if (blockChunkComponent != null) { + BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(y); + boolean hasCrop = FarmingSystems.hasCropAbove(blockChunkComponent, x, y, z); + int blockId = blockSection.get(x, y, z); + BlockType blockTypeAsset = BlockType.getAssetMap().getAsset(blockId); + if (blockTypeAsset != null) { + Instant currentTime = commandBuffer.getExternalData() + .getWorld() + .getEntityStore() + .getStore() + .getResource(WorldTimeResource.getResourceType()) + .getGameTime(); + Instant decayTime = soilBlock.getDecayTime(); + if (soilBlock.isPlanted() && !hasCrop) { + if (!FarmingSystems.updateSoilDecayTime(commandBuffer, soilBlock, blockTypeAsset)) { return; } + + if (decayTime != null) { + blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), decayTime); + } + } else if (!soilBlock.isPlanted() && !hasCrop) { + if (decayTime == null || !decayTime.isAfter(currentTime)) { + if (blockTypeAsset.getFarming() != null && blockTypeAsset.getFarming().getSoilConfig() != null) { + FarmingData.SoilConfig soilConfig = blockTypeAsset.getFarming().getSoilConfig(); + String targetBlock = soilConfig.getTargetBlock(); + if (targetBlock == null) { + return; + } else { + int targetBlockId = BlockType.getAssetMap().getIndex(targetBlock); + if (targetBlockId == Integer.MIN_VALUE) { + return; + } else { + BlockType targetBlockType = BlockType.getAssetMap().getAsset(targetBlockId); + int rotationIndex = blockSection.getRotationIndex(x, y, z); + WorldChunk worldChunkComponent = commandBuffer.getComponent(chunkRef, WorldChunk.getComponentType()); + + assert worldChunkComponent != null; + + commandBuffer.run(_store -> worldChunkComponent.setBlock(x, y, z, targetBlockId, targetBlockType, rotationIndex, 0, 0)); + return; + } + } + } else { + return; + } + } + } else if (hasCrop) { + soilBlock.setDecayTime(null); } - } else { - return; + + String targetBlock = soilBlock.computeBlockType(currentTime, blockTypeAsset); + if (targetBlock != null && !targetBlock.equals(blockTypeAsset.getId())) { + WorldChunk worldChunkComponent = commandBuffer.getComponent(chunkRef, WorldChunk.getComponentType()); + + assert worldChunkComponent != null; + + int rotationIndex = blockSection.getRotationIndex(x, y, z); + int targetBlockId = BlockType.getAssetMap().getIndex(targetBlock); + BlockType targetBlockType = BlockType.getAssetMap().getAsset(targetBlockId); + commandBuffer.run(_store -> worldChunkComponent.setBlock(x, y, z, targetBlockId, targetBlockType, rotationIndex, 0, 2)); + } + + soilBlock.setPlanted(hasCrop); } } - } else if (hasCrop) { - soilBlock.setDecayTime(null); } - - String targetBlock = soilBlock.computeBlockType(currentTime, blockType); - if (targetBlock != null && !targetBlock.equals(blockType.getId())) { - WorldChunk worldChunk = commandBuffer.getComponent(info.getChunkRef(), WorldChunk.getComponentType()); - int rotation = blockSection.getRotationIndex(x, y, z); - int targetBlockId = BlockType.getAssetMap().getIndex(targetBlock); - BlockType targetBlockType = BlockType.getAssetMap().getAsset(targetBlockId); - commandBuffer.run(_store -> worldChunk.setBlock(x, y, z, targetBlockId, targetBlockType, rotation, 0, 2)); - } - - soilBlock.setPlanted(hasCrop); } } - private static void tickCoop( - CommandBuffer commandBuffer, BlockComponentChunk blockComponentChunk, Ref blockRef, CoopBlock coopBlock - ) { - BlockModule.BlockStateInfo info = commandBuffer.getComponent(blockRef, BlockModule.BlockStateInfo.getComponentType()); + private static void tickCoop(@Nonnull CommandBuffer commandBuffer, @Nonnull Ref blockRef, @Nonnull CoopBlock coopBlock) { + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(blockRef, BlockModule.BlockStateInfo.getComponentType()); - assert info != null; + assert blockStateInfoComponent != null; Store store = commandBuffer.getExternalData().getWorld().getEntityStore().getStore(); WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType()); FarmingCoopAsset coopAsset = coopBlock.getCoopAsset(); if (coopAsset != null) { - int x = ChunkUtil.xFromBlockInColumn(info.getIndex()); - int y = ChunkUtil.yFromBlockInColumn(info.getIndex()); - int z = ChunkUtil.zFromBlockInColumn(info.getIndex()); - BlockChunk blockChunk = commandBuffer.getComponent(info.getChunkRef(), BlockChunk.getComponentType()); + int index = blockStateInfoComponent.getIndex(); + int x = ChunkUtil.xFromBlockInColumn(index); + int y = ChunkUtil.yFromBlockInColumn(index); + int z = ChunkUtil.zFromBlockInColumn(index); + BlockChunk blockChunkComponent = commandBuffer.getComponent(blockStateInfoComponent.getChunkRef(), BlockChunk.getComponentType()); - assert blockChunk != null; + assert blockChunkComponent != null; - ChunkColumn column = commandBuffer.getComponent(info.getChunkRef(), ChunkColumn.getComponentType()); + ChunkColumn chunkColumnComponent = commandBuffer.getComponent(blockStateInfoComponent.getChunkRef(), ChunkColumn.getComponentType()); - assert column != null; + assert chunkColumnComponent != null; - Ref sectionRef = column.getSection(ChunkUtil.chunkCoordinate(y)); + Ref sectionRef = chunkColumnComponent.getSection(ChunkUtil.chunkCoordinate(y)); assert sectionRef != null; - BlockSection blockSection = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); + BlockSection blockSectionComponent = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); - assert blockSection != null; + assert blockSectionComponent != null; - ChunkSection chunkSection = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - assert chunkSection != null; + assert chunkSectionComponent != null; - int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSection.getX(), x); - int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSection.getY(), y); - int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSection.getZ(), z); + int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getX(), x); + int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getY(), y); + int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getZ(), z); World world = commandBuffer.getExternalData().getWorld(); - WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(worldX, worldZ)); + long chunkIndex = ChunkUtil.indexChunkFromBlock(worldX, worldZ); + WorldChunk chunk = world.getChunkIfInMemory(chunkIndex); double blockRotation = chunk.getRotation(worldX, worldY, worldZ).yaw().getRadians(); Vector3d spawnOffset = new Vector3d().assign(coopAsset.getResidentSpawnOffset()).rotateY((float)blockRotation); Vector3i coopLocation = new Vector3i(worldX, worldY, worldZ); @@ -652,7 +706,7 @@ public class FarmingSystems { Instant nextTickInstant = coopBlock.getNextScheduledTick(worldTimeResource); if (nextTickInstant != null) { - blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), nextTickInstant); + blockSectionComponent.scheduleTick(ChunkUtil.indexBlock(x, y, z), nextTickInstant); } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/FarmingUtil.java b/src/com/hypixel/hytale/builtin/adventure/farming/FarmingUtil.java index 0b100ead..f4b2fc1a 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/FarmingUtil.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/FarmingUtil.java @@ -20,6 +20,7 @@ import com.hypixel.hytale.server.core.asset.type.blocktype.config.farming.Farmin import com.hypixel.hytale.server.core.asset.type.blocktype.config.farming.GrowthModifierAsset; import com.hypixel.hytale.server.core.asset.type.model.config.ModelAsset; import com.hypixel.hytale.server.core.entity.ItemUtils; +import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.modules.block.BlockModule; import com.hypixel.hytale.server.core.modules.entity.component.PersistentModel; import com.hypixel.hytale.server.core.modules.interaction.BlockHarvestUtils; @@ -43,19 +44,20 @@ public class FarmingUtil { private static final int BETWEEN_RANDOM = 10; public static void tickFarming( - CommandBuffer commandBuffer, - BlockChunk blockChunk, - BlockSection blockSection, - Ref sectionRef, - Ref blockRef, - FarmingBlock farmingBlock, + @Nonnull CommandBuffer commandBuffer, + @Nonnull BlockChunk blockChunk, + @Nonnull BlockSection blockSection, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, + @Nonnull FarmingBlock farmingBlock, int x, int y, int z, boolean initialTick ) { World world = commandBuffer.getExternalData().getWorld(); - WorldTimeResource worldTimeResource = world.getEntityStore().getStore().getResource(WorldTimeResource.getResourceType()); + Store entityStore = world.getEntityStore().getStore(); + WorldTimeResource worldTimeResource = entityStore.getResource(WorldTimeResource.getResourceType()); Instant currentTime = worldTimeResource.getGameTime(); BlockType blockType = farmingBlock.getPreviousBlockType() != null ? BlockType.getAssetMap().getAsset(farmingBlock.getPreviousBlockType()) @@ -90,77 +92,79 @@ public class FarmingUtil { commandBuffer.removeEntity(blockRef, RemoveReason.REMOVE); } else { long remainingTimeSeconds = currentTime.getEpochSecond() - farmingBlock.getLastTickGameTime().getEpochSecond(); - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - int worldX = ChunkUtil.worldCoordFromLocalCoord(section.getX(), x); - int worldY = ChunkUtil.worldCoordFromLocalCoord(section.getY(), y); - int worldZ = ChunkUtil.worldCoordFromLocalCoord(section.getZ(), z); + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent != null) { + int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getX(), x); + int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getY(), y); + int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getZ(), z); - while (currentStage < stages.length) { - FarmingStageData stage = stages[currentStage]; - if (stage.shouldStop(commandBuffer, sectionRef, blockRef, x, y, z)) { - blockChunk.markNeedsSaving(); - farmingBlock.setGrowthProgress(stages.length); - commandBuffer.removeEntity(blockRef, RemoveReason.REMOVE); - break; - } - - Rangef range = stage.getDuration(); - if (range == null) { - blockChunk.markNeedsSaving(); - commandBuffer.removeEntity(blockRef, RemoveReason.REMOVE); - break; - } - - double rand = HashUtil.random(farmingBlock.getGeneration(), worldX, worldY, worldZ); - double baseDuration = range.min + (range.max - range.min) * rand; - long remainingDurationSeconds = Math.round(baseDuration * (1.0 - currentProgress % 1.0)); - double growthMultiplier = 1.0; - if (farmingConfig.getGrowthModifiers() != null) { - for (String modifierName : farmingConfig.getGrowthModifiers()) { - GrowthModifierAsset modifier = GrowthModifierAsset.getAssetMap().getAsset(modifierName); - if (modifier != null) { - growthMultiplier *= modifier.getCurrentGrowthMultiplier(commandBuffer, sectionRef, blockRef, x, y, z, initialTick); - } - } - } - - remainingDurationSeconds = Math.round(remainingDurationSeconds / growthMultiplier); - if (remainingTimeSeconds < remainingDurationSeconds) { - currentProgress += (float)(remainingTimeSeconds / (baseDuration / growthMultiplier)); - farmingBlock.setGrowthProgress(currentProgress); - long nextGrowthInNanos = (remainingDurationSeconds - remainingTimeSeconds) * 1000000000L; - long randCap = (long)( - (15.0 + 10.0 * HashUtil.random(farmingBlock.getGeneration() ^ 3405692655L, worldX, worldY, worldZ)) - * world.getTps() - * WorldTimeResource.getSecondsPerTick(world) - * 1.0E9 - ); - long cappedNextGrowthInNanos = Math.min(nextGrowthInNanos, randCap); - blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), currentTime.plusNanos(cappedNextGrowthInNanos)); - break; - } - - remainingTimeSeconds -= remainingDurationSeconds; - currentProgress = ++currentStage; - farmingBlock.setGrowthProgress(currentProgress); - blockChunk.markNeedsSaving(); - farmingBlock.setGeneration(farmingBlock.getGeneration() + 1); - if (currentStage >= stages.length) { - if (stages[currentStage - 1].implementsShouldStop()) { - currentStage = stages.length - 1; - farmingBlock.setGrowthProgress(currentStage); - stages[currentStage].apply(commandBuffer, sectionRef, blockRef, x, y, z, stages[currentStage]); - } else { + while (currentStage < stages.length) { + FarmingStageData stage = stages[currentStage]; + if (stage.shouldStop(commandBuffer, sectionRef, blockRef, x, y, z)) { + blockChunk.markNeedsSaving(); farmingBlock.setGrowthProgress(stages.length); commandBuffer.removeEntity(blockRef, RemoveReason.REMOVE); + break; } - } else { - farmingBlock.setExecutions(0); - stages[currentStage].apply(commandBuffer, sectionRef, blockRef, x, y, z, stages[currentStage - 1]); - } - } - farmingBlock.setLastTickGameTime(currentTime); + Rangef range = stage.getDuration(); + if (range == null) { + blockChunk.markNeedsSaving(); + commandBuffer.removeEntity(blockRef, RemoveReason.REMOVE); + break; + } + + double rand = HashUtil.random(farmingBlock.getGeneration(), worldX, worldY, worldZ); + double baseDuration = range.min + (range.max - range.min) * rand; + long remainingDurationSeconds = Math.round(baseDuration * (1.0 - currentProgress % 1.0)); + double growthMultiplier = 1.0; + if (farmingConfig.getGrowthModifiers() != null) { + for (String modifierName : farmingConfig.getGrowthModifiers()) { + GrowthModifierAsset modifierAsset = GrowthModifierAsset.getAssetMap().getAsset(modifierName); + if (modifierAsset != null) { + growthMultiplier *= modifierAsset.getCurrentGrowthMultiplier(commandBuffer, sectionRef, blockRef, x, y, z, initialTick); + } + } + } + + remainingDurationSeconds = Math.round(remainingDurationSeconds / growthMultiplier); + if (remainingTimeSeconds < remainingDurationSeconds) { + currentProgress += (float)(remainingTimeSeconds / (baseDuration / growthMultiplier)); + farmingBlock.setGrowthProgress(currentProgress); + long nextGrowthInNanos = (remainingDurationSeconds - remainingTimeSeconds) * 1000000000L; + long randCap = (long)( + (15.0 + 10.0 * HashUtil.random(farmingBlock.getGeneration() ^ 3405692655L, worldX, worldY, worldZ)) + * world.getTps() + * WorldTimeResource.getSecondsPerTick(world) + * 1.0E9 + ); + long cappedNextGrowthInNanos = Math.min(nextGrowthInNanos, randCap); + blockSection.scheduleTick(ChunkUtil.indexBlock(x, y, z), currentTime.plusNanos(cappedNextGrowthInNanos)); + break; + } + + remainingTimeSeconds -= remainingDurationSeconds; + currentProgress = ++currentStage; + farmingBlock.setGrowthProgress(currentProgress); + blockChunk.markNeedsSaving(); + farmingBlock.setGeneration(farmingBlock.getGeneration() + 1); + if (currentStage >= stages.length) { + if (stages[currentStage - 1].implementsShouldStop()) { + currentStage = stages.length - 1; + farmingBlock.setGrowthProgress(currentStage); + stages[currentStage].apply(commandBuffer, sectionRef, blockRef, x, y, z, stages[currentStage]); + } else { + farmingBlock.setGrowthProgress(stages.length); + commandBuffer.removeEntity(blockRef, RemoveReason.REMOVE); + } + } else { + farmingBlock.setExecutions(0); + stages[currentStage].apply(commandBuffer, sectionRef, blockRef, x, y, z, stages[currentStage - 1]); + } + } + + farmingBlock.setLastTickGameTime(currentTime); + } } } } @@ -170,20 +174,20 @@ public class FarmingUtil { public static void harvest( @Nonnull World world, - @Nonnull ComponentAccessor store, + @Nonnull ComponentAccessor componentAccessor, @Nonnull Ref ref, @Nonnull BlockType blockType, int rotationIndex, @Nonnull Vector3i blockPosition ) { if (world.getGameplayConfig().getWorldConfig().isBlockGatheringAllowed()) { - harvest0(store, ref, blockType, rotationIndex, blockPosition); + harvest0(componentAccessor, ref, blockType, rotationIndex, blockPosition); } } @Nullable public static CapturedNPCMetadata generateCapturedNPCMetadata( - @Nonnull ComponentAccessor componentAccessor, @Nonnull Ref entityRef, int roleIndex + @Nonnull ComponentAccessor componentAccessor, @Nonnull Ref entityRef, String npcNameKey ) { PersistentModel persistentModel = componentAccessor.getComponent(entityRef, PersistentModel.getComponentType()); if (persistentModel == null) { @@ -195,7 +199,7 @@ public class FarmingUtil { meta.setIconPath(modelAsset.getIcon()); } - meta.setRoleIndex(roleIndex); + meta.setNpcNameKey(npcNameKey); return meta; } } @@ -285,7 +289,8 @@ public class FarmingUtil { } else { BlockSection section = chunkStore.getComponent(sectionRef, BlockSection.getComponentType()); if (section != null) { - section.scheduleTick(ChunkUtil.indexBlock(blockPosition.x, blockPosition.y, blockPosition.z), now); + int blockIndex = ChunkUtil.indexBlock(blockPosition.x, blockPosition.y, blockPosition.z); + section.scheduleTick(blockIndex, now); } newStages[0].apply(chunkStore, sectionRef, blockRef, blockPosition.x, blockPosition.y, blockPosition.z, previousStage); @@ -312,6 +317,9 @@ public class FarmingUtil { HarvestingDropType harvest = blockType.getGathering().getHarvest(); String itemId = harvest.getItemId(); String dropListId = harvest.getDropListId(); - BlockHarvestUtils.getDrops(blockType, 1, itemId, dropListId).forEach(itemStack -> ItemUtils.interactivelyPickupItem(ref, itemStack, origin, store)); + + for (ItemStack itemStack : BlockHarvestUtils.getDrops(blockType, 1, itemId, dropListId)) { + ItemUtils.interactivelyPickupItem(ref, itemStack, origin, store); + } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/component/CoopResidentComponent.java b/src/com/hypixel/hytale/builtin/adventure/farming/component/CoopResidentComponent.java index 263afae3..1175cd22 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/component/CoopResidentComponent.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/component/CoopResidentComponent.java @@ -7,9 +7,11 @@ import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CoopResidentComponent implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CoopResidentComponent.class, CoopResidentComponent::new) .append(new KeyedCodec<>("CoopLocation", Vector3i.CODEC), (comp, ref) -> comp.coopLocation = ref, comp -> comp.coopLocation) .add() @@ -20,6 +22,7 @@ public class CoopResidentComponent implements Component { ) .add() .build(); + @Nonnull private Vector3i coopLocation = new Vector3i(); private boolean markedForDespawn; @@ -27,10 +30,11 @@ public class CoopResidentComponent implements Component { return FarmingPlugin.get().getCoopResidentComponentType(); } - public void setCoopLocation(Vector3i coopLocation) { + public void setCoopLocation(@Nonnull Vector3i coopLocation) { this.coopLocation = coopLocation; } + @Nonnull public Vector3i getCoopLocation() { return this.coopLocation; } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/FarmingCoopAsset.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/FarmingCoopAsset.java index 83dc6cad..5788042c 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/FarmingCoopAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/FarmingCoopAsset.java @@ -20,6 +20,7 @@ import java.util.Map; import javax.annotation.Nonnull; public class FarmingCoopAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( FarmingCoopAsset.class, FarmingCoopAsset::new, Codec.STRING, (o, v) -> o.id = v, FarmingCoopAsset::getId, (o, data) -> o.data = data, o -> o.data ) @@ -87,6 +88,7 @@ public class FarmingCoopAsset implements JsonAssetWithMap produceDrops = Collections.emptyMap(); protected IntRange residentRoamTime; + @Nonnull protected Vector3d residentSpawnOffset = new Vector3d(); protected String[] acceptedNpcGroupIds; protected int[] acceptedNpcGroupIndexes; @@ -128,6 +130,7 @@ public class FarmingCoopAsset implements JsonAssetWithMap CODEC = BuilderCodec.builder( FertilizerGrowthModifierAsset.class, FertilizerGrowthModifierAsset::new, ABSTRACT_CODEC ) @@ -18,17 +20,37 @@ public class FertilizerGrowthModifierAsset extends GrowthModifierAsset { @Override public double getCurrentGrowthMultiplier( - CommandBuffer commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z, boolean initialTick + @Nonnull CommandBuffer commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, + int x, + int y, + int z, + boolean initialTick ) { - ChunkSection chunkSection = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - Ref chunk = chunkSection.getChunkColumnReference(); - BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunk, BlockComponentChunk.getComponentType()); - Ref blockRefBelow = blockComponentChunk.getEntityReference(ChunkUtil.indexBlockInColumn(x, y - 1, z)); - if (blockRefBelow == null) { - return 1.0; + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + + assert chunkSectionComponent != null; + + Ref chunkRef = chunkSectionComponent.getChunkColumnReference(); + if (chunkRef != null && chunkRef.isValid()) { + BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunkRef, BlockComponentChunk.getComponentType()); + if (blockComponentChunk == null) { + return 1.0; + } else { + int chunkIndexBelow = ChunkUtil.indexBlockInColumn(x, y - 1, z); + Ref blockBelowRef = blockComponentChunk.getEntityReference(chunkIndexBelow); + if (blockBelowRef != null && blockBelowRef.isValid()) { + TilledSoilBlock belowTilledSoilComponent = commandBuffer.getComponent(blockBelowRef, TilledSoilBlock.getComponentType()); + return belowTilledSoilComponent != null && belowTilledSoilComponent.isFertilized() + ? super.getCurrentGrowthMultiplier(commandBuffer, sectionRef, blockRef, x, y, z, initialTick) + : 1.0; + } else { + return 1.0; + } + } } else { - TilledSoilBlock soil = commandBuffer.getComponent(blockRefBelow, TilledSoilBlock.getComponentType()); - return soil != null && soil.isFertilized() ? super.getCurrentGrowthMultiplier(commandBuffer, sectionRef, blockRef, x, y, z, initialTick) : 1.0; + return 1.0; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/modifiers/LightLevelGrowthModifierAsset.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/modifiers/LightLevelGrowthModifierAsset.java index 7a8521d0..1c288c87 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/modifiers/LightLevelGrowthModifierAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/modifiers/LightLevelGrowthModifierAsset.java @@ -10,12 +10,15 @@ import com.hypixel.hytale.protocol.Rangef; import com.hypixel.hytale.server.core.asset.type.blocktype.config.farming.GrowthModifierAsset; import com.hypixel.hytale.server.core.codec.ProtocolCodecs; import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; +import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection; import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkLightData; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class LightLevelGrowthModifierAsset extends GrowthModifierAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( LightLevelGrowthModifierAsset.class, LightLevelGrowthModifierAsset::new, ABSTRACT_CODEC ) @@ -57,7 +60,7 @@ public class LightLevelGrowthModifierAsset extends GrowthModifierAsset { return isInRange(redRange, red) && isInRange(greenRange, green) && isInRange(blueRange, blue); } - protected boolean checkSunLight(WorldTimeResource worldTimeResource, byte sky) { + protected boolean checkSunLight(@Nonnull WorldTimeResource worldTimeResource, byte sky) { Rangef range = this.sunlight; double sunlightFactor = worldTimeResource.getSunlightFactor(); double daylight = sunlightFactor * sky; @@ -70,19 +73,26 @@ public class LightLevelGrowthModifierAsset extends GrowthModifierAsset { @Override public double getCurrentGrowthMultiplier( - CommandBuffer commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z, boolean initialTick + @Nonnull CommandBuffer commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, + int x, + int y, + int z, + boolean initialTick ) { - BlockSection blockSection = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); - short lightRaw = blockSection.getGlobalLight().getLightRaw(x, y, z); + BlockSection blockSectionComponent = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); + + assert blockSectionComponent != null; + + short lightRaw = blockSectionComponent.getGlobalLight().getLightRaw(x, y, z); byte redLight = ChunkLightData.getLightValue(lightRaw, 0); byte greenLight = ChunkLightData.getLightValue(lightRaw, 1); byte blueLight = ChunkLightData.getLightValue(lightRaw, 2); byte skyLight = ChunkLightData.getLightValue(lightRaw, 3); - WorldTimeResource worldTimeResource = commandBuffer.getExternalData() - .getWorld() - .getEntityStore() - .getStore() - .getResource(WorldTimeResource.getResourceType()); + World world = commandBuffer.getExternalData().getWorld(); + EntityStore entityStore = world.getEntityStore(); + WorldTimeResource worldTimeResource = entityStore.getStore().getResource(WorldTimeResource.getResourceType()); boolean active = false; boolean onlySunlight = false; if (this.requireBoth) { @@ -117,6 +127,7 @@ public class LightLevelGrowthModifierAsset extends GrowthModifierAsset { } public static class ArtificialLight { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( LightLevelGrowthModifierAsset.ArtificialLight.class, LightLevelGrowthModifierAsset.ArtificialLight::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/modifiers/WaterGrowthModifierAsset.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/modifiers/WaterGrowthModifierAsset.java index bf7339d8..465eea7e 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/modifiers/WaterGrowthModifierAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/modifiers/WaterGrowthModifierAsset.java @@ -28,6 +28,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class WaterGrowthModifierAsset extends GrowthModifierAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( WaterGrowthModifierAsset.class, WaterGrowthModifierAsset::new, ABSTRACT_CODEC ) @@ -84,19 +85,28 @@ public class WaterGrowthModifierAsset extends GrowthModifierAsset { @Override public double getCurrentGrowthMultiplier( - CommandBuffer commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z, boolean initialTick + @Nonnull CommandBuffer commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, + int x, + int y, + int z, + boolean initialTick ) { - boolean hasWaterBlock = this.checkIfWaterSource(commandBuffer, sectionRef, blockRef, x, y, z); + boolean hasWaterBlock = this.checkIfWaterSource(commandBuffer, sectionRef, x, y, z); boolean isRaining = this.checkIfRaining(commandBuffer, sectionRef, x, y, z); boolean active = hasWaterBlock || isRaining; TilledSoilBlock soil = getSoil(commandBuffer, sectionRef, x, y, z); if (soil != null) { if (soil.hasExternalWater() != active) { soil.setExternalWater(active); - commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()).setTicking(x, y, z, true); + BlockSection blockSectionComponent = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); + if (blockSectionComponent != null) { + blockSectionComponent.setTicking(x, y, z, true); + } } - active |= this.isSoilWaterExpiring( + active |= isSoilWaterExpiring( commandBuffer.getExternalData().getWorld().getEntityStore().getStore().getResource(WorldTimeResource.getResourceType()), soil ); } @@ -105,15 +115,28 @@ public class WaterGrowthModifierAsset extends GrowthModifierAsset { } @Nullable - private static TilledSoilBlock getSoil(CommandBuffer commandBuffer, Ref sectionRef, int x, int y, int z) { - ChunkSection chunkSection = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - Ref chunk = chunkSection.getChunkColumnReference(); - BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunk, BlockComponentChunk.getComponentType()); - Ref blockRefBelow = blockComponentChunk.getEntityReference(ChunkUtil.indexBlockInColumn(x, y - 1, z)); - return blockRefBelow == null ? null : commandBuffer.getComponent(blockRefBelow, TilledSoilBlock.getComponentType()); + private static TilledSoilBlock getSoil(@Nonnull CommandBuffer commandBuffer, @Nonnull Ref sectionRef, int x, int y, int z) { + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent == null) { + return null; + } else { + Ref chunkRef = chunkSectionComponent.getChunkColumnReference(); + if (chunkRef != null && chunkRef.isValid()) { + BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunkRef, BlockComponentChunk.getComponentType()); + if (blockComponentChunk == null) { + return null; + } else { + int blockBelowIndex = ChunkUtil.indexBlockInColumn(x, y - 1, z); + Ref blockBelowRef = blockComponentChunk.getEntityReference(blockBelowIndex); + return blockBelowRef == null ? null : commandBuffer.getComponent(blockBelowRef, TilledSoilBlock.getComponentType()); + } + } else { + return null; + } + } } - protected boolean checkIfWaterSource(CommandBuffer commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z) { + protected boolean checkIfWaterSource(@Nonnull CommandBuffer commandBuffer, @Nonnull Ref sectionRef, int x, int y, int z) { IntOpenHashSet waterBlocks = this.fluidIds; if (waterBlocks == null) { return false; @@ -122,31 +145,42 @@ public class WaterGrowthModifierAsset extends GrowthModifierAsset { if (soil == null) { return false; } else { - int[] fluids = this.getNeighbourFluids(commandBuffer, sectionRef, x, y - 1, z); - - for (int block : fluids) { - if (waterBlocks.contains(block)) { - return true; + int[] fluids = getNeighbourFluids(commandBuffer, sectionRef, x, y - 1, z); + if (fluids == null) { + return false; + } else { + for (int block : fluids) { + if (waterBlocks.contains(block)) { + return true; + } } - } - return false; + return false; + } } } } - private int[] getNeighbourFluids(CommandBuffer commandBuffer, Ref sectionRef, int x, int y, int z) { - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - return new int[]{ - this.getFluidAtPos(x - 1, y, z, sectionRef, section, commandBuffer), - this.getFluidAtPos(x + 1, y, z, sectionRef, section, commandBuffer), - this.getFluidAtPos(x, y, z - 1, sectionRef, section, commandBuffer), - this.getFluidAtPos(x, y, z + 1, sectionRef, section, commandBuffer) - }; + @Nullable + private static int[] getNeighbourFluids(@Nonnull CommandBuffer commandBuffer, @Nonnull Ref sectionRef, int x, int y, int z) { + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + return chunkSectionComponent == null + ? null + : new int[]{ + getFluidAtPos(x - 1, y, z, sectionRef, chunkSectionComponent, commandBuffer), + getFluidAtPos(x + 1, y, z, sectionRef, chunkSectionComponent, commandBuffer), + getFluidAtPos(x, y, z - 1, sectionRef, chunkSectionComponent, commandBuffer), + getFluidAtPos(x, y, z + 1, sectionRef, chunkSectionComponent, commandBuffer) + }; } - private int getFluidAtPos( - int posX, int posY, int posZ, Ref sectionRef, ChunkSection currentChunkSection, CommandBuffer commandBuffer + private static int getFluidAtPos( + int posX, + int posY, + int posZ, + @Nonnull Ref sectionRef, + @Nonnull ChunkSection currentChunkSection, + @Nonnull CommandBuffer commandBuffer ) { Ref chunkToUse = sectionRef; int chunkX = ChunkUtil.worldCoordFromLocalCoord(currentChunkSection.getX(), posX); @@ -156,49 +190,59 @@ public class WaterGrowthModifierAsset extends GrowthModifierAsset { chunkToUse = commandBuffer.getExternalData().getChunkSectionReference(chunkX, chunkY, chunkZ); } - return chunkToUse == null ? Integer.MIN_VALUE : commandBuffer.getComponent(chunkToUse, FluidSection.getComponentType()).getFluidId(posX, posY, posZ); - } - - protected boolean checkIfRaining(CommandBuffer commandBuffer, Ref sectionRef, int x, int y, int z) { - if (this.weatherIds == null) { - return false; + if (chunkToUse == null) { + return Integer.MIN_VALUE; } else { - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - Ref chunk = section.getChunkColumnReference(); - BlockChunk blockChunk = commandBuffer.getComponent(chunk, BlockChunk.getComponentType()); - int cropId = blockChunk.getBlock(x, y, z); - Store store = commandBuffer.getExternalData().getWorld().getEntityStore().getStore(); - WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType()); - WeatherResource weatherResource = store.getResource(WeatherResource.getResourceType()); - int environment = blockChunk.getEnvironment(x, y, z); - int weatherId; - if (weatherResource.getForcedWeatherIndex() != 0) { - weatherId = weatherResource.getForcedWeatherIndex(); - } else { - weatherId = weatherResource.getWeatherIndexForEnvironment(environment); - } - - if (this.weatherIds.contains(weatherId)) { - boolean unobstructed = true; - - for (int searchY = y + 1; searchY < 320; searchY++) { - int block = blockChunk.getBlock(x, searchY, z); - if (block != 0 && block != cropId) { - unobstructed = false; - break; - } - } - - if (unobstructed) { - return true; - } - } - - return false; + FluidSection fluidSectionComponent = commandBuffer.getComponent(chunkToUse, FluidSection.getComponentType()); + return fluidSectionComponent == null ? Integer.MIN_VALUE : fluidSectionComponent.getFluidId(posX, posY, posZ); } } - private boolean isSoilWaterExpiring(WorldTimeResource worldTimeResource, TilledSoilBlock soilBlock) { + protected boolean checkIfRaining(@Nonnull CommandBuffer commandBuffer, @Nonnull Ref sectionRef, int x, int y, int z) { + if (this.weatherIds == null) { + return false; + } else { + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent == null) { + return false; + } else { + Ref chunkRef = chunkSectionComponent.getChunkColumnReference(); + BlockChunk blockChunkComponent = commandBuffer.getComponent(chunkRef, BlockChunk.getComponentType()); + if (blockChunkComponent == null) { + return false; + } else { + int blockId = blockChunkComponent.getBlock(x, y, z); + Store entityStore = commandBuffer.getExternalData().getWorld().getEntityStore().getStore(); + WeatherResource weatherResource = entityStore.getResource(WeatherResource.getResourceType()); + int environment = blockChunkComponent.getEnvironment(x, y, z); + int weatherId; + if (weatherResource.getForcedWeatherIndex() != 0) { + weatherId = weatherResource.getForcedWeatherIndex(); + } else { + weatherId = weatherResource.getWeatherIndexForEnvironment(environment); + } + + if (!this.weatherIds.contains(weatherId)) { + return false; + } else { + boolean unobstructed = true; + + for (int searchY = y + 1; searchY < 320; searchY++) { + int block = blockChunkComponent.getBlock(x, searchY, z); + if (block != 0 && block != blockId) { + unobstructed = false; + break; + } + } + + return unobstructed; + } + } + } + } + } + + private static boolean isSoilWaterExpiring(@Nonnull WorldTimeResource worldTimeResource, @Nonnull TilledSoilBlock soilBlock) { Instant until = soilBlock.getWateredUntil(); if (until == null) { return false; diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/BlockStateFarmingStageData.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/BlockStateFarmingStageData.java index 096423c7..c95da9cb 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/BlockStateFarmingStageData.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/BlockStateFarmingStageData.java @@ -5,17 +5,22 @@ import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.farming.FarmingStageData; import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockStateFarmingStageData extends FarmingStageData { @Nonnull - public static BuilderCodec CODEC = BuilderCodec.builder( + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder( BlockStateFarmingStageData.class, BlockStateFarmingStageData::new, FarmingStageData.BASE_CODEC ) .append(new KeyedCodec<>("State", Codec.STRING), (stage, block) -> stage.state = block, stage -> stage.state) @@ -29,25 +34,49 @@ public class BlockStateFarmingStageData extends FarmingStageData { @Override public void apply( - ComponentAccessor commandBuffer, - Ref sectionRef, - Ref blockRef, + @Nonnull ComponentAccessor commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, int x, int y, int z, @Nullable FarmingStageData previousStage ) { super.apply(commandBuffer, sectionRef, blockRef, x, y, z, previousStage); - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - WorldChunk worldChunk = commandBuffer.getComponent(section.getChunkColumnReference(), WorldChunk.getComponentType()); - int origBlockId = worldChunk.getBlock(x, y, z); - BlockType origBlockType = BlockType.getAssetMap().getAsset(origBlockId); - BlockType blockType = origBlockType.getBlockForState(this.state); - if (blockType != null) { - int newType = BlockType.getAssetMap().getIndex(blockType.getId()); - if (origBlockId != newType) { - int rotation = worldChunk.getRotationIndex(x, y, z); - commandBuffer.getExternalData().getWorld().execute(() -> worldChunk.setBlock(x, y, z, newType, blockType, rotation, 0, 2)); + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing chunk section component when applying state farming stage at (%d, %d, %d)", x, y, z); + } else { + WorldChunk worldChunkComponent = commandBuffer.getComponent(chunkSectionComponent.getChunkColumnReference(), WorldChunk.getComponentType()); + if (worldChunkComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing world chunk component when applying state farming stage at (%d, %d, %d)", x, y, z); + } else { + int originBlockId = worldChunkComponent.getBlock(x, y, z); + BlockType originBlockType = BlockType.getAssetMap().getAsset(originBlockId); + if (originBlockType == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing origin block type for block ID '%s' when applying state farming stage at (%d, %d, %d)", String.valueOf(originBlockId), x, y, z); + } else { + BlockType blockType = originBlockType.getBlockForState(this.state); + if (blockType == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing new block type '%s' when applying state farming stage at (%d, %d, %d)", this.state, x, y, z); + } else { + int newBlockId = BlockType.getAssetMap().getIndex(blockType.getId()); + if (originBlockId != newBlockId) { + int rotationIndex = worldChunkComponent.getRotationIndex(x, y, z); + commandBuffer.getExternalData() + .getWorld() + .execute(() -> worldChunkComponent.setBlock(x, y, z, newBlockId, blockType, rotationIndex, 0, 2)); + } + } + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/BlockTypeFarmingStageData.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/BlockTypeFarmingStageData.java index 1e20b215..2406e680 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/BlockTypeFarmingStageData.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/BlockTypeFarmingStageData.java @@ -5,17 +5,22 @@ import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.farming.FarmingStageData; import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockTypeFarmingStageData extends FarmingStageData { @Nonnull - public static BuilderCodec CODEC = BuilderCodec.builder( + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder( BlockTypeFarmingStageData.class, BlockTypeFarmingStageData::new, FarmingStageData.BASE_CODEC ) .append(new KeyedCodec<>("Block", Codec.STRING), (stage, block) -> stage.block = block, stage -> stage.block) @@ -30,21 +35,42 @@ public class BlockTypeFarmingStageData extends FarmingStageData { @Override public void apply( - ComponentAccessor commandBuffer, - Ref sectionRef, - Ref blockRef, + @Nonnull ComponentAccessor commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, int x, int y, int z, @Nullable FarmingStageData previousStage ) { super.apply(commandBuffer, sectionRef, blockRef, x, y, z, previousStage); - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - WorldChunk worldChunk = commandBuffer.getComponent(section.getChunkColumnReference(), WorldChunk.getComponentType()); - int blockId = BlockType.getAssetMap().getIndex(this.block); - if (blockId != worldChunk.getBlock(x, y, z)) { - BlockType blockType = BlockType.getAssetMap().getAsset(blockId); - commandBuffer.getExternalData().getWorld().execute(() -> worldChunk.setBlock(x, y, z, blockId, blockType, worldChunk.getRotationIndex(x, y, z), 0, 2)); + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing chunk section component when applying state farming stage at (%d, %d, %d)", x, y, z); + } else { + WorldChunk worldChunkComponent = commandBuffer.getComponent(chunkSectionComponent.getChunkColumnReference(), WorldChunk.getComponentType()); + if (worldChunkComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing world chunk component when applying state farming stage at (%d, %d, %d)", x, y, z); + } else { + int blockId = BlockType.getAssetMap().getIndex(this.block); + if (blockId != worldChunkComponent.getBlock(x, y, z)) { + BlockType blockType = BlockType.getAssetMap().getAsset(blockId); + if (blockType == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Invalid block type '%s' when applying block type farming stage at (%d, %d, %d)", this.block, x, y, z); + } else { + commandBuffer.getExternalData().getWorld().execute(() -> { + int rotationIndex = worldChunkComponent.getRotationIndex(x, y, z); + worldChunkComponent.setBlock(x, y, z, blockId, blockType, rotationIndex, 0, 2); + }); + } + } + } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/PrefabFarmingStageData.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/PrefabFarmingStageData.java index f5785e91..dde600e8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/PrefabFarmingStageData.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/PrefabFarmingStageData.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.common.map.IWeightedElement; import com.hypixel.hytale.common.map.IWeightedMap; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.util.FastRandom; import com.hypixel.hytale.math.util.HashUtil; @@ -40,17 +41,22 @@ import com.hypixel.hytale.server.core.util.PrefabUtil; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PrefabFarmingStageData extends FarmingStageData { + @Nonnull + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static final float MIN_VOLUME_PREFAB = 125.0F; public static final float MAX_VOLUME_PREFAB = 1000.0F; public static final float MIN_BROKEN_PARTICLE_RATE = 0.25F; public static final float MAX_BROKEN_PARTICLE_RATE = 0.75F; + @Nonnull private static final String[] EMPTY_REPLACE_MASK = new String[0]; @Nonnull - public static BuilderCodec CODEC = BuilderCodec.builder( + public static final BuilderCodec CODEC = BuilderCodec.builder( PrefabFarmingStageData.class, PrefabFarmingStageData::new, FarmingStageData.BASE_CODEC ) .append( @@ -77,12 +83,12 @@ public class PrefabFarmingStageData extends FarmingStageData { double zLength = prefab.getMaxZ() - prefab.getMinZ(); double volume = xLength * yLength * zLength; double ratio = -5.7142857E-4F; - double rate = (volume - 125.0) * ratio; + double rate = (volume - 125.0) * -5.7142857E-4F; return MathUtil.clamp(rate + 0.75, 0.25, 0.75); } private static boolean isPrefabBlockIntact( - LocalCachedChunkAccessor chunkAccessor, + @Nonnull LocalCachedChunkAccessor chunkAccessor, int worldX, int worldY, int worldZ, @@ -91,33 +97,40 @@ public class PrefabFarmingStageData extends FarmingStageData { int blockZ, int blockId, int rotation, - PrefabRotation prefabRotation + @Nonnull PrefabRotation prefabRotation ) { int globalX = prefabRotation.getX(blockX, blockZ) + worldX; int globalY = blockY + worldY; int globalZ = prefabRotation.getZ(blockX, blockZ) + worldZ; - BlockType block = BlockType.getAssetMap().getAsset(blockId); - if (block.getMaterial() == BlockMaterial.Empty) { - return true; - } else { - WorldChunk chunk = chunkAccessor.getNonTickingChunk(ChunkUtil.indexChunkFromBlock(globalX, globalZ)); - if (chunk == null) { + BlockType blockType = BlockType.getAssetMap().getAsset(blockId); + if (blockType != null && blockType.getMaterial() != BlockMaterial.Empty) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(globalX, globalZ); + WorldChunk worldChunkComponent = chunkAccessor.getNonTickingChunk(chunkIndex); + if (worldChunkComponent == null) { return false; } else { - int worldBlockId = chunk.getBlock(globalX, globalY, globalZ); + int worldBlockId = worldChunkComponent.getBlock(globalX, globalY, globalZ); if (worldBlockId != blockId) { return false; } else { int expectedRotation = prefabRotation.getRotation(rotation); - int worldRotation = chunk.getRotationIndex(globalX, globalY, globalZ); + int worldRotation = worldChunkComponent.getRotationIndex(globalX, globalY, globalZ); return worldRotation == expectedRotation; } } + } else { + return true; } } private static boolean isPrefabIntact( - IPrefabBuffer prefabBuffer, LocalCachedChunkAccessor chunkAccessor, int worldX, int worldY, int worldZ, PrefabRotation prefabRotation, FastRandom random + @Nonnull IPrefabBuffer prefabBuffer, + @Nonnull LocalCachedChunkAccessor chunkAccessor, + int worldX, + int worldY, + int worldZ, + @Nonnull PrefabRotation prefabRotation, + @Nonnull FastRandom random ) { return prefabBuffer.forEachRaw( IPrefabBuffer.iterateAllColumns(), @@ -136,144 +149,210 @@ public class PrefabFarmingStageData extends FarmingStageData { @Override public void apply( - ComponentAccessor commandBuffer, - Ref sectionRef, - Ref blockRef, + @Nonnull ComponentAccessor commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, int x, int y, int z, @Nullable FarmingStageData previousStage ) { - FarmingBlock farming = commandBuffer.getComponent(blockRef, FarmingBlock.getComponentType()); - IPrefabBuffer prefabBuffer = this.getCachedPrefab(x, y, z, farming.getGeneration()); - BlockSection blockSection = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); - int randomRotation = HashUtil.randomInt(x, y, z, Rotation.VALUES.length); - RotationTuple yaw = RotationTuple.of(Rotation.VALUES[randomRotation], Rotation.None); - World world = commandBuffer.getExternalData().getWorld(); - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - int worldX = ChunkUtil.worldCoordFromLocalCoord(section.getX(), x); - int worldY = ChunkUtil.worldCoordFromLocalCoord(section.getY(), y); - int worldZ = ChunkUtil.worldCoordFromLocalCoord(section.getZ(), z); - if (farming.getPreviousBlockType() == null) { - farming.setPreviousBlockType(BlockType.getAssetMap().getAsset(blockSection.get(x, y, z)).getId()); - } - - double xLength = prefabBuffer.getMaxX() - prefabBuffer.getMinX(); - double zLength = prefabBuffer.getMaxZ() - prefabBuffer.getMinZ(); - int prefabRadius = (int)MathUtil.fastFloor(0.5 * Math.sqrt(xLength * xLength + zLength * zLength)); - LocalCachedChunkAccessor chunkAccessor = LocalCachedChunkAccessor.atWorldCoords(world, x, z, prefabRadius); - FastRandom random = new FastRandom(); - PrefabRotation prefabRotation = PrefabRotation.fromRotation(yaw.yaw()); - BlockTypeAssetMap blockTypeMap = BlockType.getAssetMap(); - if (previousStage instanceof PrefabFarmingStageData oldPrefab) { - IPrefabBuffer oldPrefabBuffer = oldPrefab.getCachedPrefab(worldX, worldY, worldZ, farming.getGeneration() - 1); - double brokenParticlesRate = computeParticlesRate(prefabBuffer); - world.execute( - () -> { - boolean isIntact = isPrefabIntact(oldPrefabBuffer, chunkAccessor, worldX, worldY, worldZ, prefabRotation, random); - if (isIntact) { - boolean isUnobstructed = prefabBuffer.compare( - (px, py, pz, blockId, stateWrapper, chance, rotation, filler, secondBlockId, secondStateWrapper, secondChance, secondRotation, secondFiller, prefabBufferCall) -> { - int bx = worldX + px; - int by = worldY + py; - int bz = worldZ + pz; - if ((secondBlockId == 0 || secondBlockId == Integer.MIN_VALUE) && blockId != 0 && blockId != Integer.MIN_VALUE) { - WorldChunk nonTickingChunk = chunkAccessor.getNonTickingChunk(ChunkUtil.indexChunkFromBlock(bx, bz)); - int worldBlock = nonTickingChunk.getBlock(bx, by, bz); - return !this.doesBlockObstruct(blockId, worldBlock); - } else { - return true; - } - }, - new PrefabBufferCall(random, prefabRotation), - oldPrefabBuffer - ); - if (isUnobstructed) { - prefabBuffer.compare( - (px, py, pz, blockId, stateWrapper, chance, rotation, filler, secondBlockId, secondStateWrapper, secondChance, secondRotation, secondFiller, prefabBufferCall) -> { - int bx = worldX + px; - int by = worldY + py; - int bz = worldZ + pz; - WorldChunk nonTickingChunk = chunkAccessor.getNonTickingChunk(ChunkUtil.indexChunkFromBlock(bx, bz)); - int updatedSetBlockSettings = 2; - if (random.nextDouble() > brokenParticlesRate) { - updatedSetBlockSettings |= 4; - } - - if (blockId != 0 && blockId != Integer.MIN_VALUE) { - BlockType block = blockTypeMap.getAsset(blockId); - if (filler != 0) { - return true; - } - - int worldBlock = nonTickingChunk.getBlock(bx, by, bz); - if ((secondBlockId == 0 || secondBlockId == Integer.MIN_VALUE) && !this.canReplace(worldBlock, blockTypeMap)) { - return true; - } - - nonTickingChunk.setBlock(bx, by, bz, blockId, block, rotation, filler, updatedSetBlockSettings); - if (stateWrapper != null) { - nonTickingChunk.setState(bx, by, bz, stateWrapper.clone()); - } - } else if (secondBlockId != 0 && secondBlockId != Integer.MIN_VALUE) { - nonTickingChunk.breakBlock(bx, by, bz, updatedSetBlockSettings); - } - - return true; - }, - new PrefabBufferCall(random, prefabRotation), - oldPrefabBuffer - ); - } - } - } - ); + FarmingBlock farmingBlockComponent = commandBuffer.getComponent(blockRef, FarmingBlock.getComponentType()); + if (farmingBlockComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing farming block component when applying prefab farming stage at (%d, %d, %d)", x, y, z); } else { - super.apply(commandBuffer, sectionRef, blockRef, x, y, z, previousStage); - world.execute( - () -> { - boolean isUnObstructed = prefabBuffer.forEachRaw( - IPrefabBuffer.iterateAllColumns(), (blockX, blockY, blockZ, blockId, chance, holder, supportValue, rotation, filler, t) -> { - int bx = worldX + prefabRotation.getX(blockX, blockZ); - int by = worldY + blockY; - int bz = worldZ + prefabRotation.getX(blockZ, blockX); - if (blockId != 0 && blockId != Integer.MIN_VALUE) { - int worldBlock = chunkAccessor.getNonTickingChunk(ChunkUtil.indexChunkFromBlock(bx, bz)).getBlock(bx, by, bz); - return !this.doesBlockObstruct(blockId, worldBlock); - } else { - return true; - } - }, (fluidX, fluidY, fluidZ, fluidId, level, o) -> true, null, new PrefabBufferCall(random, prefabRotation) - ); - if (isUnObstructed) { - prefabBuffer.forEach( - IPrefabBuffer.iterateAllColumns(), (blockX, blockY, blockZ, blockId, holder, supportValue, rotation, filler, t, fluidId, fluidLevel) -> { - int bx = worldX + blockX; - int by = worldY + blockY; - int bz = worldZ + blockZ; - WorldChunk nonTickingChunk = chunkAccessor.getNonTickingChunk(ChunkUtil.indexChunkFromBlock(bx, bz)); - int updatedSetBlockSettings = 2; - if (blockId != 0 && blockId != Integer.MIN_VALUE) { - BlockType block = blockTypeMap.getAsset(blockId); - if (filler != 0) { - return; - } - - int worldBlock = nonTickingChunk.getBlock(bx, by, bz); - if (!this.canReplace(worldBlock, blockTypeMap)) { - return; - } - - nonTickingChunk.setBlock(bx, by, bz, blockId, block, rotation, filler, updatedSetBlockSettings); - if (holder != null) { - nonTickingChunk.setState(bx, by, bz, holder.clone()); - } - } - }, null, null, new PrefabBufferCall(random, prefabRotation) - ); - } + IPrefabBuffer prefabBuffer = this.getCachedPrefab(x, y, z, farmingBlockComponent.getGeneration()); + BlockSection blockSection = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); + int randomRotation = HashUtil.randomInt(x, y, z, Rotation.VALUES.length); + RotationTuple yaw = RotationTuple.of(Rotation.VALUES[randomRotation], Rotation.None); + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing chunk section component when applying prefab farming stage at (%d, %d, %d)", x, y, z); + } else { + int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getX(), x); + int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getY(), y); + int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getZ(), z); + if (farmingBlockComponent.getPreviousBlockType() == null) { + farmingBlockComponent.setPreviousBlockType(BlockType.getAssetMap().getAsset(blockSection.get(x, y, z)).getId()); } - ); + + double xLength = prefabBuffer.getMaxX() - prefabBuffer.getMinX(); + double zLength = prefabBuffer.getMaxZ() - prefabBuffer.getMinZ(); + int prefabRadius = (int)MathUtil.fastFloor(0.5 * Math.sqrt(xLength * xLength + zLength * zLength)); + World world = commandBuffer.getExternalData().getWorld(); + LocalCachedChunkAccessor chunkAccessor = LocalCachedChunkAccessor.atWorldCoords(world, x, z, prefabRadius); + FastRandom random = new FastRandom(); + PrefabRotation prefabRotation = PrefabRotation.fromRotation(yaw.yaw()); + BlockTypeAssetMap blockTypeMap = BlockType.getAssetMap(); + if (previousStage instanceof PrefabFarmingStageData oldPrefab) { + IPrefabBuffer oldPrefabBuffer = oldPrefab.getCachedPrefab(worldX, worldY, worldZ, farmingBlockComponent.getGeneration() - 1); + double brokenParticlesRate = computeParticlesRate(prefabBuffer); + world.execute( + () -> { + boolean isIntact = isPrefabIntact(oldPrefabBuffer, chunkAccessor, worldX, worldY, worldZ, prefabRotation, random); + if (isIntact) { + boolean isUnobstructed = prefabBuffer.compare( + (px, py, pz, blockId, stateWrapper, chance, rotation, filler, secondBlockId, secondStateWrapper, secondChance, secondRotation, secondFiller, prefabBufferCall) -> { + int bx = worldX + px; + int by = worldY + py; + int bz = worldZ + pz; + if ((secondBlockId == 0 || secondBlockId == Integer.MIN_VALUE) && blockId != 0 && blockId != Integer.MIN_VALUE) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(bx, bz); + WorldChunk nonTickingChunk = chunkAccessor.getNonTickingChunk(chunkIndex); + if (nonTickingChunk == null) { + return false; + } else { + int worldBlock = nonTickingChunk.getBlock(bx, by, bz); + return !this.doesBlockObstruct(blockId, worldBlock); + } + } else { + return true; + } + }, + new PrefabBufferCall(random, prefabRotation), + oldPrefabBuffer + ); + if (isUnobstructed) { + prefabBuffer.compare( + (px, py, pz, blockId, stateWrapper, chance, rotation, filler, secondBlockId, secondStateWrapper, secondChance, secondRotation, secondFiller, prefabBufferCall) -> { + int bx = worldX + px; + int by = worldY + py; + int bz = worldZ + pz; + long chunkIndex = ChunkUtil.indexChunkFromBlock(bx, bz); + WorldChunk nonTickingChunk = chunkAccessor.getNonTickingChunk(chunkIndex); + if (nonTickingChunk == null) { + return true; + } else { + int updatedSetBlockSettings = 2; + if (random.nextDouble() > brokenParticlesRate) { + updatedSetBlockSettings |= 4; + } + + if (blockId != 0 && blockId != Integer.MIN_VALUE) { + BlockType block = blockTypeMap.getAsset(blockId); + if (block == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log( + "Invalid block ID %d in prefab at (%d, %d, %d) for farming stage at (%d, %d, %d)", + blockId, + px, + py, + pz, + worldX, + worldY, + worldZ + ); + return true; + } + + if (filler != 0) { + return true; + } + + int worldBlock = nonTickingChunk.getBlock(bx, by, bz); + if ((secondBlockId == 0 || secondBlockId == Integer.MIN_VALUE) && !this.canReplace(worldBlock, blockTypeMap)) { + return true; + } + + nonTickingChunk.setBlock(bx, by, bz, blockId, block, rotation, filler, updatedSetBlockSettings); + if (stateWrapper != null) { + nonTickingChunk.setState(bx, by, bz, stateWrapper.clone()); + } + } else if (secondBlockId != 0 && secondBlockId != Integer.MIN_VALUE) { + nonTickingChunk.breakBlock(bx, by, bz, updatedSetBlockSettings); + } + + return true; + } + }, + new PrefabBufferCall(random, prefabRotation), + oldPrefabBuffer + ); + } + } + } + ); + } else { + super.apply(commandBuffer, sectionRef, blockRef, x, y, z, previousStage); + world.execute( + () -> { + boolean isUnObstructed = prefabBuffer.forEachRaw( + IPrefabBuffer.iterateAllColumns(), (blockX, blockY, blockZ, blockId, chance, holder, supportValue, rotation, filler, t) -> { + int bx = worldX + prefabRotation.getX(blockX, blockZ); + int by = worldY + blockY; + int bz = worldZ + prefabRotation.getX(blockZ, blockX); + if (blockId != 0 && blockId != Integer.MIN_VALUE) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(bx, bz); + WorldChunk nonTickingWorldChunkComponent = chunkAccessor.getNonTickingChunk(chunkIndex); + if (nonTickingWorldChunkComponent == null) { + return false; + } else { + int worldBlock = nonTickingWorldChunkComponent.getBlock(bx, by, bz); + return !this.doesBlockObstruct(blockId, worldBlock); + } + } else { + return true; + } + }, (fluidX, fluidY, fluidZ, fluidId, level, o) -> true, null, new PrefabBufferCall(random, prefabRotation) + ); + if (isUnObstructed) { + prefabBuffer.forEach( + IPrefabBuffer.iterateAllColumns(), + (blockX, blockY, blockZ, blockId, holder, supportValue, rotation, filler, t, fluidId, fluidLevel) -> { + int bx = worldX + blockX; + int by = worldY + blockY; + int bz = worldZ + blockZ; + long chunkIndex = ChunkUtil.indexChunkFromBlock(bx, bz); + WorldChunk nonTickingWorldChunkComponent = chunkAccessor.getNonTickingChunk(chunkIndex); + if (nonTickingWorldChunkComponent != null) { + if (blockId != 0 && blockId != Integer.MIN_VALUE) { + BlockType blockTypeAsset = blockTypeMap.getAsset(blockId); + if (blockTypeAsset == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log( + "Invalid block ID %d in prefab at (%d, %d, %d) for farming stage at (%d, %d, %d)", + blockId, + blockX, + blockY, + blockZ, + worldX, + worldY, + worldZ + ); + return; + } + + if (filler != 0) { + return; + } + + int worldBlock = nonTickingWorldChunkComponent.getBlock(bx, by, bz); + if (!this.canReplace(worldBlock, blockTypeMap)) { + return; + } + + nonTickingWorldChunkComponent.setBlock(bx, by, bz, blockId, blockTypeAsset, rotation, filler, 2); + if (holder != null) { + nonTickingWorldChunkComponent.setState(bx, by, bz, holder.clone()); + } + } + } + }, + null, + null, + new PrefabBufferCall(random, prefabRotation) + ); + } + } + ); + } + } } } @@ -283,7 +362,7 @@ public class PrefabFarmingStageData extends FarmingStageData { return blockType != null && blockType.getMaterial() != BlockMaterial.Empty ? !this.canReplace(worldBlockId, assetMap) : false; } - private boolean canReplace(int worldBlockId, BlockTypeAssetMap assetMap) { + private boolean canReplace(int worldBlockId, @Nonnull BlockTypeAssetMap assetMap) { BlockType worldBlockType = assetMap.getAsset(worldBlockId); if (worldBlockType != null && worldBlockType.getMaterial() != BlockMaterial.Empty) { for (int tagIndex : this.replaceMaskTagIndices) { @@ -299,18 +378,39 @@ public class PrefabFarmingStageData extends FarmingStageData { } @Override - public void remove(ComponentAccessor commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z) { + public void remove( + @Nonnull ComponentAccessor commandBuffer, @Nonnull Ref sectionRef, @Nonnull Ref blockRef, int x, int y, int z + ) { super.remove(commandBuffer, sectionRef, blockRef, x, y, z); - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - int worldX = ChunkUtil.worldCoordFromLocalCoord(section.getX(), x); - int worldY = ChunkUtil.worldCoordFromLocalCoord(section.getY(), y); - int worldZ = ChunkUtil.worldCoordFromLocalCoord(section.getZ(), z); - FarmingBlock farming = commandBuffer.getComponent(blockRef, FarmingBlock.getComponentType()); - IPrefabBuffer prefab = this.getCachedPrefab(worldX, worldY, worldZ, farming.getGeneration() - 1); - RotationTuple rotation = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()).getRotation(x, y, z); - double rate = computeParticlesRate(prefab); - World world = commandBuffer.getExternalData().getWorld(); - world.execute(() -> PrefabUtil.remove(prefab, world, new Vector3i(worldX, worldY, worldZ), rotation.yaw(), true, new FastRandom(), 2, rate)); + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing chunk section component when removing prefab farming stage at (%d, %d, %d)", x, y, z); + } else { + int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getX(), x); + int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getY(), y); + int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getZ(), z); + FarmingBlock farmingBlockComponent = commandBuffer.getComponent(blockRef, FarmingBlock.getComponentType()); + if (farmingBlockComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing farming block component when removing prefab farming stage at (%d, %d, %d)", worldX, worldY, worldZ); + } else { + IPrefabBuffer prefab = this.getCachedPrefab(worldX, worldY, worldZ, farmingBlockComponent.getGeneration() - 1); + BlockSection blockSectionComponent = commandBuffer.getComponent(sectionRef, BlockSection.getComponentType()); + if (blockSectionComponent == null) { + LOGGER.at(Level.WARNING) + .atMostEvery(1, TimeUnit.MINUTES) + .log("Missing block section component when removing prefab farming stage at (%d, %d, %d)", worldX, worldY, worldZ); + } else { + RotationTuple rotation = blockSectionComponent.getRotation(x, y, z); + double rate = computeParticlesRate(prefab); + World world = commandBuffer.getExternalData().getWorld(); + world.execute(() -> PrefabUtil.remove(prefab, world, new Vector3i(worldX, worldY, worldZ), rotation.yaw(), true, new FastRandom(), 2, rate)); + } + } + } } @Nonnull @@ -326,15 +426,17 @@ public class PrefabFarmingStageData extends FarmingStageData { } } + @Nonnull @Override public String toString() { return "PrefabFarmingStageData{replaceMaskTags=" + Arrays.toString((Object[])this.replaceMaskTags) + ", prefabStages=" + this.prefabStages + "}"; } public static class PrefabStage implements IWeightedElement { + @Nonnull public static final PrefabFarmingStageData.PrefabStage[] EMPTY_ARRAY = new PrefabFarmingStageData.PrefabStage[0]; @Nonnull - public static Codec CODEC = BuilderCodec.builder( + public static final Codec CODEC = BuilderCodec.builder( PrefabFarmingStageData.PrefabStage.class, PrefabFarmingStageData.PrefabStage::new ) .append(new KeyedCodec<>("Weight", Codec.INTEGER), (prefabStage, integer) -> prefabStage.weight = integer, prefabStage -> prefabStage.weight) diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/DirectionalGrowthBehaviour.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/DirectionalGrowthBehaviour.java index 82226cbe..f682ebfd 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/DirectionalGrowthBehaviour.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/DirectionalGrowthBehaviour.java @@ -32,6 +32,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import javax.annotation.Nonnull; public class DirectionalGrowthBehaviour extends SpreadGrowthBehaviour { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DirectionalGrowthBehaviour.class, DirectionalGrowthBehaviour::new, BASE_CODEC ) @@ -92,9 +93,9 @@ public class DirectionalGrowthBehaviour extends SpreadGrowthBehaviour { @Override public void execute( - ComponentAccessor commandBuffer, - Ref sectionRef, - Ref blockRef, + @Nonnull ComponentAccessor componentAccessor, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, int worldX, int worldY, int worldZ, @@ -103,54 +104,68 @@ public class DirectionalGrowthBehaviour extends SpreadGrowthBehaviour { int x = 0; int z = 0; FastRandom random = new FastRandom(); - String blockTypeKey = this.blockTypes.get(random).getBlockTypeKey(); - World world = commandBuffer.getExternalData().getWorld(); - LocalCachedChunkAccessor chunkAccessor = LocalCachedChunkAccessor.atWorldCoords(world, worldX, worldZ, 1); + DirectionalGrowthBehaviour.BlockTypeWeight blockTypeWeight = this.blockTypes.get(random); + if (blockTypeWeight != null) { + String blockTypeKey = blockTypeWeight.getBlockTypeKey(); + World world = componentAccessor.getExternalData().getWorld(); + LocalCachedChunkAccessor chunkAccessor = LocalCachedChunkAccessor.atWorldCoords(world, worldX, worldZ, 1); - for (int i = 0; i < 100; i++) { - if (this.horizontalRange != null) { - double angle = (float) (Math.PI * 2) * random.nextFloat(); - int radius = this.horizontalRange.getInt(random.nextFloat()); - x = MathUtil.fastRound(radius * TrigMathUtil.cos(angle)); - z = MathUtil.fastRound(radius * TrigMathUtil.sin(angle)); - } - - int targetX = worldX + x; - int targetZ = worldZ + z; - int chunkX = ChunkUtil.chunkCoordinate(targetX); - int chunkZ = ChunkUtil.chunkCoordinate(targetZ); - WorldChunk chunk = chunkAccessor.getChunkIfInMemory(ChunkUtil.indexChunk(chunkX, chunkZ)); - if (chunk != null) { - int targetY; - if (this.verticalRange != null) { - int directionValue = switch (this.verticalDirection) { - case DOWNWARDS, UPWARDS -> this.verticalDirection.getValue(); - case BOTH -> random.nextBoolean() ? 1 : -1; - }; - targetY = worldY + this.verticalRange.getInt(random.nextFloat()) * directionValue; - } else { - targetY = chunk.getHeight(targetX, targetZ) + 1; + for (int i = 0; i < 100; i++) { + if (this.horizontalRange != null) { + double angle = (float) (Math.PI * 2) * random.nextFloat(); + int radius = this.horizontalRange.getInt(random.nextFloat()); + x = MathUtil.fastRound(radius * TrigMathUtil.cos(angle)); + z = MathUtil.fastRound(radius * TrigMathUtil.sin(angle)); } - if (this.tryPlaceBlock(world, chunk, targetX, targetY, targetZ, blockTypeKey, 0)) { - int finalTargetY = targetY; - world.execute(() -> { - WorldChunk loadedChunk = chunkAccessor.getChunk(ChunkUtil.indexChunk(chunkX, chunkZ)); - if (loadedChunk != null) { - loadedChunk.placeBlock(targetX, finalTargetY, targetZ, blockTypeKey, Rotation.None, Rotation.None, Rotation.None); - decaySpread(commandBuffer, loadedChunk.getBlockComponentChunk(), targetX, finalTargetY, targetZ, newSpreadRate); - } - }); - return; + int targetX = worldX + x; + int targetZ = worldZ + z; + int chunkX = ChunkUtil.chunkCoordinate(targetX); + int chunkZ = ChunkUtil.chunkCoordinate(targetZ); + long chunkIndex = ChunkUtil.indexChunk(chunkX, chunkZ); + WorldChunk worldChunkComponent = chunkAccessor.getChunkIfInMemory(chunkIndex); + if (worldChunkComponent != null) { + int targetY; + if (this.verticalRange != null) { + int directionValue = switch (this.verticalDirection) { + case DOWNWARDS, UPWARDS -> this.verticalDirection.getValue(); + case BOTH -> random.nextBoolean() ? 1 : -1; + }; + targetY = worldY + this.verticalRange.getInt(random.nextFloat()) * directionValue; + } else { + targetY = worldChunkComponent.getHeight(targetX, targetZ) + 1; + } + + if (this.tryPlaceBlock(world, worldChunkComponent, targetX, targetY, targetZ, blockTypeKey, 0)) { + int finalTargetY = targetY; + world.execute(() -> { + long loadedChunkIndex = ChunkUtil.indexChunk(chunkX, chunkZ); + WorldChunk loadedChunk = chunkAccessor.getChunk(loadedChunkIndex); + if (loadedChunk != null) { + loadedChunk.placeBlock(targetX, finalTargetY, targetZ, blockTypeKey, Rotation.None, Rotation.None, Rotation.None); + BlockComponentChunk blockComponentChunk = loadedChunk.getBlockComponentChunk(); + if (blockComponentChunk != null) { + decaySpread(componentAccessor, blockComponentChunk, targetX, finalTargetY, targetZ, newSpreadRate); + } + } + }); + return; + } } } } } private static void decaySpread( - ComponentAccessor commandBuffer, BlockComponentChunk blockComponentChunk, int worldX, int worldY, int worldZ, float newSpreadRate + @Nonnull ComponentAccessor commandBuffer, + @Nonnull BlockComponentChunk blockComponentChunk, + int worldX, + int worldY, + int worldZ, + float newSpreadRate ) { - Ref blockRefPlaced = blockComponentChunk.getEntityReference(ChunkUtil.indexBlockInColumn(worldX, worldY, worldZ)); + int blockIndex = ChunkUtil.indexBlockInColumn(worldX, worldY, worldZ); + Ref blockRefPlaced = blockComponentChunk.getEntityReference(blockIndex); if (blockRefPlaced != null) { FarmingBlock farmingPlaced = commandBuffer.getComponent(blockRefPlaced, FarmingBlock.getComponentType()); if (farmingPlaced != null) { @@ -159,37 +174,58 @@ public class DirectionalGrowthBehaviour extends SpreadGrowthBehaviour { } } - private boolean tryPlaceBlock(@Nonnull World world, @Nonnull WorldChunk chunk, int worldX, int worldY, int worldZ, String blockTypeKey, int rotation) { + private boolean tryPlaceBlock( + @Nonnull World world, @Nonnull WorldChunk chunk, int worldX, int worldY, int worldZ, @Nonnull String blockTypeKey, int rotation + ) { if (chunk.getBlock(worldX, worldY, worldZ) != 0) { return false; } else if (!this.validatePosition(world, worldX, worldY, worldZ)) { return false; } else { - BlockType blockType = BlockType.getAssetMap().getAsset(blockTypeKey); - if (blockType == null) { + BlockType blockTypeAsset = BlockType.getAssetMap().getAsset(blockTypeKey); + if (blockTypeAsset == null) { return false; - } else if (!chunk.testPlaceBlock(worldX, worldY, worldZ, blockType, rotation)) { + } else if (!chunk.testPlaceBlock(worldX, worldY, worldZ, blockTypeAsset, rotation)) { return false; } else { - int cx = chunk.getX(); - int cz = chunk.getZ(); - int cy = ChunkUtil.indexSection(worldY); - Ref sectionRef = world.getChunkStore().getChunkSectionReference(cx, cy, cz); - if (sectionRef == null) { - return false; - } else { - Store store = world.getChunkStore().getStore(); - BlockPhysics blockPhysics = store.getComponent(sectionRef, BlockPhysics.getComponentType()); - FluidSection fluidSection = store.getComponent(sectionRef, FluidSection.getComponentType()); - BlockSection blockSection = store.getComponent(sectionRef, BlockSection.getComponentType()); - int filler = blockSection.getFiller(worldX, worldY, worldZ); + int chunkX = chunk.getX(); + int chunkY = ChunkUtil.indexSection(worldY); + int chunkZ = chunk.getZ(); + ChunkStore chunkStore = world.getChunkStore(); + Ref sectionRef = chunkStore.getChunkSectionReference(chunkX, chunkY, chunkZ); + if (sectionRef != null && sectionRef.isValid()) { + Store store = chunkStore.getStore(); + BlockPhysics blockPhysicsComponent = store.getComponent(sectionRef, BlockPhysics.getComponentType()); + + assert blockPhysicsComponent != null; + + FluidSection fluidSectionComponent = store.getComponent(sectionRef, FluidSection.getComponentType()); + + assert fluidSectionComponent != null; + + BlockSection blockSectionComponent = store.getComponent(sectionRef, BlockSection.getComponentType()); + + assert blockSectionComponent != null; + + int filler = blockSectionComponent.getFiller(worldX, worldY, worldZ); BlockPhysicsSystems.CachedAccessor cachedAccessor = BlockPhysicsSystems.CachedAccessor.of( - store, blockSection, blockPhysics, fluidSection, cx, cy, cz, 14 + store, blockSectionComponent, blockPhysicsComponent, fluidSectionComponent, chunkX, chunkY, chunkZ, 14 ); return BlockPhysicsUtil.testBlockPhysics( - cachedAccessor, blockSection, blockPhysics, fluidSection, worldX, worldY, worldZ, blockType, rotation, filler + cachedAccessor, + blockSectionComponent, + blockPhysicsComponent, + fluidSectionComponent, + worldX, + worldY, + worldZ, + blockTypeAsset, + rotation, + filler ) != 0; + } else { + return false; } } } @@ -212,7 +248,7 @@ public class DirectionalGrowthBehaviour extends SpreadGrowthBehaviour { public static class BlockTypeWeight implements IWeightedElement { @Nonnull - public static BuilderCodec CODEC = BuilderCodec.builder( + public static final BuilderCodec CODEC = BuilderCodec.builder( DirectionalGrowthBehaviour.BlockTypeWeight.class, DirectionalGrowthBehaviour.BlockTypeWeight::new ) .append( diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/SpreadFarmingStageData.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/SpreadFarmingStageData.java index b1cf33ea..11a5343e 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/SpreadFarmingStageData.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/SpreadFarmingStageData.java @@ -19,7 +19,7 @@ import javax.annotation.Nullable; public class SpreadFarmingStageData extends FarmingStageData { @Nonnull - public static BuilderCodec CODEC = BuilderCodec.builder( + public static final BuilderCodec CODEC = BuilderCodec.builder( SpreadFarmingStageData.class, SpreadFarmingStageData::new, FarmingStageData.BASE_CODEC ) .append( @@ -84,50 +84,67 @@ public class SpreadFarmingStageData extends FarmingStageData { } @Override - public boolean shouldStop(ComponentAccessor commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z) { - FarmingBlock farming = commandBuffer.getComponent(blockRef, FarmingBlock.getComponentType()); - float spreadRate = farming.getSpreadRate(); - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - int worldX = ChunkUtil.worldCoordFromLocalCoord(section.getX(), x); - int worldY = ChunkUtil.worldCoordFromLocalCoord(section.getY(), y); - int worldZ = ChunkUtil.worldCoordFromLocalCoord(section.getZ(), z); - float executions = this.executions.getInt(HashUtil.random(worldX, worldY, worldZ, farming.getGeneration())) * spreadRate; - int executed = farming.getExecutions(); - return spreadRate <= 0.0F || executed >= executions; + public boolean shouldStop( + @Nonnull ComponentAccessor commandBuffer, @Nonnull Ref sectionRef, @Nonnull Ref blockRef, int x, int y, int z + ) { + FarmingBlock farmingBlockComponent = commandBuffer.getComponent(blockRef, FarmingBlock.getComponentType()); + if (farmingBlockComponent == null) { + return true; + } else { + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent == null) { + return true; + } else { + int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getX(), x); + int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getY(), y); + int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getZ(), z); + float spreadRate = farmingBlockComponent.getSpreadRate(); + float executions = this.executions.getInt(HashUtil.random(worldX, worldY, worldZ, farmingBlockComponent.getGeneration())) * spreadRate; + int executed = farmingBlockComponent.getExecutions(); + return spreadRate <= 0.0F || executed >= executions; + } + } } @Override public void apply( - ComponentAccessor commandBuffer, - Ref sectionRef, - Ref blockRef, + @Nonnull ComponentAccessor commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, int x, int y, int z, @Nullable FarmingStageData previousStage ) { super.apply(commandBuffer, sectionRef, blockRef, x, y, z, previousStage); - FarmingBlock farming = commandBuffer.getComponent(blockRef, FarmingBlock.getComponentType()); - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - int worldX = ChunkUtil.worldCoordFromLocalCoord(section.getX(), x); - int worldY = ChunkUtil.worldCoordFromLocalCoord(section.getY(), y); - int worldZ = ChunkUtil.worldCoordFromLocalCoord(section.getZ(), z); - float spreadRate = farming.getSpreadRate(); - double executions = Math.floor(this.executions.getInt(HashUtil.random(worldX, worldY, worldZ, farming.getGeneration())) * spreadRate); - int executed = farming.getExecutions(); - if (!(spreadRate <= 0.0F) && !(executed >= executions)) { - for (int i = 0; i < this.spreadGrowthBehaviours.length; i++) { - SpreadGrowthBehaviour spreadGrowthBehaviour = this.spreadGrowthBehaviours[i]; - float decayRate = this.spreadDecayPercent.getInt(HashUtil.random(i | (long)farming.getGeneration() << 32, worldX, worldY, worldZ)) / 100.0F; - spreadGrowthBehaviour.execute(commandBuffer, sectionRef, blockRef, worldX, worldY, worldZ, spreadRate - decayRate); - } + FarmingBlock farmingBlockComponent = commandBuffer.getComponent(blockRef, FarmingBlock.getComponentType()); + if (farmingBlockComponent != null) { + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent != null) { + int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getX(), x); + int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getY(), y); + int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getZ(), z); + float spreadRate = farmingBlockComponent.getSpreadRate(); + int generation = farmingBlockComponent.getGeneration(); + double executions = Math.floor(this.executions.getInt(HashUtil.random(worldX, worldY, worldZ, generation)) * spreadRate); + int executed = farmingBlockComponent.getExecutions(); + if (!(spreadRate <= 0.0F) && !(executed >= executions)) { + for (int i = 0; i < this.spreadGrowthBehaviours.length; i++) { + SpreadGrowthBehaviour spreadGrowthBehaviour = this.spreadGrowthBehaviours[i]; + float decayRate = this.spreadDecayPercent.getInt(HashUtil.random(i | (long)generation << 32, worldX, worldY, worldZ)) / 100.0F; + spreadGrowthBehaviour.execute(commandBuffer, sectionRef, blockRef, worldX, worldY, worldZ, spreadRate - decayRate); + } - farming.setExecutions(++executed); + farmingBlockComponent.setExecutions(++executed); + } + } } } @Override - public void remove(ComponentAccessor commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z) { + public void remove( + @Nonnull ComponentAccessor commandBuffer, @Nonnull Ref sectionRef, @Nonnull Ref blockRef, int x, int y, int z + ) { super.remove(commandBuffer, sectionRef, blockRef, x, y, z); } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/SpreadGrowthBehaviour.java b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/SpreadGrowthBehaviour.java index 60d81e8e..3ab24058 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/SpreadGrowthBehaviour.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/config/stages/spread/SpreadGrowthBehaviour.java @@ -9,9 +9,12 @@ import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.worldlocationcondition.WorldLocationCondition; +import javax.annotation.Nonnull; public abstract class SpreadGrowthBehaviour { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(SpreadGrowthBehaviour.class) .append( new KeyedCodec<>("LocationConditions", new ArrayCodec<>(WorldLocationCondition.CODEC, WorldLocationCondition[]::new)), @@ -23,9 +26,11 @@ public abstract class SpreadGrowthBehaviour { .build(); protected WorldLocationCondition[] worldLocationConditions; - public abstract void execute(ComponentAccessor var1, Ref var2, Ref var3, int var4, int var5, int var6, float var7); + public abstract void execute( + @Nonnull ComponentAccessor var1, @Nonnull Ref var2, @Nonnull Ref var3, int var4, int var5, int var6, float var7 + ); - protected boolean validatePosition(World world, int worldX, int worldY, int worldZ) { + protected boolean validatePosition(@Nonnull World world, int worldX, int worldY, int worldZ) { if (this.worldLocationConditions == null) { return true; } else { diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/ChangeFarmingStageInteraction.java b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/ChangeFarmingStageInteraction.java index 2f8c5cac..145daccf 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/ChangeFarmingStageInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/ChangeFarmingStageInteraction.java @@ -35,7 +35,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ChangeFarmingStageInteraction extends SimpleBlockInteraction { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ChangeFarmingStageInteraction.class, ChangeFarmingStageInteraction::new, SimpleBlockInteraction.CODEC ) @@ -75,11 +77,11 @@ public class ChangeFarmingStageInteraction extends SimpleBlockInteraction { .build(); protected int targetStage = -1; @Nullable - protected Integer increaseBy = null; + protected Integer increaseBy; @Nullable - protected Integer decreaseBy = null; + protected Integer decreaseBy; @Nullable - protected String targetStageSet = null; + protected String targetStageSet; @Nonnull @Override @@ -270,16 +272,16 @@ public class ChangeFarmingStageInteraction extends SimpleBlockInteraction { ); Ref sectionRef = world.getChunkStore() .getChunkSectionReference(ChunkUtil.chunkCoordinate(x), ChunkUtil.chunkCoordinate(y), ChunkUtil.chunkCoordinate(z)); - if (sectionRef != null) { - BlockSection section = chunkStore.getComponent(sectionRef, BlockSection.getComponentType()); - if (section != null) { - section.scheduleTick(ChunkUtil.indexBlock(x, y, z), now); + if (sectionRef != null && sectionRef.isValid()) { + BlockSection blockSectionComponent = chunkStore.getComponent(sectionRef, BlockSection.getComponentType()); + if (blockSectionComponent != null) { + blockSectionComponent.scheduleTick(ChunkUtil.indexBlock(x, y, z), now); } stages[stageIndex].apply(chunkStore, sectionRef, blockRef, x, y, z, previousStage); LOGGER.atInfo().log("[ChangeFarmingStage] Applied stage %d via stages[%d].apply()", stageIndex, stageIndex); } else { - LOGGER.atWarning().log("[ChangeFarmingStage] sectionRef was null - could not apply stage!"); + LOGGER.atWarning().log("[ChangeFarmingStage] sectionRef was null or invalid - could not apply stage!"); } worldChunk.setTicking(x, y, z, true); diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/FertilizeSoilInteraction.java b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/FertilizeSoilInteraction.java index 7774f93a..983a5046 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/FertilizeSoilInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/FertilizeSoilInteraction.java @@ -26,6 +26,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class FertilizeSoilInteraction extends SimpleBlockInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( FertilizeSoilInteraction.class, FertilizeSoilInteraction::new, SimpleBlockInteraction.CODEC ) @@ -56,40 +57,45 @@ public class FertilizeSoilInteraction extends SimpleBlockInteraction { ) { int x = targetBlock.getX(); int z = targetBlock.getZ(); - WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(x, z)); - Ref blockRef = worldChunk.getBlockComponentEntity(x, targetBlock.getY(), z); - if (blockRef == null) { - blockRef = BlockModule.ensureBlockEntity(worldChunk, targetBlock.x, targetBlock.y, targetBlock.z); - } - - if (blockRef == null) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(x, z); + WorldChunk worldChunkComponent = world.getChunk(chunkIndex); + if (worldChunkComponent == null) { context.getState().state = InteractionState.Failed; } else { - Store chunkStore = world.getChunkStore().getStore(); - TilledSoilBlock soil = chunkStore.getComponent(blockRef, TilledSoilBlock.getComponentType()); - if (soil != null && !soil.isFertilized()) { - soil.setFertilized(true); - worldChunk.setTicking(x, targetBlock.getY(), z, true); - worldChunk.setTicking(x, targetBlock.getY() + 1, z, true); - } else { - FarmingBlock farmingState = chunkStore.getComponent(blockRef, FarmingBlock.getComponentType()); - if (farmingState == null) { - context.getState().state = InteractionState.Failed; + Ref blockRef = worldChunkComponent.getBlockComponentEntity(x, targetBlock.getY(), z); + if (blockRef == null || !blockRef.isValid()) { + blockRef = BlockModule.ensureBlockEntity(worldChunkComponent, targetBlock.x, targetBlock.y, targetBlock.z); + } + + if (blockRef != null && blockRef.isValid()) { + Store chunkStore = world.getChunkStore().getStore(); + TilledSoilBlock tilledSoilComponent = chunkStore.getComponent(blockRef, TilledSoilBlock.getComponentType()); + if (tilledSoilComponent != null && !tilledSoilComponent.isFertilized()) { + tilledSoilComponent.setFertilized(true); + worldChunkComponent.setTicking(x, targetBlock.getY(), z, true); + worldChunkComponent.setTicking(x, targetBlock.getY() + 1, z, true); } else { - Ref soilRef = worldChunk.getBlockComponentEntity(x, targetBlock.getY() - 1, z); - if (soilRef == null) { + FarmingBlock farmingBlockComponent = chunkStore.getComponent(blockRef, FarmingBlock.getComponentType()); + if (farmingBlockComponent == null) { context.getState().state = InteractionState.Failed; } else { - soil = chunkStore.getComponent(soilRef, TilledSoilBlock.getComponentType()); - if (soil != null && !soil.isFertilized()) { - soil.setFertilized(true); - worldChunk.setTicking(x, targetBlock.getY() - 1, z, true); - worldChunk.setTicking(x, targetBlock.getY(), z, true); + Ref soilBlockRef = worldChunkComponent.getBlockComponentEntity(x, targetBlock.getY() - 1, z); + if (soilBlockRef != null && soilBlockRef.isValid()) { + tilledSoilComponent = chunkStore.getComponent(soilBlockRef, TilledSoilBlock.getComponentType()); + if (tilledSoilComponent != null && !tilledSoilComponent.isFertilized()) { + tilledSoilComponent.setFertilized(true); + worldChunkComponent.setTicking(x, targetBlock.getY() - 1, z, true); + worldChunkComponent.setTicking(x, targetBlock.getY(), z, true); + } else { + context.getState().state = InteractionState.Failed; + } } else { context.getState().state = InteractionState.Failed; } } } + } else { + context.getState().state = InteractionState.Failed; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/HarvestCropInteraction.java b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/HarvestCropInteraction.java index ece66585..28c5a8a1 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/HarvestCropInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/HarvestCropInteraction.java @@ -22,6 +22,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class HarvestCropInteraction extends SimpleBlockInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( HarvestCropInteraction.class, HarvestCropInteraction::new, SimpleBlockInteraction.CODEC ) @@ -47,15 +48,15 @@ public class HarvestCropInteraction extends SimpleBlockInteraction { assert blockChunkComponent != null; - BlockSection section = blockChunkComponent.getSectionAtBlockY(targetBlock.y); - if (section != null) { + BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(targetBlock.y); + if (blockSection != null) { WorldChunk worldChunkComponent = chunkStore.getStore().getComponent(chunkRef, WorldChunk.getComponentType()); assert worldChunkComponent != null; BlockType blockType = worldChunkComponent.getBlockType(targetBlock); if (blockType != null) { - int rotationIndex = section.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z); + int rotationIndex = blockSection.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z); FarmingUtil.harvest(world, commandBuffer, ref, blockType, rotationIndex, targetBlock); } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseCaptureCrateInteraction.java b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseCaptureCrateInteraction.java index 8c11f3cf..9bff1703 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseCaptureCrateInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseCaptureCrateInteraction.java @@ -26,6 +26,7 @@ import com.hypixel.hytale.server.core.inventory.Inventory; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.modules.block.BlockModule; import com.hypixel.hytale.server.core.modules.entity.component.PersistentModel; +import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent; import com.hypixel.hytale.server.core.modules.interaction.interaction.CooldownHandler; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.SimpleInteraction; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.client.SimpleBlockInteraction; @@ -41,6 +42,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class UseCaptureCrateInteraction extends SimpleBlockInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UseCaptureCrateInteraction.class, UseCaptureCrateInteraction::new, SimpleInteraction.CODEC ) @@ -74,20 +76,26 @@ public class UseCaptureCrateInteraction extends SimpleBlockInteraction { boolean firstRun, float time, @Nonnull InteractionType type, @Nonnull InteractionContext context, @Nonnull CooldownHandler cooldownHandler ) { CommandBuffer commandBuffer = context.getCommandBuffer(); - if (commandBuffer == null) { + + assert commandBuffer != null; + + ItemStack item = context.getHeldItem(); + if (item == null) { context.getState().state = InteractionState.Failed; + super.tick0(firstRun, time, type, context, cooldownHandler); } else { - ItemStack item = context.getHeldItem(); - if (item == null) { + Ref ref = context.getEntity(); + if (!(EntityUtils.getEntity(ref, commandBuffer) instanceof LivingEntity livingEntity)) { context.getState().state = InteractionState.Failed; + super.tick0(firstRun, time, type, context, cooldownHandler); } else { - Ref ref = context.getEntity(); - if (!(EntityUtils.getEntity(ref, commandBuffer) instanceof LivingEntity livingEntity)) { + Inventory inventory = livingEntity.getInventory(); + byte activeHotbarSlot = inventory.getActiveHotbarSlot(); + ItemStack inHandItemStack = inventory.getActiveHotbarItem(); + if (inHandItemStack == null) { context.getState().state = InteractionState.Failed; + super.tick0(firstRun, time, type, context, cooldownHandler); } else { - Inventory inventory = livingEntity.getInventory(); - byte activeHotbarSlot = inventory.getActiveHotbarSlot(); - ItemStack inHandItemStack = inventory.getActiveHotbarItem(); CapturedNPCMetadata existingMeta = item.getFromMetadataOrNull("CapturedEntity", CapturedNPCMetadata.CODEC); if (existingMeta != null) { super.tick0(firstRun, time, type, context, cooldownHandler); @@ -95,47 +103,56 @@ public class UseCaptureCrateInteraction extends SimpleBlockInteraction { Ref targetEntity = context.getTargetEntity(); if (targetEntity == null) { context.getState().state = InteractionState.Failed; + super.tick0(firstRun, time, type, context, cooldownHandler); } else { NPCEntity npcComponent = commandBuffer.getComponent(targetEntity, NPCEntity.getComponentType()); if (npcComponent == null) { context.getState().state = InteractionState.Failed; + super.tick0(firstRun, time, type, context, cooldownHandler); } else { - TagSetPlugin.TagSetLookup tagSetPlugin = TagSetPlugin.get(NPCGroup.class); - boolean tagFound = false; - - for (int group : this.acceptedNpcGroupIndexes) { - if (tagSetPlugin.tagInSet(group, npcComponent.getRoleIndex())) { - tagFound = true; - break; - } - } - - if (!tagFound) { + DeathComponent deathComponent = commandBuffer.getComponent(targetEntity, DeathComponent.getComponentType()); + if (deathComponent != null) { context.getState().state = InteractionState.Failed; + super.tick0(firstRun, time, type, context, cooldownHandler); } else { - PersistentModel persistentModel = commandBuffer.getComponent(targetEntity, PersistentModel.getComponentType()); - if (persistentModel == null) { + TagSetPlugin.TagSetLookup tagSetPlugin = TagSetPlugin.get(NPCGroup.class); + boolean tagFound = false; + + for (int group : this.acceptedNpcGroupIndexes) { + if (tagSetPlugin.tagInSet(group, npcComponent.getRoleIndex())) { + tagFound = true; + break; + } + } + + if (!tagFound) { context.getState().state = InteractionState.Failed; + super.tick0(firstRun, time, type, context, cooldownHandler); } else { - ModelAsset modelAsset = ModelAsset.getAssetMap().getAsset(persistentModel.getModelReference().getModelAssetId()); - CapturedNPCMetadata meta = inHandItemStack.getFromMetadataOrDefault("CapturedEntity", CapturedNPCMetadata.CODEC); - if (modelAsset != null) { - meta.setIconPath(modelAsset.getIcon()); - } + PersistentModel persistentModelComponent = commandBuffer.getComponent(targetEntity, PersistentModel.getComponentType()); + if (persistentModelComponent == null) { + context.getState().state = InteractionState.Failed; + super.tick0(firstRun, time, type, context, cooldownHandler); + } else { + ModelAsset modelAsset = ModelAsset.getAssetMap().getAsset(persistentModelComponent.getModelReference().getModelAssetId()); + CapturedNPCMetadata itemMetaData = inHandItemStack.getFromMetadataOrDefault("CapturedEntity", CapturedNPCMetadata.CODEC); + if (modelAsset != null) { + itemMetaData.setIconPath(modelAsset.getIcon()); + } - meta.setRoleIndex(npcComponent.getRoleIndex()); - String npcName = NPCPlugin.get().getName(npcComponent.getRoleIndex()); - if (npcName != null) { - meta.setNpcNameKey(npcName); - } + String npcName = NPCPlugin.get().getName(npcComponent.getRoleIndex()); + if (npcName != null) { + itemMetaData.setNpcNameKey(npcName); + } - if (this.fullIcon != null) { - meta.setFullItemIcon(this.fullIcon); - } + if (this.fullIcon != null) { + itemMetaData.setFullItemIcon(this.fullIcon); + } - ItemStack itemWithNPC = inHandItemStack.withMetadata(CapturedNPCMetadata.KEYED_CODEC, meta); - inventory.getHotbar().replaceItemStackInSlot(activeHotbarSlot, item, itemWithNPC); - commandBuffer.removeEntity(targetEntity, RemoveReason.REMOVE); + ItemStack itemWithNPC = inHandItemStack.withMetadata(CapturedNPCMetadata.KEYED_CODEC, itemMetaData); + inventory.getHotbar().replaceItemStackInSlot(activeHotbarSlot, item, itemWithNPC); + commandBuffer.removeEntity(targetEntity, RemoveReason.REMOVE); + } } } } @@ -172,46 +189,51 @@ public class UseCaptureCrateInteraction extends SimpleBlockInteraction { if (pos == null) { context.getState().state = InteractionState.Failed; } else { - WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(pos.x, pos.z)); - Ref blockRef = worldChunk.getBlockComponentEntity(pos.x, pos.y, pos.z); - if (blockRef == null) { - blockRef = BlockModule.ensureBlockEntity(worldChunk, pos.x, pos.y, pos.z); - } + long chunkIndex = ChunkUtil.indexChunkFromBlock(pos.x, pos.z); + WorldChunk worldChunk = world.getChunk(chunkIndex); + if (worldChunk == null) { + context.getState().state = InteractionState.Failed; + } else { + Ref blockRef = worldChunk.getBlockComponentEntity(pos.x, pos.y, pos.z); + if (blockRef == null || !blockRef.isValid()) { + blockRef = BlockModule.ensureBlockEntity(worldChunk, pos.x, pos.y, pos.z); + } - ItemStack noMetaItemStack = item.withMetadata(null); - if (blockRef != null) { - Store chunkStore = world.getChunkStore().getStore(); - CoopBlock coopBlockState = chunkStore.getComponent(blockRef, CoopBlock.getComponentType()); - if (coopBlockState != null) { - WorldTimeResource worldTimeResource = commandBuffer.getResource(WorldTimeResource.getResourceType()); - if (coopBlockState.tryPutResident(existingMeta, worldTimeResource)) { - world.execute( - () -> coopBlockState.ensureSpawnResidentsInWorld( - world, world.getEntityStore().getStore(), new Vector3d(pos.x, pos.y, pos.z), new Vector3d().assign(Vector3d.FORWARD) - ) - ); - inventory.getHotbar().replaceItemStackInSlot(activeHotbarSlot, item, noMetaItemStack); - } else { - context.getState().state = InteractionState.Failed; + ItemStack noMetaItemStack = item.withMetadata(null); + if (blockRef != null && blockRef.isValid()) { + Store chunkStore = world.getChunkStore().getStore(); + CoopBlock coopBlockComponent = chunkStore.getComponent(blockRef, CoopBlock.getComponentType()); + if (coopBlockComponent != null) { + WorldTimeResource worldTimeResource = commandBuffer.getResource(WorldTimeResource.getResourceType()); + if (coopBlockComponent.tryPutResident(existingMeta, worldTimeResource)) { + world.execute( + () -> coopBlockComponent.ensureSpawnResidentsInWorld( + world, world.getEntityStore().getStore(), new Vector3d(pos.x, pos.y, pos.z), new Vector3d().assign(Vector3d.FORWARD) + ) + ); + inventory.getHotbar().replaceItemStackInSlot(activeHotbarSlot, item, noMetaItemStack); + context.getState().state = InteractionState.Finished; + } else { + context.getState().state = InteractionState.Failed; + } + + return; } - - return; } - } - Vector3d spawnPos = new Vector3d(pos.x + 0.5F, pos.y, pos.z + 0.5F); - if (context.getClientState() != null) { - BlockFace blockFace = BlockFace.fromProtocolFace(context.getClientState().blockFace); - if (blockFace != null) { - spawnPos.add(blockFace.getDirection()); + Vector3d spawnPos = new Vector3d(pos.x + 0.5F, pos.y, pos.z + 0.5F); + if (context.getClientState() != null) { + BlockFace blockFace = BlockFace.fromProtocolFace(context.getClientState().blockFace); + if (blockFace != null) { + spawnPos.add(blockFace.getDirection()); + } } - } - NPCPlugin npcModule = NPCPlugin.get(); - Store store = context.getCommandBuffer().getStore(); - int roleIndex = existingMeta.getRoleIndex(); - commandBuffer.run(_store -> npcModule.spawnEntity(store, roleIndex, spawnPos, Vector3f.ZERO, null, null)); - inventory.getHotbar().replaceItemStackInSlot(activeHotbarSlot, item, noMetaItemStack); + String roleId = existingMeta.getNpcNameKey(); + int roleIndex = NPCPlugin.get().getIndex(roleId); + commandBuffer.run(_store -> NPCPlugin.get().spawnEntity(_store, roleIndex, spawnPos, Vector3f.ZERO, null, null)); + inventory.getHotbar().replaceItemStackInSlot(activeHotbarSlot, item, noMetaItemStack); + } } } } else { diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseCoopInteraction.java b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseCoopInteraction.java index 532287fc..5b9e0b2d 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseCoopInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseCoopInteraction.java @@ -26,6 +26,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class UseCoopInteraction extends SimpleBlockInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UseCoopInteraction.class, UseCoopInteraction::new, SimpleBlockInteraction.CODEC ) @@ -43,39 +44,39 @@ public class UseCoopInteraction extends SimpleBlockInteraction { ) { int x = targetBlock.getX(); int z = targetBlock.getZ(); - WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(x, z)); + long chunkIndex = ChunkUtil.indexChunkFromBlock(x, z); + WorldChunk worldChunk = world.getChunk(chunkIndex); if (worldChunk == null) { context.getState().state = InteractionState.Failed; } else { Ref blockRef = worldChunk.getBlockComponentEntity(x, targetBlock.getY(), z); - if (blockRef == null) { + if (blockRef == null || !blockRef.isValid()) { blockRef = BlockModule.ensureBlockEntity(worldChunk, targetBlock.x, targetBlock.y, targetBlock.z); } - if (blockRef == null) { - context.getState().state = InteractionState.Failed; - } else { + if (blockRef != null && blockRef.isValid()) { Store chunkStore = world.getChunkStore().getStore(); - CoopBlock coopBlockState = chunkStore.getComponent(blockRef, CoopBlock.getComponentType()); - if (coopBlockState == null) { + CoopBlock coopBlockComponent = chunkStore.getComponent(blockRef, CoopBlock.getComponentType()); + if (coopBlockComponent == null) { context.getState().state = InteractionState.Failed; } else { - Ref playerRef = context.getEntity(); - LivingEntity playerEntity = (LivingEntity)EntityUtils.getEntity(playerRef, commandBuffer); - if (playerEntity == null) { - context.getState().state = InteractionState.Failed; - } else { - CombinedItemContainer playerInventoryContainer = playerEntity.getInventory().getCombinedHotbarFirst(); - if (playerInventoryContainer != null) { - coopBlockState.gatherProduceFromInventory(playerInventoryContainer); + Ref ref = context.getEntity(); + if (EntityUtils.getEntity(ref, commandBuffer) instanceof LivingEntity livingEntity) { + CombinedItemContainer inventoryContainer = livingEntity.getInventory().getCombinedHotbarFirst(); + if (inventoryContainer != null) { + coopBlockComponent.gatherProduceFromContainer(inventoryContainer); BlockType currentBlockType = worldChunk.getBlockType(targetBlock); assert currentBlockType != null; - worldChunk.setBlockInteractionState(targetBlock, currentBlockType, coopBlockState.hasProduce() ? "Produce_Ready" : "default"); + worldChunk.setBlockInteractionState(targetBlock, currentBlockType, coopBlockComponent.hasProduce() ? "Produce_Ready" : "default"); } + } else { + context.getState().state = InteractionState.Failed; } } + } else { + context.getState().state = InteractionState.Failed; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseWateringCanInteraction.java b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseWateringCanInteraction.java index 1d339cba..327c1b26 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseWateringCanInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/UseWateringCanInteraction.java @@ -29,6 +29,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class UseWateringCanInteraction extends SimpleBlockInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UseWateringCanInteraction.class, UseWateringCanInteraction::new, SimpleBlockInteraction.CODEC ) @@ -61,45 +62,52 @@ public class UseWateringCanInteraction extends SimpleBlockInteraction { ) { int x = targetBlock.getX(); int z = targetBlock.getZ(); - WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(x, z)); - Ref blockRef = worldChunk.getBlockComponentEntity(x, targetBlock.getY(), z); - if (blockRef == null) { - blockRef = BlockModule.ensureBlockEntity(worldChunk, targetBlock.x, targetBlock.y, targetBlock.z); - } - - if (blockRef == null) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(x, z); + WorldChunk worldChunk = world.getChunk(chunkIndex); + if (worldChunk == null) { context.getState().state = InteractionState.Failed; } else { - Store chunkStore = world.getChunkStore().getStore(); - WorldTimeResource worldTimeResource = commandBuffer.getResource(WorldTimeResource.getResourceType()); - TilledSoilBlock soil = chunkStore.getComponent(blockRef, TilledSoilBlock.getComponentType()); - if (soil != null) { - Instant wateredUntil = worldTimeResource.getGameTime().plus(this.duration, ChronoUnit.SECONDS); - soil.setWateredUntil(wateredUntil); - worldChunk.setTicking(x, targetBlock.getY(), z, true); - worldChunk.getBlockChunk().getSectionAtBlockY(targetBlock.y).scheduleTick(ChunkUtil.indexBlock(x, targetBlock.y, z), wateredUntil); - worldChunk.setTicking(x, targetBlock.getY() + 1, z, true); - } else { - FarmingBlock farmingState = chunkStore.getComponent(blockRef, FarmingBlock.getComponentType()); - if (farmingState == null) { - context.getState().state = InteractionState.Failed; + Ref blockRef = worldChunk.getBlockComponentEntity(x, targetBlock.getY(), z); + if (blockRef == null) { + blockRef = BlockModule.ensureBlockEntity(worldChunk, targetBlock.x, targetBlock.y, targetBlock.z); + } + + if (blockRef != null && blockRef.isValid()) { + Store chunkStore = world.getChunkStore().getStore(); + WorldTimeResource worldTimeResource = commandBuffer.getResource(WorldTimeResource.getResourceType()); + TilledSoilBlock tilledSoilBlockComponent = chunkStore.getComponent(blockRef, TilledSoilBlock.getComponentType()); + if (tilledSoilBlockComponent != null) { + Instant wateredUntil = worldTimeResource.getGameTime().plus(this.duration, ChronoUnit.SECONDS); + tilledSoilBlockComponent.setWateredUntil(wateredUntil); + worldChunk.setTicking(x, targetBlock.getY(), z, true); + worldChunk.getBlockChunk().getSectionAtBlockY(targetBlock.y).scheduleTick(ChunkUtil.indexBlock(x, targetBlock.y, z), wateredUntil); + worldChunk.setTicking(x, targetBlock.getY() + 1, z, true); } else { - Ref soilRef = worldChunk.getBlockComponentEntity(x, targetBlock.getY() - 1, z); - if (soilRef == null) { + FarmingBlock farmingBlockComponent = chunkStore.getComponent(blockRef, FarmingBlock.getComponentType()); + if (farmingBlockComponent == null) { context.getState().state = InteractionState.Failed; } else { - soil = chunkStore.getComponent(soilRef, TilledSoilBlock.getComponentType()); - if (soil == null) { - context.getState().state = InteractionState.Failed; + Ref soilBlockRef = worldChunk.getBlockComponentEntity(x, targetBlock.getY() - 1, z); + if (soilBlockRef != null && soilBlockRef.isValid()) { + tilledSoilBlockComponent = chunkStore.getComponent(soilBlockRef, TilledSoilBlock.getComponentType()); + if (tilledSoilBlockComponent == null) { + context.getState().state = InteractionState.Failed; + } else { + Instant wateredUntil = worldTimeResource.getGameTime().plus(this.duration, ChronoUnit.SECONDS); + tilledSoilBlockComponent.setWateredUntil(wateredUntil); + worldChunk.getBlockChunk() + .getSectionAtBlockY(targetBlock.y - 1) + .scheduleTick(ChunkUtil.indexBlock(x, targetBlock.y - 1, z), wateredUntil); + worldChunk.setTicking(x, targetBlock.getY() - 1, z, true); + worldChunk.setTicking(x, targetBlock.getY(), z, true); + } } else { - Instant wateredUntil = worldTimeResource.getGameTime().plus(this.duration, ChronoUnit.SECONDS); - soil.setWateredUntil(wateredUntil); - worldChunk.getBlockChunk().getSectionAtBlockY(targetBlock.y - 1).scheduleTick(ChunkUtil.indexBlock(x, targetBlock.y - 1, z), wateredUntil); - worldChunk.setTicking(x, targetBlock.getY() - 1, z, true); - worldChunk.setTicking(x, targetBlock.getY(), z, true); + context.getState().state = InteractionState.Failed; } } } + } else { + context.getState().state = InteractionState.Failed; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/states/CoopBlock.java b/src/com/hypixel/hytale/builtin/adventure/farming/states/CoopBlock.java index 0cc52097..1697573a 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/states/CoopBlock.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/states/CoopBlock.java @@ -56,10 +56,13 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CoopBlock implements Component { + @Nonnull public static final String STATE_PRODUCE = "Produce_Ready"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CoopBlock.class, CoopBlock::new) .append(new KeyedCodec<>("FarmingCoopId", Codec.STRING, true), (coop, s) -> coop.coopAssetId = s, coop -> coop.coopAssetId) .add() @@ -73,7 +76,9 @@ public class CoopBlock implements Component { .add() .build(); protected String coopAssetId; - protected List residents = new ArrayList<>(); + @Nonnull + protected List residents = new ObjectArrayList<>(); + @Nonnull protected ItemContainer itemContainer = EmptyItemContainer.INSTANCE; public static ComponentType getComponentType() { @@ -81,7 +86,7 @@ public class CoopBlock implements Component { } public CoopBlock() { - ArrayList remainder = new ArrayList<>(); + List remainder = new ObjectArrayList<>(); this.itemContainer = ItemContainer.ensureContainerCapacity(this.itemContainer, (short)5, SimpleItemContainer::new, remainder); } @@ -90,7 +95,7 @@ public class CoopBlock implements Component { return FarmingCoopAsset.getAssetMap().getAsset(this.coopAssetId); } - public CoopBlock(String farmingCoopId, List residents, ItemContainer itemContainer) { + public CoopBlock(@Nonnull String farmingCoopId, @Nonnull List residents, @Nonnull ItemContainer itemContainer) { this.coopAssetId = farmingCoopId; this.residents.addAll(residents); this.itemContainer = itemContainer.clone(); @@ -98,13 +103,13 @@ public class CoopBlock implements Component { this.itemContainer = ItemContainer.ensureContainerCapacity(this.itemContainer, (short)5, SimpleItemContainer::new, remainder); } - public boolean tryPutResident(CapturedNPCMetadata metadata, WorldTimeResource worldTimeResource) { + public boolean tryPutResident(@Nonnull CapturedNPCMetadata metadata, @Nonnull WorldTimeResource worldTimeResource) { FarmingCoopAsset coopAsset = this.getCoopAsset(); if (coopAsset == null) { return false; } else if (this.residents.size() >= coopAsset.getMaxResidents()) { return false; - } else if (!this.getCoopAcceptsNPCGroup(metadata.getRoleIndex())) { + } else if (!this.getCoopAcceptsNPC(metadata.getNpcNameKey())) { return false; } else { this.residents.add(new CoopBlock.CoopResident(metadata, null, worldTimeResource.getGameTime())); @@ -112,7 +117,9 @@ public class CoopBlock implements Component { } } - public boolean tryPutWildResidentFromWild(Store store, Ref entityRef, WorldTimeResource worldTimeResource, Vector3i coopLocation) { + public boolean tryPutWildResidentFromWild( + @Nonnull Store store, @Nonnull Ref entityRef, @Nonnull WorldTimeResource worldTimeResource, @Nonnull Vector3i coopLocation + ) { FarmingCoopAsset coopAsset = this.getCoopAsset(); if (coopAsset == null) { return false; @@ -124,7 +131,7 @@ public class CoopBlock implements Component { CoopResidentComponent coopResidentComponent = store.getComponent(entityRef, CoopResidentComponent.getComponentType()); if (coopResidentComponent != null) { return false; - } else if (!this.getCoopAcceptsNPCGroup(npcComponent.getRoleIndex())) { + } else if (!this.getCoopAcceptsNPC(npcComponent.getRoleName())) { return false; } else if (this.residents.size() >= coopAsset.getMaxResidents()) { return false; @@ -137,7 +144,7 @@ public class CoopBlock implements Component { } else { PersistentRef persistentRef = new PersistentRef(); persistentRef.setEntity(entityRef, uuidComponent.getUuid()); - CapturedNPCMetadata metadata = FarmingUtil.generateCapturedNPCMetadata(store, entityRef, npcComponent.getRoleIndex()); + CapturedNPCMetadata metadata = FarmingUtil.generateCapturedNPCMetadata(store, entityRef, npcComponent.getRoleName()); CoopBlock.CoopResident residentRecord = new CoopBlock.CoopResident(metadata, persistentRef, worldTimeResource.getGameTime()); residentRecord.deployedToWorld = true; this.residents.add(residentRecord); @@ -148,8 +155,9 @@ public class CoopBlock implements Component { } } - public boolean getCoopAcceptsNPCGroup(int npcRoleIndex) { + public boolean getCoopAcceptsNPC(String npcNameKey) { TagSetPlugin.TagSetLookup tagSetPlugin = TagSetPlugin.get(NPCGroup.class); + int roleIndex = NPCPlugin.get().getIndex(npcNameKey); FarmingCoopAsset coopAsset = this.getCoopAsset(); if (coopAsset == null) { return false; @@ -159,7 +167,7 @@ public class CoopBlock implements Component { return true; } else { for (int group : acceptedNpcGroupIndexes) { - if (tagSetPlugin.tagInSet(group, npcRoleIndex)) { + if (tagSetPlugin.tagInSet(group, roleIndex)) { return true; } } @@ -169,7 +177,7 @@ public class CoopBlock implements Component { } } - public void generateProduceToInventory(WorldTimeResource worldTimeResource) { + public void generateProduceToInventory(@Nonnull WorldTimeResource worldTimeResource) { Instant currentTime = worldTimeResource.getGameTime(); FarmingCoopAsset coopAsset = this.getCoopAsset(); if (coopAsset != null) { @@ -184,8 +192,7 @@ public class CoopBlock implements Component { resident.setLastProduced(currentTime); } else { CapturedNPCMetadata residentMeta = resident.getMetadata(); - int npcRoleIndex = residentMeta.getRoleIndex(); - String npcName = NPCPlugin.get().getName(npcRoleIndex); + String npcName = residentMeta.getNpcNameKey(); String npcDropListName = produceDropsMap.get(npcName); if (npcDropListName != null) { ItemDropList dropListAsset = ItemDropList.getAssetMap().getAsset(npcDropListName); @@ -225,14 +232,15 @@ public class CoopBlock implements Component { } } - public void gatherProduceFromInventory(ItemContainer playerInventory) { + public void gatherProduceFromContainer(@Nonnull ItemContainer playerInventory) { for (ItemStack item : this.itemContainer.removeAllItemStacks()) { playerInventory.addItemStack(item); } } - public void ensureSpawnResidentsInWorld(World world, Store store, Vector3d coopLocation, Vector3d spawnOffset) { - NPCPlugin npcModule = NPCPlugin.get(); + public void ensureSpawnResidentsInWorld( + @Nonnull World world, @Nonnull Store store, @Nonnull Vector3d coopLocation, @Nonnull Vector3d spawnOffset + ) { FarmingCoopAsset coopAsset = this.getCoopAsset(); if (coopAsset != null) { float radiansPerSpawn = (float) (Math.PI * 2) / coopAsset.getMaxResidents(); @@ -241,7 +249,8 @@ public class CoopBlock implements Component { for (CoopBlock.CoopResident resident : this.residents) { CapturedNPCMetadata residentMeta = resident.getMetadata(); - int npcRoleIndex = residentMeta.getRoleIndex(); + String npcNameKey = residentMeta.getNpcNameKey(); + int npcRoleIndex = NPCPlugin.get().getIndex(npcNameKey); boolean residentDeployed = resident.getDeployedToWorld(); PersistentRef residentEntityId = resident.getPersistentRef(); if (!residentDeployed && residentEntityId == null) { @@ -251,9 +260,8 @@ public class CoopBlock implements Component { spawningContext.setSpawnable((ISpawnableWithModel)roleBuilder); if (spawningContext.set(world, residentSpawnLocation.x, residentSpawnLocation.y, residentSpawnLocation.z) && spawningContext.canSpawn() == SpawnTestResult.TEST_OK) { - Pair, NPCEntity> npcPair = npcModule.spawnEntity( - store, npcRoleIndex, spawningContext.newPosition(), Vector3f.ZERO, null, null - ); + Pair, NPCEntity> npcPair = NPCPlugin.get() + .spawnEntity(store, npcRoleIndex, spawningContext.newPosition(), Vector3f.ZERO, null, null); if (npcPair == null) { resident.setPersistentRef(null); resident.setDeployedToWorld(false); @@ -288,40 +296,45 @@ public class CoopBlock implements Component { } } - public void ensureNoResidentsInWorld(Store store) { - ArrayList residentsToRemove = new ArrayList<>(); + public void ensureNoResidentsInWorld(@Nonnull Store store) { + FarmingCoopAsset coopAsset = this.getCoopAsset(); + if (coopAsset != null) { + ObjectArrayList residentsToRemove = new ObjectArrayList<>(); - for (CoopBlock.CoopResident resident : this.residents) { - boolean deployed = resident.getDeployedToWorld(); - PersistentRef entityUuid = resident.getPersistentRef(); - if (deployed || entityUuid != null) { - Ref entityRef = entityUuid.getEntity(store); - if (entityRef == null) { - residentsToRemove.add(resident); - } else { - CoopResidentComponent coopResidentComponent = store.getComponent(entityRef, CoopResidentComponent.getComponentType()); - if (coopResidentComponent == null) { + for (CoopBlock.CoopResident resident : this.residents) { + boolean deployed = resident.getDeployedToWorld(); + PersistentRef entityUuid = resident.getPersistentRef(); + if (deployed || entityUuid != null) { + Ref entityRef = entityUuid.getEntity(store); + if (entityRef == null) { residentsToRemove.add(resident); } else { - DeathComponent deathComponent = store.getComponent(entityRef, DeathComponent.getComponentType()); - if (deathComponent != null) { + CoopResidentComponent coopResidentComponent = store.getComponent(entityRef, CoopResidentComponent.getComponentType()); + if (coopResidentComponent == null) { residentsToRemove.add(resident); } else { - coopResidentComponent.setMarkedForDespawn(true); - resident.setPersistentRef(null); - resident.setDeployedToWorld(false); + DeathComponent deathComponent = store.getComponent(entityRef, DeathComponent.getComponentType()); + if (deathComponent != null) { + residentsToRemove.add(resident); + } else if (!this.getCoopAcceptsNPC(resident.metadata.getNpcNameKey())) { + residentsToRemove.add(resident); + } else { + coopResidentComponent.setMarkedForDespawn(true); + resident.setPersistentRef(null); + resident.setDeployedToWorld(false); + } } } } } - } - for (CoopBlock.CoopResident residentx : residentsToRemove) { - this.residents.remove(residentx); + for (CoopBlock.CoopResident residentx : residentsToRemove) { + this.residents.remove(residentx); + } } } - public boolean shouldResidentsBeInCoop(WorldTimeResource worldTimeResource) { + public boolean shouldResidentsBeInCoop(@Nonnull WorldTimeResource worldTimeResource) { FarmingCoopAsset coopAsset = this.getCoopAsset(); if (coopAsset == null) { return true; @@ -337,7 +350,7 @@ public class CoopBlock implements Component { } @Nullable - public Instant getNextScheduledTick(WorldTimeResource worldTimeResource) { + public Instant getNextScheduledTick(@Nonnull WorldTimeResource worldTimeResource) { Instant gameTime = worldTimeResource.getGameTime(); LocalDateTime gameDateTime = worldTimeResource.getGameDateTime(); int gameHour = worldTimeResource.getCurrentHour(); @@ -366,7 +379,7 @@ public class CoopBlock implements Component { } } - public void handleResidentDespawn(UUID entityUuid) { + public void handleResidentDespawn(@Nonnull UUID entityUuid) { CoopBlock.CoopResident removedResident = null; for (CoopBlock.CoopResident resident : this.residents) { @@ -381,7 +394,9 @@ public class CoopBlock implements Component { } } - public void handleBlockBroken(World world, WorldTimeResource worldTimeResource, Store store, int blockX, int blockY, int blockZ) { + public void handleBlockBroken( + @Nonnull World world, @Nonnull WorldTimeResource worldTimeResource, @Nonnull Store store, int blockX, int blockY, int blockZ + ) { Vector3i location = new Vector3i(blockX, blockY, blockZ); world.execute(() -> this.ensureSpawnResidentsInWorld(world, store, location.toVector3d(), new Vector3d().assign(Vector3d.FORWARD))); this.generateProduceToInventory(worldTimeResource); @@ -416,6 +431,7 @@ public class CoopBlock implements Component { } public static class CoopResident { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CoopBlock.CoopResident.class, CoopBlock.CoopResident::new) .append(new KeyedCodec<>("Metadata", CapturedNPCMetadata.CODEC), (coop, meta) -> coop.metadata = meta, coop -> coop.metadata) .add() @@ -439,7 +455,7 @@ public class CoopBlock implements Component { public CoopResident() { } - public CoopResident(CapturedNPCMetadata metadata, PersistentRef persistentRef, Instant lastProduced) { + public CoopResident(CapturedNPCMetadata metadata, @Nullable PersistentRef persistentRef, @Nonnull Instant lastProduced) { this.metadata = metadata; this.persistentRef = persistentRef; this.lastProduced = lastProduced; diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/states/FarmingBlock.java b/src/com/hypixel/hytale/builtin/adventure/farming/states/FarmingBlock.java index dfd96363..30c0677a 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/states/FarmingBlock.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/states/FarmingBlock.java @@ -8,10 +8,13 @@ import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import java.time.Instant; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class FarmingBlock implements Component { + @Nonnull public static final String DEFAULT_STAGE_SET = "Default"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(FarmingBlock.class, FarmingBlock::new) .append( new KeyedCodec<>("CurrentStageSet", Codec.STRING), @@ -56,13 +59,14 @@ public class FarmingBlock implements Component { ) .add() .build(); + @Nonnull private String currentStageSet = "Default"; private float growthProgress; private Instant lastTickGameTime; private int generation; private String previousBlockType; private float spreadRate = 1.0F; - private int executions = 0; + private int executions; public static ComponentType getComponentType() { return FarmingPlugin.get().getFarmingBlockComponentType(); @@ -72,7 +76,13 @@ public class FarmingBlock implements Component { } public FarmingBlock( - String currentStageSet, float growthProgress, Instant lastTickGameTime, int generation, String previousBlockType, float spreadRate, int executions + @Nonnull String currentStageSet, + float growthProgress, + Instant lastTickGameTime, + int generation, + String previousBlockType, + float spreadRate, + int executions ) { this.currentStageSet = currentStageSet; this.growthProgress = growthProgress; @@ -83,11 +93,12 @@ public class FarmingBlock implements Component { this.executions = executions; } + @Nonnull public String getCurrentStageSet() { return this.currentStageSet; } - public void setCurrentStageSet(String currentStageSet) { + public void setCurrentStageSet(@Nullable String currentStageSet) { this.currentStageSet = currentStageSet != null ? currentStageSet : "Default"; } @@ -147,6 +158,7 @@ public class FarmingBlock implements Component { ); } + @Nonnull @Override public String toString() { return "FarmingBlock{currentStageSet='" diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/states/FarmingBlockState.java b/src/com/hypixel/hytale/builtin/adventure/farming/states/FarmingBlockState.java index 967bc3f1..803338b4 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/states/FarmingBlockState.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/states/FarmingBlockState.java @@ -13,7 +13,7 @@ import javax.annotation.Nullable; @Deprecated(forRemoval = true) public class FarmingBlockState implements Component { @Nonnull - public static BuilderCodec CODEC = BuilderCodec.builder(FarmingBlockState.class, FarmingBlockState::new) + public static final BuilderCodec CODEC = BuilderCodec.builder(FarmingBlockState.class, FarmingBlockState::new) .append(new KeyedCodec<>("BaseCrop", Codec.STRING), (state, crop) -> state.baseCrop = crop, state -> state.baseCrop) .add() .append(new KeyedCodec<>("StageStart", Codec.INSTANT), (state, start) -> state.stageStart = start, state -> state.stageStart) diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/states/TilledSoilBlock.java b/src/com/hypixel/hytale/builtin/adventure/farming/states/TilledSoilBlock.java index 1e501be0..cadea2aa 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/states/TilledSoilBlock.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/states/TilledSoilBlock.java @@ -13,10 +13,12 @@ import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.time.Instant; import java.util.Map; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class TilledSoilBlock implements Component { public static int VERSION = 1; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(TilledSoilBlock.class, TilledSoilBlock::new) .versioned() .codecVersion(VERSION) @@ -116,7 +118,8 @@ public class TilledSoilBlock implements Component { this.decayTime = decayTime; } - public String computeBlockType(Instant gameTime, BlockType type) { + @Nullable + public String computeBlockType(@Nonnull Instant gameTime, @Nonnull BlockType type) { boolean watered = this.hasExternalWater() || this.wateredUntil != null && this.wateredUntil.isAfter(gameTime); if (this.fertilized && watered) { return type.getBlockKeyForState("Fertilized_Watered"); @@ -127,6 +130,7 @@ public class TilledSoilBlock implements Component { } } + @Nonnull @Override public String toString() { return "TilledSoilBlock{planted=" diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesGameplayConfig.java b/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesGameplayConfig.java index d435c185..9e3bf1bc 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesGameplayConfig.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesGameplayConfig.java @@ -11,7 +11,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MemoriesGameplayConfig { + @Nonnull public static final String ID = "Memories"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(MemoriesGameplayConfig.class, MemoriesGameplayConfig::new) .appendInherited( new KeyedCodec<>("MemoriesAmountPerLevel", Codec.INT_ARRAY), diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesPlugin.java b/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesPlugin.java index db16993b..03c5f1c0 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesPlugin.java @@ -69,9 +69,14 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MemoriesPlugin extends JavaPlugin { + @Nonnull + public static final String MEMORIES_JSON_PATH = "memories.json"; private static MemoriesPlugin instance; + @Nonnull private final Config config = this.withConfig(MemoriesPlugin.MemoriesPluginConfig.CODEC); + @Nonnull private final List> providers = new ObjectArrayList<>(); + @Nonnull private final Map> allMemories = new Object2ObjectRBTreeMap<>(); private ComponentType playerMemoriesComponentType; @Nullable @@ -169,6 +174,7 @@ public class MemoriesPlugin extends JavaPlugin { this.providers.add(memoryProvider); } + @Nonnull public Map> getAllMemories() { return this.allMemories; } @@ -299,6 +305,7 @@ public class MemoriesPlugin extends JavaPlugin { } public static class MemoriesPluginConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MemoriesPlugin.MemoriesPluginConfig.class, MemoriesPlugin.MemoriesPluginConfig::new ) @@ -361,6 +368,7 @@ public class MemoriesPlugin extends JavaPlugin { } private static class RecordedMemories { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MemoriesPlugin.RecordedMemories.class, MemoriesPlugin.RecordedMemories::new ) @@ -371,7 +379,9 @@ public class MemoriesPlugin extends JavaPlugin { }, recordedMemories -> recordedMemories.memories.toArray(Memory[]::new)) .add() .build(); + @Nonnull private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + @Nonnull private final Set memories = new HashSet<>(); } } diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/component/PlayerMemories.java b/src/com/hypixel/hytale/builtin/adventure/memories/component/PlayerMemories.java index 10580a06..e53ff976 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/component/PlayerMemories.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/component/PlayerMemories.java @@ -15,6 +15,7 @@ import java.util.Set; import javax.annotation.Nonnull; public class PlayerMemories implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PlayerMemories.class, PlayerMemories::new) .append( new KeyedCodec<>("Capacity", Codec.INTEGER), @@ -29,6 +30,7 @@ public class PlayerMemories implements Component { }, playerMemories -> playerMemories.memories.toArray(Memory[]::new)) .add() .build(); + @Nonnull private final Set memories = new LinkedHashSet<>(); private int memoriesCapacity; diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/interactions/MemoriesConditionInteraction.java b/src/com/hypixel/hytale/builtin/adventure/memories/interactions/MemoriesConditionInteraction.java index 3b8f3dec..a71edc0a 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/interactions/MemoriesConditionInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/interactions/MemoriesConditionInteraction.java @@ -142,7 +142,7 @@ public class MemoriesConditionInteraction extends Interaction { } @Override - protected void configurePacket(com.hypixel.hytale.protocol.Interaction packet) { + protected void configurePacket(@Nonnull com.hypixel.hytale.protocol.Interaction packet) { super.configurePacket(packet); com.hypixel.hytale.protocol.MemoriesConditionInteraction p = (com.hypixel.hytale.protocol.MemoriesConditionInteraction)packet; p.memoriesNext = new Int2IntOpenHashMap(this.next.size()); @@ -156,11 +156,9 @@ public class MemoriesConditionInteraction extends Interaction { @Override public boolean walk(@Nonnull Collector collector, @Nonnull InteractionContext context) { - if (this.next != null) { - for (Entry entry : this.next.int2ObjectEntrySet()) { - if (InteractionManager.walkInteraction(collector, context, new MemoriesConditionInteraction.MemoriesTag(entry.getIntKey()), entry.getValue())) { - return true; - } + for (Entry entry : this.next.int2ObjectEntrySet()) { + if (InteractionManager.walkInteraction(collector, context, new MemoriesConditionInteraction.MemoriesTag(entry.getIntKey()), entry.getValue())) { + return true; } } @@ -172,6 +170,7 @@ public class MemoriesConditionInteraction extends Interaction { return false; } + @Nonnull @Override public WaitForDataFrom getWaitForDataFrom() { return WaitForDataFrom.Server; diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/interactions/SetMemoriesCapacityInteraction.java b/src/com/hypixel/hytale/builtin/adventure/memories/interactions/SetMemoriesCapacityInteraction.java index 8692daa3..faf67b8f 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/interactions/SetMemoriesCapacityInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/interactions/SetMemoriesCapacityInteraction.java @@ -21,6 +21,15 @@ import com.hypixel.hytale.server.core.util.NotificationUtil; import javax.annotation.Nonnull; public class SetMemoriesCapacityInteraction extends SimpleInstantInteraction { + @Nonnull + private static final String NOTIFICATION_ICON_MEMORIES = "NotificationIcons/MemoriesIcon.png"; + @Nonnull + private static final Message MESSAGE_SERVER_MEMORIES_GENERAL_FEATURE_UNLOCKED_NOTIFICATION = Message.translation( + "server.memories.general.featureUnlockedNotification" + ); + @Nonnull + private static final Message MESSAGE_SERVER_MEMORIES_GENERAL_FEATURE_UNLOCKED_MESSAGE = Message.translation("server.memories.general.featureUnlockedMessage"); + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SetMemoriesCapacityInteraction.class, SetMemoriesCapacityInteraction::new, SimpleInstantInteraction.CODEC ) @@ -48,15 +57,14 @@ public class SetMemoriesCapacityInteraction extends SimpleInstantInteraction { memoriesComponent.setMemoriesCapacity(this.capacity); if (previousCapacity <= 0) { PlayerRef playerRefComponent = commandBuffer.getComponent(ref, PlayerRef.getComponentType()); - - assert playerRefComponent != null; - - PacketHandler playerConnection = playerRefComponent.getPacketHandler(); - playerConnection.writeNoCache(new UpdateMemoriesFeatureStatus(true)); - NotificationUtil.sendNotification( - playerConnection, Message.translation("server.memories.general.featureUnlockedNotification"), null, "NotificationIcons/MemoriesIcon.png" - ); - playerRefComponent.sendMessage(Message.translation("server.memories.general.featureUnlockedMessage")); + if (playerRefComponent != null) { + PacketHandler playerConnection = playerRefComponent.getPacketHandler(); + playerConnection.writeNoCache(new UpdateMemoriesFeatureStatus(true)); + NotificationUtil.sendNotification( + playerConnection, MESSAGE_SERVER_MEMORIES_GENERAL_FEATURE_UNLOCKED_NOTIFICATION, null, "NotificationIcons/MemoriesIcon.png" + ); + playerRefComponent.sendMessage(MESSAGE_SERVER_MEMORIES_GENERAL_FEATURE_UNLOCKED_MESSAGE); + } } context.getState().state = InteractionState.Finished; diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/memories/Memory.java b/src/com/hypixel/hytale/builtin/adventure/memories/memories/Memory.java index 3710f4d0..8e7b508e 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/memories/Memory.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/memories/Memory.java @@ -6,6 +6,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class Memory { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>(); public abstract String getId(); diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/memories/npc/NPCMemory.java b/src/com/hypixel/hytale/builtin/adventure/memories/memories/npc/NPCMemory.java index 72b97a4f..fa702870 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/memories/npc/NPCMemory.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/memories/npc/NPCMemory.java @@ -53,6 +53,8 @@ public class NPCMemory extends Memory { @Nonnull public static final String ID = "NPC"; @Nonnull + public static final String ZONE_NAME_UNKNOWN = "???"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(NPCMemory.class, NPCMemory::new) .append(new KeyedCodec<>("NPCRole", Codec.STRING), (npcMemory, s) -> npcMemory.npcRole = s, npcMemory -> npcMemory.npcRole) .addValidator(Validators.nonNull()) @@ -119,7 +121,7 @@ public class NPCMemory extends Memory { return Message.translation("server.memories.general.discovered.tooltipText"); } - @Nullable + @Nonnull @Override public String getIconPath() { return "UI/Custom/Pages/Memories/npcs/" + this.npcRole + ".png"; @@ -157,6 +159,7 @@ public class NPCMemory extends Memory { return this.foundLocationZoneNameKey; } + @Nonnull public Message getLocationMessage() { if (this.foundLocationGeneralNameKey != null) { return Message.translation(this.foundLocationGeneralNameKey); @@ -166,7 +169,7 @@ public class NPCMemory extends Memory { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o == null || this.getClass() != o.getClass()) { return false; } else if (!super.equals(o)) { @@ -184,6 +187,7 @@ public class NPCMemory extends Memory { return 31 * result + Boolean.hashCode(this.isMemoriesNameOverridden); } + @Nonnull @Override public String toString() { return "NPCMemory{npcRole='" @@ -200,7 +204,7 @@ public class NPCMemory extends Memory { public static class GatherMemoriesSystem extends EntityTickingSystem { @Nonnull public static final Query QUERY = Query.and( - TransformComponent.getComponentType(), Player.getComponentType(), PlayerMemories.getComponentType() + TransformComponent.getComponentType(), Player.getComponentType(), PlayerRef.getComponentType(), PlayerMemories.getComponentType() ); private final double radius; @@ -248,10 +252,7 @@ public class NPCMemory extends Memory { NPCEntity npcComponent = commandBuffer.getComponent(npcRef, NPCEntity.getComponentType()); if (npcComponent != null) { Role role = npcComponent.getRole(); - - assert role != null; - - if (role.isMemory()) { + if (role != null && role.isMemory()) { temp.isMemoriesNameOverridden = role.isMemoriesNameOverriden(); temp.npcRole = temp.isMemoriesNameOverridden ? role.getMemoriesNameOverride() : npcComponent.getRoleName(); temp.memoryTitleKey = role.getNameTranslationKey(); @@ -268,29 +269,30 @@ public class NPCMemory extends Memory { ); temp = new NPCMemory(); TransformComponent npcTransformComponent = commandBuffer.getComponent(npcRef, TransformComponent.getComponentType()); - - assert npcTransformComponent != null; - - MemoriesGameplayConfig memoriesGameplayConfig = MemoriesGameplayConfig.get(store.getExternalData().getWorld().getGameplayConfig()); - if (memoriesGameplayConfig != null) { - ItemStack memoryItemStack = new ItemStack(memoriesGameplayConfig.getMemoriesCatchItemId()); - Vector3d memoryItemHolderPosition = npcTransformComponent.getPosition().clone(); - BoundingBox boundingBoxComponent = commandBuffer.getComponent(npcRef, BoundingBox.getComponentType()); - if (boundingBoxComponent != null) { - memoryItemHolderPosition.y = memoryItemHolderPosition.y + boundingBoxComponent.getBoundingBox().middleY(); - } - - Holder memoryItemHolder = ItemComponent.generatePickedUpItem( - memoryItemStack, memoryItemHolderPosition, commandBuffer, ref + if (npcTransformComponent != null) { + MemoriesGameplayConfig memoriesGameplayConfig = MemoriesGameplayConfig.get( + store.getExternalData().getWorld().getGameplayConfig() ); - float memoryCatchItemLifetimeS = 0.62F; - PickupItemComponent pickupItemComponent = memoryItemHolder.getComponent(PickupItemComponent.getComponentType()); + if (memoriesGameplayConfig != null) { + ItemStack memoryItemStack = new ItemStack(memoriesGameplayConfig.getMemoriesCatchItemId()); + Vector3d memoryItemHolderPosition = npcTransformComponent.getPosition().clone(); + BoundingBox boundingBoxComponent = commandBuffer.getComponent(npcRef, BoundingBox.getComponentType()); + if (boundingBoxComponent != null) { + memoryItemHolderPosition.y = memoryItemHolderPosition.y + boundingBoxComponent.getBoundingBox().middleY(); + } - assert pickupItemComponent != null; + Holder memoryItemHolder = ItemComponent.generatePickedUpItem( + memoryItemStack, memoryItemHolderPosition, commandBuffer, ref + ); + float memoryCatchItemLifetimeS = 0.62F; + PickupItemComponent pickupItemComponent = memoryItemHolder.getComponent(PickupItemComponent.getComponentType()); - pickupItemComponent.setInitialLifeTime(0.62F); - commandBuffer.addEntity(memoryItemHolder, AddReason.SPAWN); - displayCatchEntityParticles(memoriesGameplayConfig, memoryItemHolderPosition, npcRef, commandBuffer); + assert pickupItemComponent != null; + + pickupItemComponent.setInitialLifeTime(0.62F); + commandBuffer.addEntity(memoryItemHolder, AddReason.SPAWN); + displayCatchEntityParticles(memoriesGameplayConfig, memoryItemHolderPosition, npcRef, commandBuffer); + } } } } @@ -301,7 +303,7 @@ public class NPCMemory extends Memory { } } - private static String findLocationZoneName(World world, Vector3d position) { + private static String findLocationZoneName(@Nonnull World world, @Nonnull Vector3d position) { if (world.getChunkStore().getGenerator() instanceof ChunkGenerator generator) { int seed = (int)world.getWorldConfig().getSeed(); ZoneBiomeResult result = generator.getZoneBiomeResultAt(seed, MathUtil.floor(position.x), MathUtil.floor(position.z)); @@ -320,7 +322,10 @@ public class NPCMemory extends Memory { } private static void displayCatchEntityParticles( - MemoriesGameplayConfig memoriesGameplayConfig, Vector3d targetPosition, Ref targetRef, @Nonnull CommandBuffer commandBuffer + @Nonnull MemoriesGameplayConfig memoriesGameplayConfig, + @Nonnull Vector3d targetPosition, + @Nonnull Ref targetRef, + @Nonnull CommandBuffer commandBuffer ) { ModelParticle particle = memoriesGameplayConfig.getMemoriesCatchEntityParticle(); if (particle != null) { @@ -335,10 +340,9 @@ public class NPCMemory extends Memory { for (Ref ref : results) { PlayerRef playerRefComponent = commandBuffer.getComponent(ref, PlayerRef.getComponentType()); - - assert playerRefComponent != null; - - playerRefComponent.getPacketHandler().write(packet); + if (playerRefComponent != null) { + playerRefComponent.getPacketHandler().write(packet); + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesPage.java b/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesPage.java index 9ddd9951..68d7b787 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesPage.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesPage.java @@ -34,11 +34,8 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectList; import java.time.Instant; import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; import java.util.Comparator; import java.util.Iterator; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.Map.Entry; @@ -50,9 +47,10 @@ public class MemoriesPage extends InteractiveCustomUIPage CODEC = new EnumCodec<>(MemoriesPage.PageAction.class); } public static class PageEventData { + @Nonnull public static final String KEY_ACTION = "Action"; + @Nonnull public static final String KEY_CATEGORY = "Category"; + @Nonnull public static final String KEY_MEMORY_ID = "MemoryId"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MemoriesPage.PageEventData.class, MemoriesPage.PageEventData::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesPageSupplier.java b/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesPageSupplier.java index 896d6861..df1e3739 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesPageSupplier.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesPageSupplier.java @@ -2,17 +2,25 @@ package com.hypixel.hytale.builtin.adventure.memories.page; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.protocol.BlockPosition; import com.hypixel.hytale.server.core.entity.InteractionContext; import com.hypixel.hytale.server.core.entity.entities.player.pages.CustomUIPage; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.server.OpenCustomUIInteraction; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MemoriesPageSupplier implements OpenCustomUIInteraction.CustomPageSupplier { @Nullable @Override - public CustomUIPage tryCreate(Ref ref, ComponentAccessor componentAccessor, PlayerRef playerRef, InteractionContext context) { - return new MemoriesPage(playerRef, context.getTargetBlock()); + public CustomUIPage tryCreate( + @Nonnull Ref ref, + @Nonnull ComponentAccessor componentAccessor, + @Nonnull PlayerRef playerRef, + @Nonnull InteractionContext context + ) { + BlockPosition targetBlock = context.getTargetBlock(); + return targetBlock == null ? null : new MemoriesPage(playerRef, targetBlock); } } diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesUnlockedPage.java b/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesUnlockedPage.java index 012a830d..8d928fec 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesUnlockedPage.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesUnlockedPage.java @@ -51,11 +51,14 @@ public class MemoriesUnlockedPage extends InteractiveCustomUIPage CODEC = new EnumCodec<>(MemoriesUnlockedPage.PageAction.class); } public static class PageEventData { + @Nonnull public static final String KEY_ACTION = "Action"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MemoriesUnlockedPage.PageEventData.class, MemoriesUnlockedPage.PageEventData::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesUnlockedPageSuplier.java b/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesUnlockedPageSuplier.java index 801c1406..1aca0b4a 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesUnlockedPageSuplier.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/page/MemoriesUnlockedPageSuplier.java @@ -2,17 +2,25 @@ package com.hypixel.hytale.builtin.adventure.memories.page; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.protocol.BlockPosition; import com.hypixel.hytale.server.core.entity.InteractionContext; import com.hypixel.hytale.server.core.entity.entities.player.pages.CustomUIPage; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.server.OpenCustomUIInteraction; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MemoriesUnlockedPageSuplier implements OpenCustomUIInteraction.CustomPageSupplier { @Nullable @Override - public CustomUIPage tryCreate(Ref ref, ComponentAccessor componentAccessor, PlayerRef playerRef, InteractionContext context) { - return new MemoriesUnlockedPage(playerRef, context.getTargetBlock()); + public CustomUIPage tryCreate( + @Nonnull Ref ref, + @Nonnull ComponentAccessor componentAccessor, + @Nonnull PlayerRef playerRef, + @Nonnull InteractionContext context + ) { + BlockPosition targetBlock = context.getTargetBlock(); + return targetBlock == null ? null : new MemoriesUnlockedPage(playerRef, targetBlock); } } diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/temple/ForgottenTempleConfig.java b/src/com/hypixel/hytale/builtin/adventure/memories/temple/ForgottenTempleConfig.java index 67760a9f..58fa78dd 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/temple/ForgottenTempleConfig.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/temple/ForgottenTempleConfig.java @@ -4,8 +4,10 @@ import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.server.core.asset.type.soundevent.config.SoundEvent; +import javax.annotation.Nonnull; public class ForgottenTempleConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ForgottenTempleConfig.class, ForgottenTempleConfig::new) .append(new KeyedCodec<>("MinYRespawn", Codec.DOUBLE), (config, o) -> config.minYRespawn = o, config -> config.minYRespawn) .documentation("The Y at which players are teleported back to spawn.") diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/temple/TempleRespawnPlayersSystem.java b/src/com/hypixel/hytale/builtin/adventure/memories/temple/TempleRespawnPlayersSystem.java index 16da9251..2f6e2b87 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/temple/TempleRespawnPlayersSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/temple/TempleRespawnPlayersSystem.java @@ -21,6 +21,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class TempleRespawnPlayersSystem extends DelayedEntitySystem { + @Nonnull public static final Query QUERY = Query.and(PlayerRef.getComponentType(), TransformComponent.getComponentType()); public TempleRespawnPlayersSystem() { diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/window/MemoriesWindow.java b/src/com/hypixel/hytale/builtin/adventure/memories/window/MemoriesWindow.java index c5b8eb0f..62c18ea6 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/window/MemoriesWindow.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/window/MemoriesWindow.java @@ -21,6 +21,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MemoriesWindow extends Window { + @Nonnull private final JsonObject windowData = new JsonObject(); public MemoriesWindow() { diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/NPCObjectivesPlugin.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/NPCObjectivesPlugin.java index f686d5a1..5ee7c4a3 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/NPCObjectivesPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/NPCObjectivesPlugin.java @@ -23,6 +23,7 @@ import com.hypixel.hytale.builtin.adventure.objectives.config.task.UseEntityObje import com.hypixel.hytale.builtin.adventure.objectives.task.ObjectiveTask; import com.hypixel.hytale.builtin.adventure.objectives.task.UseEntityObjectiveTask; import com.hypixel.hytale.builtin.tagset.config.NPCGroup; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; @@ -56,45 +57,43 @@ public class NPCObjectivesPlugin extends JavaPlugin { @Override protected void setup() { instance = this; - ObjectivePlugin.get() - .registerTask( - "KillSpawnBeacon", - KillSpawnBeaconObjectiveTaskAsset.class, - KillSpawnBeaconObjectiveTaskAsset.CODEC, - KillSpawnBeaconObjectiveTask.class, - KillSpawnBeaconObjectiveTask.CODEC, - KillSpawnBeaconObjectiveTask::new - ); - ObjectivePlugin.get() - .registerTask( - "KillSpawnMarker", - KillSpawnMarkerObjectiveTaskAsset.class, - KillSpawnMarkerObjectiveTaskAsset.CODEC, - KillSpawnMarkerObjectiveTask.class, - KillSpawnMarkerObjectiveTask.CODEC, - KillSpawnMarkerObjectiveTask::new - ); - ObjectivePlugin.get() - .registerTask( - "Bounty", - BountyObjectiveTaskAsset.class, - BountyObjectiveTaskAsset.CODEC, - BountyObjectiveTask.class, - BountyObjectiveTask.CODEC, - BountyObjectiveTask::new - ); - ObjectivePlugin.get() - .registerTask( - "KillNPC", - KillObjectiveTaskAsset.class, - KillObjectiveTaskAsset.CODEC, - KillNPCObjectiveTask.class, - KillNPCObjectiveTask.CODEC, - KillNPCObjectiveTask::new - ); - this.getEntityStoreRegistry().registerSystem(new SpawnBeaconCheckRemovalSystem()); - this.killTrackerResourceType = this.getEntityStoreRegistry().registerResource(KillTrackerResource.class, KillTrackerResource::new); - this.getEntityStoreRegistry().registerSystem(new KillTrackerSystem()); + ObjectivePlugin objectivePlugin = ObjectivePlugin.get(); + ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); + objectivePlugin.registerTask( + "KillSpawnBeacon", + KillSpawnBeaconObjectiveTaskAsset.class, + KillSpawnBeaconObjectiveTaskAsset.CODEC, + KillSpawnBeaconObjectiveTask.class, + KillSpawnBeaconObjectiveTask.CODEC, + KillSpawnBeaconObjectiveTask::new + ); + objectivePlugin.registerTask( + "KillSpawnMarker", + KillSpawnMarkerObjectiveTaskAsset.class, + KillSpawnMarkerObjectiveTaskAsset.CODEC, + KillSpawnMarkerObjectiveTask.class, + KillSpawnMarkerObjectiveTask.CODEC, + KillSpawnMarkerObjectiveTask::new + ); + objectivePlugin.registerTask( + "Bounty", + BountyObjectiveTaskAsset.class, + BountyObjectiveTaskAsset.CODEC, + BountyObjectiveTask.class, + BountyObjectiveTask.CODEC, + BountyObjectiveTask::new + ); + objectivePlugin.registerTask( + "KillNPC", + KillObjectiveTaskAsset.class, + KillObjectiveTaskAsset.CODEC, + KillNPCObjectiveTask.class, + KillNPCObjectiveTask.CODEC, + KillNPCObjectiveTask::new + ); + entityStoreRegistry.registerSystem(new SpawnBeaconCheckRemovalSystem()); + this.killTrackerResourceType = entityStoreRegistry.registerResource(KillTrackerResource.class, KillTrackerResource::new); + entityStoreRegistry.registerSystem(new KillTrackerSystem()); NPCPlugin.get() .registerCoreComponentType("CompleteTask", BuilderActionCompleteTask::new) .registerCoreComponentType("StartObjective", BuilderActionStartObjective::new) @@ -114,48 +113,51 @@ public class NPCObjectivesPlugin extends JavaPlugin { @Nonnull Store store, @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull UUID npcId, @Nonnull String taskId ) { UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType()); - - assert uuidComponent != null; - - ObjectiveDataStore objectiveDataStore = ObjectivePlugin.get().getObjectiveDataStore(); - Map> entityObjectiveUUIDs = objectiveDataStore.getEntityTasksForPlayer(uuidComponent.getUuid()); - if (entityObjectiveUUIDs == null) { + if (uuidComponent == null) { return null; } else { - Set objectiveUUIDsForTaskId = entityObjectiveUUIDs.get(taskId); - if (objectiveUUIDsForTaskId == null) { + ObjectiveDataStore objectiveDataStore = ObjectivePlugin.get().getObjectiveDataStore(); + Map> entityObjectiveUUIDs = objectiveDataStore.getEntityTasksForPlayer(uuidComponent.getUuid()); + if (entityObjectiveUUIDs == null) { return null; } else { - for (UUID objectiveUUID : objectiveUUIDsForTaskId) { - Objective objective = objectiveDataStore.getObjective(objectiveUUID); - if (objective != null) { - for (ObjectiveTask task : objective.getCurrentTasks()) { - if (task instanceof UseEntityObjectiveTask useEntityTask) { - UseEntityObjectiveTaskAsset taskAsset = useEntityTask.getAsset(); - if (taskAsset.getTaskId().equals(taskId)) { - if (!useEntityTask.increaseTaskCompletion(store, ref, 1, objective, playerRef, npcId)) { - return null; - } + Set objectiveUUIDsForTaskId = entityObjectiveUUIDs.get(taskId); + if (objectiveUUIDsForTaskId == null) { + return null; + } else { + for (UUID objectiveUUID : objectiveUUIDsForTaskId) { + Objective objective = objectiveDataStore.getObjective(objectiveUUID); + if (objective != null) { + ObjectiveTask[] currentTasks = objective.getCurrentTasks(); + if (currentTasks != null) { + for (ObjectiveTask task : currentTasks) { + if (task instanceof UseEntityObjectiveTask useEntityTask) { + UseEntityObjectiveTaskAsset taskAsset = useEntityTask.getAsset(); + if (taskAsset.getTaskId().equals(taskId)) { + if (!useEntityTask.increaseTaskCompletion(store, ref, 1, objective, playerRef, npcId)) { + return null; + } - return taskAsset.getAnimationIdToPlay(); + return taskAsset.getAnimationIdToPlay(); + } + } } } } } - } - return null; + return null; + } } } } - public static void startObjective(@Nonnull Ref playerReference, @Nonnull String taskId, @Nonnull Store store) { - UUIDComponent uuidComponent = store.getComponent(playerReference, UUIDComponent.getComponentType()); - - assert uuidComponent != null; - - World world = store.getExternalData().getWorld(); - ObjectivePlugin.get().startObjective(taskId, Set.of(uuidComponent.getUuid()), world.getWorldConfig().getUuid(), null, store); + public static void startObjective(@Nonnull Ref playerRef, @Nonnull String taskId, @Nonnull Store store) { + UUIDComponent uuidComponent = store.getComponent(playerRef, UUIDComponent.getComponentType()); + if (uuidComponent != null) { + World world = store.getExternalData().getWorld(); + ObjectivePlugin.get().startObjective(taskId, Set.of(uuidComponent.getUuid()), world.getWorldConfig().getUuid(), null, store); + } } public ResourceType getKillTrackerResourceType() { diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/BountyObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/BountyObjectiveTaskAsset.java index 9e843d30..c8c37a6e 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/BountyObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/BountyObjectiveTaskAsset.java @@ -12,6 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; public class BountyObjectiveTaskAsset extends ObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( BountyObjectiveTaskAsset.class, BountyObjectiveTaskAsset::new, ObjectiveTaskAsset.BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillObjectiveTaskAsset.java index b8f7c1b8..3499421b 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillObjectiveTaskAsset.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class KillObjectiveTaskAsset extends CountObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( KillObjectiveTaskAsset.class, KillObjectiveTaskAsset::new, CountObjectiveTaskAsset.CODEC ) @@ -45,7 +46,7 @@ public class KillObjectiveTaskAsset extends CountObjectiveTaskAsset { if (!super.matchesAsset0(task)) { return false; } else { - return !(task instanceof KillObjectiveTaskAsset) ? false : ((KillObjectiveTaskAsset)task).npcGroupId.equals(this.npcGroupId); + return task instanceof KillObjectiveTaskAsset killObjectiveTaskAsset ? killObjectiveTaskAsset.npcGroupId.equals(this.npcGroupId) : false; } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillSpawnBeaconObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillSpawnBeaconObjectiveTaskAsset.java index 4b3247ba..ec2acc7d 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillSpawnBeaconObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillSpawnBeaconObjectiveTaskAsset.java @@ -16,6 +16,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class KillSpawnBeaconObjectiveTaskAsset extends KillObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( KillSpawnBeaconObjectiveTaskAsset.class, KillSpawnBeaconObjectiveTaskAsset::new, KillObjectiveTaskAsset.CODEC ) @@ -56,9 +57,9 @@ public class KillSpawnBeaconObjectiveTaskAsset extends KillObjectiveTaskAsset { if (!super.matchesAsset0(task)) { return false; } else { - return !(task instanceof KillSpawnBeaconObjectiveTaskAsset) - ? false - : Arrays.equals((Object[])((KillSpawnBeaconObjectiveTaskAsset)task).spawnBeacons, (Object[])this.spawnBeacons); + return task instanceof KillSpawnBeaconObjectiveTaskAsset killSpawnBeaconObjectiveTaskAsset + ? Arrays.equals((Object[])killSpawnBeaconObjectiveTaskAsset.spawnBeacons, (Object[])this.spawnBeacons) + : false; } } @@ -69,6 +70,7 @@ public class KillSpawnBeaconObjectiveTaskAsset extends KillObjectiveTaskAsset { } public static class ObjectiveSpawnBeacon { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( KillSpawnBeaconObjectiveTaskAsset.ObjectiveSpawnBeacon.class, KillSpawnBeaconObjectiveTaskAsset.ObjectiveSpawnBeacon::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillSpawnMarkerObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillSpawnMarkerObjectiveTaskAsset.java index 1ba2733b..16e9a073 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillSpawnMarkerObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/assets/KillSpawnMarkerObjectiveTaskAsset.java @@ -14,6 +14,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; public class KillSpawnMarkerObjectiveTaskAsset extends KillObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( KillSpawnMarkerObjectiveTaskAsset.class, KillSpawnMarkerObjectiveTaskAsset::new, KillObjectiveTaskAsset.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/ActionCompleteTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/ActionCompleteTask.java index c8f1e194..cac6d0b3 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/ActionCompleteTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/ActionCompleteTask.java @@ -25,41 +25,42 @@ public class ActionCompleteTask extends ActionPlayAnimation { @Override public boolean canExecute(@Nonnull Ref ref, @Nonnull Role role, InfoProvider sensorInfo, double dt, @Nonnull Store store) { - Ref target = role.getStateSupport().getInteractionIterationTarget(); - boolean targetExists = target != null && !store.getArchetype(target).contains(DeathComponent.getComponentType()); + Ref targetRef = role.getStateSupport().getInteractionIterationTarget(); + boolean targetExists = targetRef != null && targetRef.isValid() && !store.getArchetype(targetRef).contains(DeathComponent.getComponentType()); return super.canExecute(ref, role, sensorInfo, dt, store) && targetExists; } @Override public boolean execute(@Nonnull Ref ref, @Nonnull Role role, InfoProvider sensorInfo, double dt, @Nonnull Store store) { UUIDComponent parentUuidComponent = store.getComponent(ref, UUIDComponent.getComponentType()); - - assert parentUuidComponent != null; - - Ref targetPlayerReference = role.getStateSupport().getInteractionIterationTarget(); - if (targetPlayerReference == null) { + if (parentUuidComponent == null) { return false; } else { - PlayerRef targetPlayerRefComponent = store.getComponent(targetPlayerReference, PlayerRef.getComponentType()); - if (targetPlayerRefComponent == null) { + Ref targetPlayerReference = role.getStateSupport().getInteractionIterationTarget(); + if (targetPlayerReference == null) { return false; } else { - List activeTasks = role.getEntitySupport().getTargetPlayerActiveTasks(); - String animation = null; - if (activeTasks != null) { - for (int i = 0; i < activeTasks.size(); i++) { - animation = NPCObjectivesPlugin.updateTaskCompletion( - store, targetPlayerReference, targetPlayerRefComponent, parentUuidComponent.getUuid(), activeTasks.get(i) - ); + PlayerRef targetPlayerRefComponent = store.getComponent(targetPlayerReference, PlayerRef.getComponentType()); + if (targetPlayerRefComponent == null) { + return false; + } else { + List activeTasks = role.getEntitySupport().getTargetPlayerActiveTasks(); + String animation = null; + if (activeTasks != null) { + for (int i = 0; i < activeTasks.size(); i++) { + animation = NPCObjectivesPlugin.updateTaskCompletion( + store, targetPlayerReference, targetPlayerRefComponent, parentUuidComponent.getUuid(), activeTasks.get(i) + ); + } } - } - if (this.playAnimation && animation != null) { - this.setAnimationId(animation); - super.execute(ref, role, sensorInfo, dt, store); - } + if (this.playAnimation && animation != null) { + this.setAnimationId(animation); + super.execute(ref, role, sensorInfo, dt, store); + } - return true; + return true; + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/ActionStartObjective.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/ActionStartObjective.java index c5032026..0559b5ab 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/ActionStartObjective.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/ActionStartObjective.java @@ -27,7 +27,12 @@ public class ActionStartObjective extends ActionBase { @Override public boolean execute(@Nonnull Ref ref, @Nonnull Role role, InfoProvider sensorInfo, double dt, @Nonnull Store store) { super.execute(ref, role, sensorInfo, dt, store); - NPCObjectivesPlugin.startObjective(role.getStateSupport().getInteractionIterationTarget(), this.objectiveId, store); - return true; + Ref interactionIterationTarget = role.getStateSupport().getInteractionIterationTarget(); + if (interactionIterationTarget == null) { + return false; + } else { + NPCObjectivesPlugin.startObjective(interactionIterationTarget, this.objectiveId, store); + return true; + } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/SensorHasTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/SensorHasTask.java index d6e1ebb3..de3cad98 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/SensorHasTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/SensorHasTask.java @@ -30,39 +30,42 @@ public class SensorHasTask extends SensorBase { public boolean matches(@Nonnull Ref ref, @Nonnull Role role, double dt, @Nonnull Store store) { if (!super.matches(ref, role, dt, store)) { return false; - } else { - Ref target = role.getStateSupport().getInteractionIterationTarget(); - if (target == null) { - return false; - } else { - Archetype targetArchetype = store.getArchetype(target); + } else if (this.tasksById != null && this.tasksById.length != 0) { + Ref targetRef = role.getStateSupport().getInteractionIterationTarget(); + if (targetRef != null && targetRef.isValid()) { + Archetype targetArchetype = store.getArchetype(targetRef); if (targetArchetype.contains(DeathComponent.getComponentType())) { return false; } else { - UUIDComponent targetUuidComponent = store.getComponent(target, UUIDComponent.getComponentType()); + UUIDComponent targetUuidComponent = store.getComponent(targetRef, UUIDComponent.getComponentType()); + if (targetUuidComponent == null) { + return false; + } else { + UUID targetUuid = targetUuidComponent.getUuid(); + UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType()); + if (uuidComponent == null) { + return false; + } else { + UUID uuid = uuidComponent.getUuid(); + EntitySupport entitySupport = role.getEntitySupport(); + boolean match = false; - assert targetUuidComponent != null; + for (String taskById : this.tasksById) { + if (NPCObjectivesPlugin.hasTask(targetUuid, uuid, taskById)) { + match = true; + entitySupport.addTargetPlayerActiveTask(taskById); + } + } - UUID targetUuid = targetUuidComponent.getUuid(); - UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType()); - - assert uuidComponent != null; - - UUID uuid = uuidComponent.getUuid(); - NPCObjectivesPlugin objectiveSystem = NPCObjectivesPlugin.get(); - EntitySupport entitySupport = role.getEntitySupport(); - boolean match = false; - - for (String taskById : this.tasksById) { - if (NPCObjectivesPlugin.hasTask(targetUuid, uuid, taskById)) { - match = true; - entitySupport.addTargetPlayerActiveTask(taskById); + return match; } } - - return match; } + } else { + return false; } + } else { + return false; } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderActionCompleteTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderActionCompleteTask.java index 1d1a6a25..47949df3 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderActionCompleteTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderActionCompleteTask.java @@ -11,6 +11,7 @@ import java.util.EnumSet; import javax.annotation.Nonnull; public class BuilderActionCompleteTask extends BuilderActionPlayAnimation { + @Nonnull protected final BooleanHolder playAnimation = new BooleanHolder(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderActionStartObjective.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderActionStartObjective.java index a65a07d5..92e1c21d 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderActionStartObjective.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderActionStartObjective.java @@ -12,6 +12,7 @@ import java.util.EnumSet; import javax.annotation.Nonnull; public class BuilderActionStartObjective extends BuilderActionBase { + @Nonnull protected final AssetHolder objectiveId = new AssetHolder(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderSensorHasTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderSensorHasTask.java index a55f799f..4b85cc6a 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderSensorHasTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/builders/BuilderSensorHasTask.java @@ -15,6 +15,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BuilderSensorHasTask extends BuilderSensorBase { + @Nonnull protected final StringArrayHolder tasksById = new StringArrayHolder(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/validators/ObjectiveExistsValidator.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/validators/ObjectiveExistsValidator.java index e6a6bc70..c831122c 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/validators/ObjectiveExistsValidator.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/npc/validators/ObjectiveExistsValidator.java @@ -6,6 +6,7 @@ import java.util.EnumSet; import javax.annotation.Nonnull; public class ObjectiveExistsValidator extends AssetValidator { + @Nonnull private static final ObjectiveExistsValidator DEFAULT_INSTANCE = new ObjectiveExistsValidator(); private ObjectiveExistsValidator() { @@ -38,6 +39,7 @@ public class ObjectiveExistsValidator extends AssetValidator { return ObjectiveAsset.class.getSimpleName(); } + @Nonnull public static ObjectiveExistsValidator required() { return DEFAULT_INSTANCE; } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/resources/KillTrackerResource.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/resources/KillTrackerResource.java index 53d2d44d..5f4b54ca 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/resources/KillTrackerResource.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/resources/KillTrackerResource.java @@ -10,17 +10,18 @@ import java.util.List; import javax.annotation.Nonnull; public class KillTrackerResource implements Resource { + @Nonnull private final List killTasks = new ObjectArrayList<>(); public static ResourceType getResourceType() { return NPCObjectivesPlugin.get().getKillTrackerResourceType(); } - public void watch(KillTaskTransaction task) { + public void watch(@Nonnull KillTaskTransaction task) { this.killTasks.add(task); } - public void unwatch(KillTaskTransaction task) { + public void unwatch(@Nonnull KillTaskTransaction task) { this.killTasks.remove(task); } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/KillTrackerSystem.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/KillTrackerSystem.java index 1afcd587..78f4394c 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/KillTrackerSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/KillTrackerSystem.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; +import com.hypixel.hytale.server.core.modules.entity.damage.Damage; import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent; import com.hypixel.hytale.server.core.modules.entity.damage.DeathSystems; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; @@ -24,14 +25,20 @@ public class KillTrackerSystem extends DeathSystems.OnDeathSystem { public void onComponentAdded( @Nonnull Ref ref, @Nonnull DeathComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - NPCEntity entity = store.getComponent(ref, NPCEntity.getComponentType()); - KillTrackerResource tracker = store.getResource(KillTrackerResource.getResourceType()); - List killTasks = tracker.getKillTasks(); - int size = killTasks.size(); + NPCEntity npcEntityComponent = store.getComponent(ref, NPCEntity.getComponentType()); - for (int i = size - 1; i >= 0; i--) { - KillTaskTransaction entry = killTasks.get(i); - entry.getTask().checkKilledEntity(store, ref, entry.getObjective(), entity, component.getDeathInfo()); + assert npcEntityComponent != null; + + KillTrackerResource killTrackerResource = store.getResource(KillTrackerResource.getResourceType()); + List killTasks = killTrackerResource.getKillTasks(); + Damage deathInfo = component.getDeathInfo(); + if (deathInfo != null) { + int size = killTasks.size(); + + for (int i = size - 1; i >= 0; i--) { + KillTaskTransaction entry = killTasks.get(i); + entry.getTask().checkKilledEntity(store, ref, entry.getObjective(), npcEntityComponent, deathInfo); + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/BountyObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/BountyObjectiveTask.java index 8929cf8f..99c875c3 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/BountyObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/BountyObjectiveTask.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.builtin.adventure.npcobjectives.transaction.KillTaskTr import com.hypixel.hytale.builtin.adventure.objectives.Objective; import com.hypixel.hytale.builtin.adventure.objectives.ObjectivePlugin; import com.hypixel.hytale.builtin.adventure.objectives.config.task.ObjectiveTaskAsset; +import com.hypixel.hytale.builtin.adventure.objectives.markers.ObjectiveTaskMarker; import com.hypixel.hytale.builtin.adventure.objectives.task.ObjectiveTask; import com.hypixel.hytale.builtin.adventure.objectives.transaction.RegistrationTransactionRecord; import com.hypixel.hytale.builtin.adventure.objectives.transaction.SpawnEntityTransactionRecord; @@ -15,25 +16,29 @@ import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3f; import com.hypixel.hytale.math.vector.Vector3i; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.modules.entity.damage.Damage; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.npc.INonPlayerCharacter; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.util.PositionUtil; import com.hypixel.hytale.server.npc.NPCPlugin; import com.hypixel.hytale.server.npc.entities.NPCEntity; import it.unimi.dsi.fastutil.Pair; import java.util.UUID; import java.util.logging.Level; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class BountyObjectiveTask extends ObjectiveTask implements KillTask { + @Nonnull + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( BountyObjectiveTask.class, BountyObjectiveTask::new, ObjectiveTask.BASE_CODEC ) @@ -65,36 +70,47 @@ public class BountyObjectiveTask extends ObjectiveTask implements KillTask { return (BountyObjectiveTaskAsset)super.getAsset(); } - @Nonnull + @Nullable @Override protected TransactionRecord[] setup0(@Nonnull Objective objective, @Nonnull World world, @Nonnull Store store) { if (this.serializedTransactionRecords != null) { return RegistrationTransactionRecord.append(this.serializedTransactionRecords, this.eventRegistry); } else { Vector3d objectivePosition = objective.getPosition(store); - - assert objectivePosition != null; - - Vector3i spawnPosition = this.getAsset().getWorldLocationProvider().runCondition(world, objectivePosition.clone().floor().toVector3i()); - TransactionRecord[] transactionRecords = new TransactionRecord[2]; - Pair, INonPlayerCharacter> npcPair = NPCPlugin.get() - .spawnNPC(store, this.getAsset().getNpcId(), null, spawnPosition.toVector3d(), Vector3f.ZERO); - Ref npcReference = npcPair.first(); - UUIDComponent npcUuidComponent = store.getComponent(npcReference, UUIDComponent.getComponentType()); - - assert npcUuidComponent != null; - - UUID npcUuid = npcUuidComponent.getUuid(); - ObjectivePlugin.get().getLogger().at(Level.INFO).log("Spawned Entity '" + this.getAsset().getNpcId() + "' at position: " + spawnPosition); - transactionRecords[0] = new SpawnEntityTransactionRecord(world.getWorldConfig().getUuid(), npcUuid); - this.entityUuid = npcUuid; - this.addMarker( - new MapMarker(getBountyMarkerIDFromUUID(npcUuid), "Bounty Target", "Home.png", PositionUtil.toTransformPacket(new Transform(spawnPosition)), null) - ); - KillTaskTransaction transaction = new KillTaskTransaction(this, objective, store); - store.getResource(KillTrackerResource.getResourceType()).watch(transaction); - transactionRecords[1] = transaction; - return transactionRecords; + if (objectivePosition == null) { + return null; + } else { + Vector3i spawnPosition = this.getAsset().getWorldLocationProvider().runCondition(world, objectivePosition.clone().floor().toVector3i()); + if (spawnPosition == null) { + return null; + } else { + TransactionRecord[] transactionRecords = new TransactionRecord[2]; + String npcId = this.getAsset().getNpcId(); + Pair, INonPlayerCharacter> npcPair = NPCPlugin.get().spawnNPC(store, npcId, null, spawnPosition.toVector3d(), Vector3f.ZERO); + if (npcPair == null) { + return null; + } else { + Ref npcReference = npcPair.first(); + UUIDComponent npcUuidComponent = store.getComponent(npcReference, UUIDComponent.getComponentType()); + if (npcUuidComponent == null) { + return null; + } else { + UUID npcUuid = npcUuidComponent.getUuid(); + ObjectivePlugin.get().getLogger().at(Level.INFO).log("Spawned Entity '" + npcId + "' at position: " + spawnPosition); + transactionRecords[0] = new SpawnEntityTransactionRecord(world.getWorldConfig().getUuid(), npcUuid); + this.entityUuid = npcUuid; + ObjectiveTaskMarker marker = new ObjectiveTaskMarker( + getBountyMarkerIDFromUUID(npcUuid), new Transform(spawnPosition), "Home.png", Message.translation("server.objectives.bounty.marker") + ); + this.addMarker(marker); + KillTaskTransaction transaction = new KillTaskTransaction(this, objective, store); + store.getResource(KillTrackerResource.getResourceType()).watch(transaction); + transactionRecords[1] = transaction; + return transactionRecords; + } + } + } + } } } @@ -110,7 +126,7 @@ public class BountyObjectiveTask extends ObjectiveTask implements KillTask { @Override public void checkKilledEntity( - @Nonnull Store store, @Nonnull Ref npcRef, @Nonnull Objective objective, NPCEntity npc, Damage damageInfo + @Nonnull Store store, @Nonnull Ref npcRef, @Nonnull Objective objective, @Nonnull NPCEntity npc, @Nonnull Damage damageInfo ) { UUIDComponent uuidComponent = store.getComponent(npcRef, UUIDComponent.getComponentType()); @@ -129,7 +145,8 @@ public class BountyObjectiveTask extends ObjectiveTask implements KillTask { @Nonnull public com.hypixel.hytale.protocol.ObjectiveTask toPacket(@Nonnull Objective objective) { com.hypixel.hytale.protocol.ObjectiveTask packet = new com.hypixel.hytale.protocol.ObjectiveTask(); - packet.taskDescriptionKey = this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex); + packet.taskDescriptionKey = Message.translation(this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex)) + .getFormattedMessage(); packet.currentCompletion = this.completed ? 1 : 0; packet.completionNeeded = 1; return packet; diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillNPCObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillNPCObjectiveTask.java index b4a5573f..c0892c17 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillNPCObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillNPCObjectiveTask.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class KillNPCObjectiveTask extends KillObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( KillNPCObjectiveTask.class, KillNPCObjectiveTask::new, KillObjectiveTask.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillObjectiveTask.java index 2d8be2e4..b5b5d9e3 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillObjectiveTask.java @@ -8,8 +8,6 @@ import com.hypixel.hytale.builtin.tagset.config.NPCGroup; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; -import com.hypixel.hytale.server.core.entity.Entity; -import com.hypixel.hytale.server.core.entity.EntityUtils; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.modules.entity.damage.Damage; @@ -18,6 +16,7 @@ import com.hypixel.hytale.server.npc.entities.NPCEntity; import javax.annotation.Nonnull; public abstract class KillObjectiveTask extends CountObjectiveTask implements KillTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.abstractBuilder(KillObjectiveTask.class, CountObjectiveTask.CODEC).build(); public KillObjectiveTask(@Nonnull KillObjectiveTaskAsset asset, int taskSetIndex, int taskIndex) { @@ -41,16 +40,14 @@ public abstract class KillObjectiveTask extends CountObjectiveTask implements Ki if (index == Integer.MIN_VALUE) { throw new IllegalArgumentException("Unknown npc group! " + key); } else if (TagSetPlugin.get(NPCGroup.class).tagInSet(index, npc.getNPCTypeIndex())) { - if (info.getSource() instanceof Damage.EntitySource) { - Ref attackerEntityRef = ((Damage.EntitySource)info.getSource()).getRef(); - Entity attackerEntity = EntityUtils.getEntity(attackerEntityRef, attackerEntityRef.getStore()); - if (attackerEntity instanceof Player) { - UUIDComponent attackerUuidComponent = store.getComponent(attackerEntityRef, UUIDComponent.getComponentType()); - - assert attackerUuidComponent != null; - - if (objective.getActivePlayerUUIDs().contains(attackerUuidComponent.getUuid())) { - this.increaseTaskCompletion(store, npcRef, 1, objective); + if (info.getSource() instanceof Damage.EntitySource entitySource) { + Ref var11 = entitySource.getRef(); + if (store.getArchetype(var11).contains(Player.getComponentType())) { + UUIDComponent sourceUuidComponent = store.getComponent(var11, UUIDComponent.getComponentType()); + if (sourceUuidComponent != null) { + if (objective.getActivePlayerUUIDs().contains(sourceUuidComponent.getUuid())) { + this.increaseTaskCompletion(store, npcRef, 1, objective); + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillSpawnBeaconObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillSpawnBeaconObjectiveTask.java index 517c3aa7..702bde19 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillSpawnBeaconObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillSpawnBeaconObjectiveTask.java @@ -18,6 +18,7 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3f; +import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; @@ -31,6 +32,7 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class KillSpawnBeaconObjectiveTask extends KillObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( KillSpawnBeaconObjectiveTask.class, KillSpawnBeaconObjectiveTask::new, KillObjectiveTask.CODEC ) @@ -91,7 +93,12 @@ public class KillSpawnBeaconObjectiveTask extends KillObjectiveTask { WorldLocationProvider worldLocationCondition = spawnBeaconConfig.getWorldLocationProvider(); if (worldLocationCondition != null) { - spawnPosition = worldLocationCondition.runCondition(world, spawnPosition.toVector3i()).toVector3d(); + Vector3i potentialSpawnLocation = worldLocationCondition.runCondition(world, spawnPosition.toVector3i()); + if (potentialSpawnLocation != null) { + spawnPosition = potentialSpawnLocation.toVector3d(); + } else { + spawnPosition = null; + } } if (spawnPosition == null) { @@ -103,11 +110,12 @@ public class KillSpawnBeaconObjectiveTask extends KillObjectiveTask { ); spawnBeaconPair.second().setObjectiveUUID(objective.getObjectiveUUID()); UUIDComponent spawnBeaconUuidComponent = componentAccessor.getComponent(spawnBeaconPair.first(), UUIDComponent.getComponentType()); - - assert spawnBeaconUuidComponent != null; - - logger.at(Level.INFO).log("Spawned SpawnBeacon '" + spawnBeaconId + "' at position: " + position); - transactionRecords[i] = new SpawnEntityTransactionRecord(world.getWorldConfig().getUuid(), spawnBeaconUuidComponent.getUuid()); + if (spawnBeaconUuidComponent == null) { + transactionRecords[i] = new WorldTransactionRecord().fail("Failed to retrieve UUID component for spawned beacon " + spawnBeaconId); + } else { + logger.at(Level.INFO).log("Spawned SpawnBeacon '" + spawnBeaconId + "' at position: " + position); + transactionRecords[i] = new SpawnEntityTransactionRecord(world.getWorldConfig().getUuid(), spawnBeaconUuidComponent.getUuid()); + } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillSpawnMarkerObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillSpawnMarkerObjectiveTask.java index e1adc3f9..639b956f 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillSpawnMarkerObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillSpawnMarkerObjectiveTask.java @@ -24,11 +24,13 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class KillSpawnMarkerObjectiveTask extends KillObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( KillSpawnMarkerObjectiveTask.class, KillSpawnMarkerObjectiveTask::new, KillObjectiveTask.CODEC ) .build(); private static final ComponentType SPAWN_MARKER_COMPONENT_TYPE = SpawnMarkerEntity.getComponentType(); + @Nonnull private static final ComponentType TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType(); public KillSpawnMarkerObjectiveTask(@Nonnull KillSpawnMarkerObjectiveTaskAsset asset, int taskSetIndex, int taskIndex) { @@ -55,21 +57,17 @@ public class KillSpawnMarkerObjectiveTask extends KillObjectiveTask { String[] spawnMarkerIds = asset.getSpawnMarkerIds(); HytaleLogger logger = ObjectivePlugin.get().getLogger(); - for (Ref entityReference : results) { - SpawnMarkerEntity entitySpawnMarkerComponent = store.getComponent(entityReference, SPAWN_MARKER_COMPONENT_TYPE); - - assert entitySpawnMarkerComponent != null; - - String spawnMarkerId = entitySpawnMarkerComponent.getSpawnMarkerId(); - if (ArrayUtil.contains(spawnMarkerIds, spawnMarkerId)) { - world.execute(() -> entitySpawnMarkerComponent.trigger(entityReference, store)); - logger.at(Level.INFO) - .log( - "Triggered SpawnMarker '" - + spawnMarkerId - + "' at position: " - + store.getComponent(entityReference, TRANSFORM_COMPONENT_TYPE).getPosition() - ); + for (Ref ref : results) { + SpawnMarkerEntity entitySpawnMarkerComponent = store.getComponent(ref, SPAWN_MARKER_COMPONENT_TYPE); + if (entitySpawnMarkerComponent != null) { + String spawnMarkerId = entitySpawnMarkerComponent.getSpawnMarkerId(); + if (ArrayUtil.contains(spawnMarkerIds, spawnMarkerId)) { + world.execute(() -> entitySpawnMarkerComponent.trigger(ref, store)); + TransformComponent transformComponent = store.getComponent(ref, TRANSFORM_COMPONENT_TYPE); + if (transformComponent != null) { + logger.at(Level.INFO).log("Triggered SpawnMarker '" + spawnMarkerId + "' at position: " + transformComponent.getPosition()); + } + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillTask.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillTask.java index 354a714b..0674229f 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/task/KillTask.java @@ -6,7 +6,10 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.server.core.modules.entity.damage.Damage; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.entities.NPCEntity; +import javax.annotation.Nonnull; public interface KillTask { - void checkKilledEntity(Store var1, Ref var2, Objective var3, NPCEntity var4, Damage var5); + void checkKilledEntity( + @Nonnull Store var1, @Nonnull Ref var2, @Nonnull Objective var3, @Nonnull NPCEntity var4, @Nonnull Damage var5 + ); } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationHolderSystem.java b/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationHolderSystem.java index 5f94b481..bafa1af7 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationHolderSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationHolderSystem.java @@ -17,13 +17,14 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; public class NPCReputationHolderSystem extends HolderSystem { + @Nonnull private final ComponentType reputationGroupComponentType; private final ComponentType npcEntityComponentType; @Nonnull private final Query query; public NPCReputationHolderSystem( - ComponentType reputationGroupComponentType, ComponentType npcEntityComponentType + @Nonnull ComponentType reputationGroupComponentType, ComponentType npcEntityComponentType ) { this.reputationGroupComponentType = reputationGroupComponentType; this.npcEntityComponentType = npcEntityComponentType; @@ -38,8 +39,11 @@ public class NPCReputationHolderSystem extends HolderSystem { @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - NPCEntity npcEntity = holder.getComponent(this.npcEntityComponentType); - int npcTypeIndex = npcEntity.getNPCTypeIndex(); + NPCEntity npcComponent = holder.getComponent(this.npcEntityComponentType); + + assert npcComponent != null; + + int npcTypeIndex = npcComponent.getNPCTypeIndex(); for (Entry reputationEntry : ReputationGroup.getAssetMap().getAssetMap().entrySet()) { for (String npcGroup : reputationEntry.getValue().getNpcGroups()) { diff --git a/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationPlugin.java b/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationPlugin.java index 6bf2e935..ca304025 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationPlugin.java @@ -1,8 +1,10 @@ package com.hypixel.hytale.builtin.adventure.npcreputation; import com.hypixel.hytale.builtin.adventure.reputation.ReputationGroupComponent; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.entities.NPCEntity; import javax.annotation.Nonnull; @@ -13,7 +15,8 @@ public class NPCReputationPlugin extends JavaPlugin { @Override protected void setup() { - this.getEntityStoreRegistry().registerSystem(new ReputationAttitudeSystem()); - this.getEntityStoreRegistry().registerSystem(new NPCReputationHolderSystem(ReputationGroupComponent.getComponentType(), NPCEntity.getComponentType())); + ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); + entityStoreRegistry.registerSystem(new ReputationAttitudeSystem()); + entityStoreRegistry.registerSystem(new NPCReputationHolderSystem(ReputationGroupComponent.getComponentType(), NPCEntity.getComponentType())); } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcreputation/ReputationAttitudeSystem.java b/src/com/hypixel/hytale/builtin/adventure/npcreputation/ReputationAttitudeSystem.java index 423ecdb6..715ebdf9 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcreputation/ReputationAttitudeSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcreputation/ReputationAttitudeSystem.java @@ -11,13 +11,14 @@ import com.hypixel.hytale.server.npc.blackboard.view.attitude.AttitudeView; import javax.annotation.Nonnull; public class ReputationAttitudeSystem extends StoreSystem { + @Nonnull private final ResourceType resourceType = Blackboard.getResourceType(); @Override public void onSystemAddedToStore(@Nonnull Store store) { - Blackboard blackboard = store.getResource(this.resourceType); - AttitudeView view = blackboard.getView(AttitudeView.class, 0L); - view.registerProvider(100, (ref, role, targetRef, accessor) -> { + Blackboard blackboardResource = store.getResource(this.resourceType); + AttitudeView attitudeView = blackboardResource.getView(AttitudeView.class, 0L); + attitudeView.registerProvider(100, (ref, role, targetRef, accessor) -> { Player playerComponent = store.getComponent(targetRef, Player.getComponentType()); return playerComponent == null ? null : ReputationPlugin.get().getAttitude(store, targetRef, ref); }); diff --git a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ActionOpenBarterShop.java b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ActionOpenBarterShop.java index 68b5f022..871d1672 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ActionOpenBarterShop.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ActionOpenBarterShop.java @@ -14,6 +14,7 @@ import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider; import javax.annotation.Nonnull; public class ActionOpenBarterShop extends ActionBase { + @Nonnull protected final String shopId; public ActionOpenBarterShop(@Nonnull BuilderActionOpenBarterShop builder, @Nonnull BuilderSupport support) { diff --git a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ActionOpenShop.java b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ActionOpenShop.java index d5d976b9..db6ded60 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ActionOpenShop.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ActionOpenShop.java @@ -14,6 +14,7 @@ import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider; import javax.annotation.Nonnull; public class ActionOpenShop extends ActionBase { + @Nonnull protected final String shopId; public ActionOpenShop(@Nonnull BuilderActionOpenShop builder, @Nonnull BuilderSupport support) { @@ -34,15 +35,17 @@ public class ActionOpenShop extends ActionBase { return false; } else { PlayerRef playerRefComponent = store.getComponent(playerReference, PlayerRef.getComponentType()); - - assert playerRefComponent != null; - - Player playerComponent = store.getComponent(playerReference, Player.getComponentType()); - - assert playerComponent != null; - - playerComponent.getPageManager().openCustomPage(ref, store, new ShopPage(playerRefComponent, this.shopId)); - return true; + if (playerRefComponent == null) { + return false; + } else { + Player playerComponent = store.getComponent(playerReference, Player.getComponentType()); + if (playerComponent == null) { + return false; + } else { + playerComponent.getPageManager().openCustomPage(ref, store, new ShopPage(playerRefComponent, this.shopId)); + return true; + } + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/BarterShopExistsValidator.java b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/BarterShopExistsValidator.java index 627e2f97..f70fc03c 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/BarterShopExistsValidator.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/BarterShopExistsValidator.java @@ -6,6 +6,7 @@ import java.util.EnumSet; import javax.annotation.Nonnull; public class BarterShopExistsValidator extends AssetValidator { + @Nonnull private static final BarterShopExistsValidator DEFAULT_INSTANCE = new BarterShopExistsValidator(); private BarterShopExistsValidator() { diff --git a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ShopExistsValidator.java b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ShopExistsValidator.java index 6bd0b3a4..e58074bd 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ShopExistsValidator.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/ShopExistsValidator.java @@ -6,6 +6,7 @@ import java.util.EnumSet; import javax.annotation.Nonnull; public class ShopExistsValidator extends AssetValidator { + @Nonnull private static final ShopExistsValidator DEFAULT_INSTANCE = new ShopExistsValidator(); private ShopExistsValidator() { diff --git a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/builders/BuilderActionOpenBarterShop.java b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/builders/BuilderActionOpenBarterShop.java index 3cccc8cd..709e3867 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/builders/BuilderActionOpenBarterShop.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/builders/BuilderActionOpenBarterShop.java @@ -13,6 +13,7 @@ import java.util.EnumSet; import javax.annotation.Nonnull; public class BuilderActionOpenBarterShop extends BuilderActionBase { + @Nonnull protected final AssetHolder shopId = new AssetHolder(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/builders/BuilderActionOpenShop.java b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/builders/BuilderActionOpenShop.java index 24651433..08f7bab4 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/builders/BuilderActionOpenShop.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcshop/npc/builders/BuilderActionOpenShop.java @@ -13,6 +13,7 @@ import java.util.EnumSet; import javax.annotation.Nonnull; public class BuilderActionOpenShop extends BuilderActionBase { + @Nonnull protected final AssetHolder shopId = new AssetHolder(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/adventure/objectivereputation/ReputationCompletion.java b/src/com/hypixel/hytale/builtin/adventure/objectivereputation/ReputationCompletion.java index 5fa22a15..dee0ebcc 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectivereputation/ReputationCompletion.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectivereputation/ReputationCompletion.java @@ -28,8 +28,9 @@ public class ReputationCompletion extends ObjectiveCompletion { Player playerComponent = componentAccessor.getComponent(participantReference, Player.getComponentType()); if (playerComponent != null) { UUIDComponent uuidComponent = componentAccessor.getComponent(participantReference, UUIDComponent.getComponentType()); - - assert uuidComponent != null; + if (uuidComponent == null) { + return; + } String reputationGroupId = asset.getReputationGroupId(); int amount = asset.getAmount(); diff --git a/src/com/hypixel/hytale/builtin/adventure/objectivereputation/assets/ReputationCompletionAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectivereputation/assets/ReputationCompletionAsset.java index ed8a8007..40def0df 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectivereputation/assets/ReputationCompletionAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectivereputation/assets/ReputationCompletionAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class ReputationCompletionAsset extends ObjectiveCompletionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ReputationCompletionAsset.class, ReputationCompletionAsset::new, ObjectiveCompletionAsset.BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectivereputation/historydata/ReputationObjectiveRewardHistoryData.java b/src/com/hypixel/hytale/builtin/adventure/objectivereputation/historydata/ReputationObjectiveRewardHistoryData.java index a3c30621..2c222bb8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectivereputation/historydata/ReputationObjectiveRewardHistoryData.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectivereputation/historydata/ReputationObjectiveRewardHistoryData.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public final class ReputationObjectiveRewardHistoryData extends ObjectiveRewardHistoryData { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ReputationObjectiveRewardHistoryData.class, ReputationObjectiveRewardHistoryData::new, ObjectiveRewardHistoryData.BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/DialogPage.java b/src/com/hypixel/hytale/builtin/adventure/objectives/DialogPage.java index 65c1705a..95a4d6a2 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/DialogPage.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/DialogPage.java @@ -17,6 +17,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class DialogPage extends InteractiveCustomUIPage { + @Nonnull public static final String LAYOUT = "Pages/DialogPage.ui"; private final UseEntityObjectiveTaskAsset.DialogOptions dialogOptions; @@ -37,10 +38,13 @@ public class DialogPage extends InteractiveCustomUIPage ref, @Nonnull Store store, @Nonnull DialogPage.DialogPageEventData data) { Player playerComponent = store.getComponent(ref, Player.getComponentType()); - playerComponent.getPageManager().setPage(ref, store, Page.None); + if (playerComponent != null) { + playerComponent.getPageManager().setPage(ref, store, Page.None); + } } public static class DialogPageEventData { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DialogPage.DialogPageEventData.class, DialogPage.DialogPageEventData::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/Objective.java b/src/com/hypixel/hytale/builtin/adventure/objectives/Objective.java index d17e514e..94d02a52 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/Objective.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/Objective.java @@ -43,6 +43,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class Objective implements NetworkSerializable { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(Objective.class, Objective::new) .append(new KeyedCodec<>("ObjectiveUUID", Codec.UUID_BINARY), (objective, uuid) -> objective.objectiveUUID = uuid, objective -> objective.objectiveUUID) .add() @@ -225,39 +226,47 @@ public class Objective implements NetworkSerializable store) { - for (ObjectiveTask task : this.currentTasks) { - if (!task.isComplete()) { - TransactionRecord[] taskTransactions = task.setup(this, store); - if (taskTransactions != null && TransactionUtil.anyFailed(taskTransactions)) { - ObjectivePlugin.get() - .getLogger() - .at(Level.WARNING) - .log("Failed to setup objective tasks, transaction records:%s", Arrays.toString((Object[])taskTransactions)); + if (this.currentTasks == null) { + return false; + } else { + for (ObjectiveTask task : this.currentTasks) { + if (!task.isComplete()) { + TransactionRecord[] taskTransactions = task.setup(this, store); + if (taskTransactions != null && TransactionUtil.anyFailed(taskTransactions)) { + ObjectivePlugin.get() + .getLogger() + .at(Level.WARNING) + .log("Failed to setup objective tasks, transaction records:%s", Arrays.toString((Object[])taskTransactions)); - for (ObjectiveTask taskSetup : this.currentTasks) { - taskSetup.revertTransactionRecords(); - if (taskSetup == task) { - break; + for (ObjectiveTask taskSetup : this.currentTasks) { + taskSetup.revertTransactionRecords(); + if (taskSetup == task) { + break; + } } - } - return false; + return false; + } } } - } - return true; + return true; + } } public boolean checkTaskSetCompletion(@Nonnull Store store) { - for (ObjectiveTask task : this.currentTasks) { - if (!task.isComplete()) { - return false; + if (this.currentTasks == null) { + return false; + } else { + for (ObjectiveTask task : this.currentTasks) { + if (!task.isComplete()) { + return false; + } } - } - this.taskSetComplete(store); - return true; + this.taskSetComplete(store); + return true; + } } protected void taskSetComplete(@Nonnull Store store) { @@ -269,13 +278,12 @@ public class Objective implements NetworkSerializable { + this.forEachParticipant((participantReference, trackOrUpdateObjective) -> { PlayerRef playerRefComponent = store.getComponent(participantReference, PlayerRef.getComponentType()); if (playerRefComponent != null) { - playerRefComponent.sendMessage(message); playerRefComponent.getPacketHandler().writeNoCache(trackOrUpdateObjective); } - }, this.getTaskInfoMessage(), trackObjectivePacket); + }, trackObjectivePacket); this.checkTaskSetCompletion(store); } } else { @@ -304,28 +312,21 @@ public class Objective implements NetworkSerializable reloadedAssets) { ObjectiveTaskAsset[] taskAssets = this.checkPossibleAssetReload(reloadedAssets); if (taskAssets != null) { @@ -404,13 +405,17 @@ public class Objective implements NetworkSerializable ref = playerRef.getReference(); + if (ref != null && ref.isValid()) { + consumer.accept(playerRef.getReference(), t, u); + } } } } @@ -514,8 +524,8 @@ public class Objective implements NetworkSerializable objectives = new ConcurrentHashMap<>(); + @Nonnull private final Map>> entityObjectiveUUIDsPerPlayer = new ConcurrentHashMap<>(); @Nonnull private final DataStore dataStore; + @Nonnull private final Map, Set>> taskRefByType = new ConcurrentHashMap<>(); @Nonnull private final HytaleLogger logger; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/ObjectivePlugin.java b/src/com/hypixel/hytale/builtin/adventure/objectives/ObjectivePlugin.java index 656050c2..8da406a1 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/ObjectivePlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/ObjectivePlugin.java @@ -110,10 +110,14 @@ import javax.annotation.Nullable; public class ObjectivePlugin extends JavaPlugin { protected static ObjectivePlugin instance; + @Nonnull public static final String OBJECTIVE_LOCATION_MARKER_MODEL_ID = "Objective_Location_Marker"; public static final long SAVE_INTERVAL_MINUTES = 5L; + @Nonnull private final Map, TriFunction> taskGenerators = new ConcurrentHashMap<>(); + @Nonnull private final Map, Function> completionGenerators = new ConcurrentHashMap<>(); + @Nonnull private final Config config = this.withConfig(ObjectivePlugin.ObjectivePluginConfig.CODEC); private Model objectiveLocationMarkerModel; private ComponentType objectiveHistoryComponentType; @@ -391,7 +395,6 @@ public class ObjectivePlugin extends JavaPlugin { activeObjectiveUUIDs.add(objective.getObjectiveUUID()); playerConfigData.setActiveObjectiveUUIDs(activeObjectiveUUIDs); playerRefComponent.sendMessage(Message.translation("server.modules.objective.start.success").param("title", assetTitleMessage)); - playerRefComponent.sendMessage(objective.getTaskInfoMessage()); playerRefComponent.getPacketHandler().writeNoCache(trackObjectivePacket); } } @@ -605,8 +608,8 @@ public class ObjectivePlugin extends JavaPlugin { ObjectiveTask[] currentTasks = objective.getCurrentTasks(); for (ObjectiveTask task : currentTasks) { - if (task instanceof UseEntityObjectiveTask) { - this.objectiveDataStore.removeEntityTaskForPlayer(objectiveUUID, ((UseEntityObjectiveTask)task).getAsset().getTaskId(), playerUUID); + if (task instanceof UseEntityObjectiveTask useEntityObjectiveTask) { + this.objectiveDataStore.removeEntityTaskForPlayer(objectiveUUID, useEntityObjectiveTask.getAsset().getTaskId(), playerUUID); } } @@ -860,7 +863,7 @@ public class ObjectivePlugin extends JavaPlugin { } } - private void onWorldAdded(AddWorldEvent event) { + private void onWorldAdded(@Nonnull AddWorldEvent event) { event.getWorld().getWorldMapManager().addMarkerProvider("objectives", ObjectiveMarkerProvider.INSTANCE); } @@ -887,6 +890,7 @@ public class ObjectivePlugin extends JavaPlugin { } public static class ObjectivePluginConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ObjectivePlugin.ObjectivePluginConfig.class, ObjectivePlugin.ObjectivePluginConfig::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/blockstates/TreasureChestState.java b/src/com/hypixel/hytale/builtin/adventure/objectives/blockstates/TreasureChestState.java index 22419761..caeb3a06 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/blockstates/TreasureChestState.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/blockstates/TreasureChestState.java @@ -23,6 +23,7 @@ import java.util.UUID; import javax.annotation.Nonnull; public class TreasureChestState extends ItemContainerState implements BreakValidatedBlockState { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(TreasureChestState.class, TreasureChestState::new, BlockState.BASE_CODEC) .append( new KeyedCodec<>("ObjectiveUUID", Codec.UUID_BINARY), diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/commands/ObjectiveLocationMarkerCommand.java b/src/com/hypixel/hytale/builtin/adventure/objectives/commands/ObjectiveLocationMarkerCommand.java index 73404efc..c3e75a66 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/commands/ObjectiveLocationMarkerCommand.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/commands/ObjectiveLocationMarkerCommand.java @@ -53,38 +53,36 @@ public class ObjectiveLocationMarkerCommand extends AbstractCommandCollection { protected void execute( @Nonnull CommandContext context, @Nonnull Store store, @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world ) { - Ref playerReference = playerRef.getReference(); - TransformComponent playerTransformComponent = store.getComponent(playerReference, TransformComponent.getComponentType()); - - assert playerTransformComponent != null; - - String objectiveLocationMarkerId = this.locationMarkerArg.get(context); - if (ObjectiveLocationMarkerAsset.getAssetMap().getAsset(objectiveLocationMarkerId) == null) { - context.sendMessage(Message.translation("server.commands.objective.locationMarker.notFound").param("id", objectiveLocationMarkerId)); - context.sendMessage( - Message.translation("server.general.failed.didYouMean") - .param( - "choices", - StringUtil.sortByFuzzyDistance( - objectiveLocationMarkerId, ObjectiveLocationMarkerAsset.getAssetMap().getAssetMap().keySet(), CommandUtil.RECOMMEND_COUNT - ) - .toString() - ) - ); - } else { - Holder holder = EntityStore.REGISTRY.newHolder(); - holder.addComponent(ObjectiveLocationMarker.getComponentType(), new ObjectiveLocationMarker(objectiveLocationMarkerId)); - Model model = ObjectivePlugin.get().getObjectiveLocationMarkerModel(); - holder.addComponent(ModelComponent.getComponentType(), new ModelComponent(model)); - holder.addComponent(PersistentModel.getComponentType(), new PersistentModel(model.toReference())); - holder.addComponent(Nameplate.getComponentType(), new Nameplate(objectiveLocationMarkerId)); - TransformComponent transform = new TransformComponent(playerTransformComponent.getPosition(), playerTransformComponent.getRotation()); - holder.addComponent(TransformComponent.getComponentType(), transform); - holder.ensureComponent(UUIDComponent.getComponentType()); - holder.ensureComponent(Intangible.getComponentType()); - holder.ensureComponent(HiddenFromAdventurePlayers.getComponentType()); - store.addEntity(holder, AddReason.SPAWN); - context.sendMessage(Message.translation("server.commands.objective.locationMarker.added").param("id", objectiveLocationMarkerId)); + TransformComponent playerTransformComponent = store.getComponent(ref, TransformComponent.getComponentType()); + if (playerTransformComponent != null) { + String objectiveLocationMarkerId = this.locationMarkerArg.get(context); + if (ObjectiveLocationMarkerAsset.getAssetMap().getAsset(objectiveLocationMarkerId) == null) { + context.sendMessage(Message.translation("server.commands.objective.locationMarker.notFound").param("id", objectiveLocationMarkerId)); + context.sendMessage( + Message.translation("server.general.failed.didYouMean") + .param( + "choices", + StringUtil.sortByFuzzyDistance( + objectiveLocationMarkerId, ObjectiveLocationMarkerAsset.getAssetMap().getAssetMap().keySet(), CommandUtil.RECOMMEND_COUNT + ) + .toString() + ) + ); + } else { + Holder holder = EntityStore.REGISTRY.newHolder(); + holder.addComponent(ObjectiveLocationMarker.getComponentType(), new ObjectiveLocationMarker(objectiveLocationMarkerId)); + Model model = ObjectivePlugin.get().getObjectiveLocationMarkerModel(); + holder.addComponent(ModelComponent.getComponentType(), new ModelComponent(model)); + holder.addComponent(PersistentModel.getComponentType(), new PersistentModel(model.toReference())); + holder.addComponent(Nameplate.getComponentType(), new Nameplate(objectiveLocationMarkerId)); + TransformComponent transform = new TransformComponent(playerTransformComponent.getPosition(), playerTransformComponent.getRotation()); + holder.addComponent(TransformComponent.getComponentType(), transform); + holder.ensureComponent(UUIDComponent.getComponentType()); + holder.ensureComponent(Intangible.getComponentType()); + holder.ensureComponent(HiddenFromAdventurePlayers.getComponentType()); + store.addEntity(holder, AddReason.SPAWN); + context.sendMessage(Message.translation("server.commands.objective.locationMarker.added").param("id", objectiveLocationMarkerId)); + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/components/ObjectiveHistoryComponent.java b/src/com/hypixel/hytale/builtin/adventure/objectives/components/ObjectiveHistoryComponent.java index 17afea2d..4b16afbb 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/components/ObjectiveHistoryComponent.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/components/ObjectiveHistoryComponent.java @@ -12,6 +12,7 @@ import java.util.Map; import javax.annotation.Nonnull; public class ObjectiveHistoryComponent implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ObjectiveHistoryComponent.class, ObjectiveHistoryComponent::new) .append( new KeyedCodec<>("ObjectiveHistory", new MapCodec<>(ObjectiveHistoryData.CODEC, Object2ObjectOpenHashMap::new, false)), diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveAsset.java index 7d35d88a..7783b87b 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveAsset.java @@ -23,6 +23,7 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class ObjectiveAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( ObjectiveAsset.class, ObjectiveAsset::new, @@ -87,6 +88,7 @@ public class ObjectiveAsset implements JsonAssetWithMap VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(ObjectiveAsset::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data extraData; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveLineAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveLineAsset.java index a10be80c..cd9f51cd 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveLineAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveLineAsset.java @@ -79,6 +79,7 @@ public class ObjectiveLineAsset implements JsonAssetWithMap VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(ObjectiveLineAsset::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data extraData; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveLocationMarkerAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveLocationMarkerAsset.java index 79811ec8..96f71217 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveLocationMarkerAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/ObjectiveLocationMarkerAsset.java @@ -20,6 +20,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; public class ObjectiveLocationMarkerAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( ObjectiveLocationMarkerAsset.class, ObjectiveLocationMarkerAsset::new, @@ -74,6 +75,7 @@ public class ObjectiveLocationMarkerAsset implements JsonAssetWithMap VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(ObjectiveLocationMarkerAsset::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data data; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/ClearObjectiveItemsCompletionAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/ClearObjectiveItemsCompletionAsset.java index f29247a8..52092783 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/ClearObjectiveItemsCompletionAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/ClearObjectiveItemsCompletionAsset.java @@ -4,6 +4,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ClearObjectiveItemsCompletionAsset extends ObjectiveCompletionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ClearObjectiveItemsCompletionAsset.class, ClearObjectiveItemsCompletionAsset::new, BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/GiveItemsCompletionAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/GiveItemsCompletionAsset.java index a3522bb1..843fd6b4 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/GiveItemsCompletionAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/GiveItemsCompletionAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.server.core.asset.type.item.config.ItemDropList; import javax.annotation.Nonnull; public class GiveItemsCompletionAsset extends ObjectiveCompletionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( GiveItemsCompletionAsset.class, GiveItemsCompletionAsset::new, BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/ObjectiveCompletionAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/ObjectiveCompletionAsset.java index fb766fdb..15a8ee8d 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/ObjectiveCompletionAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/completion/ObjectiveCompletionAsset.java @@ -5,7 +5,9 @@ import com.hypixel.hytale.codec.lookup.CodecMapCodec; import javax.annotation.Nonnull; public abstract class ObjectiveCompletionAsset { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(ObjectiveCompletionAsset.class).build(); protected ObjectiveCompletionAsset() { diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/gameplayconfig/ObjectiveGameplayConfig.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/gameplayconfig/ObjectiveGameplayConfig.java index a1e4da0d..5dea9373 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/gameplayconfig/ObjectiveGameplayConfig.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/gameplayconfig/ObjectiveGameplayConfig.java @@ -12,7 +12,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ObjectiveGameplayConfig { + @Nonnull public static final String ID = "Objective"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ObjectiveGameplayConfig.class, ObjectiveGameplayConfig::new) .appendInherited( new KeyedCodec<>("StarterObjectiveLinePerWorld", new MapCodec<>(Codec.STRING, Object2ObjectOpenHashMap::new, true)), diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/markerarea/ObjectiveLocationAreaBox.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/markerarea/ObjectiveLocationAreaBox.java index aa24713c..d01c2762 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/markerarea/ObjectiveLocationAreaBox.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/markerarea/ObjectiveLocationAreaBox.java @@ -16,6 +16,7 @@ import java.util.List; import javax.annotation.Nonnull; public class ObjectiveLocationAreaBox extends ObjectiveLocationMarkerArea { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ObjectiveLocationAreaBox.class, ObjectiveLocationAreaBox::new) .append( new KeyedCodec<>("EntryBox", Box.CODEC), @@ -33,7 +34,9 @@ public class ObjectiveLocationAreaBox extends ObjectiveLocationMarkerArea { .add() .afterDecode(ObjectiveLocationAreaBox::computeAreaBoxes) .build(); + @Nonnull private static final Box DEFAULT_ENTRY_BOX = new Box(-5.0, -5.0, -5.0, 5.0, 5.0, 5.0); + @Nonnull private static final Box DEFAULT_EXIT_BOX = new Box(-10.0, -10.0, -10.0, 10.0, 10.0, 10.0); private Box entryArea; private Box exitArea; @@ -115,7 +118,7 @@ public class ObjectiveLocationAreaBox extends ObjectiveLocationMarkerArea { private static void getPlayersInArea( @Nonnull SpatialResource, EntityStore> spatialComponent, - List> results, + @Nonnull List> results, @Nonnull Vector3d markerPosition, @Nonnull Box box ) { diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/markerarea/ObjectiveLocationAreaRadius.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/markerarea/ObjectiveLocationAreaRadius.java index 2303af75..33c53497 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/markerarea/ObjectiveLocationAreaRadius.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/markerarea/ObjectiveLocationAreaRadius.java @@ -18,6 +18,7 @@ import java.util.List; import javax.annotation.Nonnull; public class ObjectiveLocationAreaRadius extends ObjectiveLocationMarkerArea { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ObjectiveLocationAreaRadius.class, ObjectiveLocationAreaRadius::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/objectivesetup/SetupObjective.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/objectivesetup/SetupObjective.java index 218cedc0..38dd8716 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/objectivesetup/SetupObjective.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/objectivesetup/SetupObjective.java @@ -15,6 +15,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SetupObjective extends ObjectiveTypeSetup { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(SetupObjective.class, SetupObjective::new) .append( new KeyedCodec<>("ObjectiveId", Codec.STRING), (setupObjective, s) -> setupObjective.objectiveId = s, setupObjective -> setupObjective.objectiveId diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/objectivesetup/SetupObjectiveLine.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/objectivesetup/SetupObjectiveLine.java index c1892a8f..67969235 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/objectivesetup/SetupObjectiveLine.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/objectivesetup/SetupObjectiveLine.java @@ -15,6 +15,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SetupObjectiveLine extends ObjectiveTypeSetup { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(SetupObjectiveLine.class, SetupObjectiveLine::new) .append( new KeyedCodec<>("ObjectiveLineId", Codec.STRING), diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/BlockTagOrItemIdField.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/BlockTagOrItemIdField.java index 7bb61a17..a90e9bb6 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/BlockTagOrItemIdField.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/BlockTagOrItemIdField.java @@ -11,6 +11,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockTagOrItemIdField { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(BlockTagOrItemIdField.class, BlockTagOrItemIdField::new) .append( new KeyedCodec<>("BlockTag", Codec.STRING), diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/CountObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/CountObjectiveTaskAsset.java index 7aea1d57..4b66db38 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/CountObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/CountObjectiveTaskAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public abstract class CountObjectiveTaskAsset extends ObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.abstractBuilder(CountObjectiveTaskAsset.class, BASE_CODEC) .append(new KeyedCodec<>("Count", Codec.INTEGER), (taskAsset, count) -> taskAsset.count = count, taskAsset -> taskAsset.count) .addValidator(Validators.greaterThan(0)) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/CraftObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/CraftObjectiveTaskAsset.java index 69e4ffe7..cabe34d8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/CraftObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/CraftObjectiveTaskAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.server.core.asset.type.item.config.Item; import javax.annotation.Nonnull; public class CraftObjectiveTaskAsset extends CountObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CraftObjectiveTaskAsset.class, CraftObjectiveTaskAsset::new, CountObjectiveTaskAsset.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/GatherObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/GatherObjectiveTaskAsset.java index 9080ba76..43316a73 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/GatherObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/GatherObjectiveTaskAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class GatherObjectiveTaskAsset extends CountObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( GatherObjectiveTaskAsset.class, GatherObjectiveTaskAsset::new, CountObjectiveTaskAsset.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/ObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/ObjectiveTaskAsset.java index fae15f23..d553de67 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/ObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/ObjectiveTaskAsset.java @@ -10,9 +10,12 @@ import com.hypixel.hytale.math.vector.Vector3i; import java.text.MessageFormat; import java.util.Arrays; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public abstract class ObjectiveTaskAsset { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(ObjectiveTaskAsset.class) .append( new KeyedCodec<>("DescriptionId", Codec.STRING), @@ -27,12 +30,13 @@ public abstract class ObjectiveTaskAsset { ) .add() .append( - new KeyedCodec<>("MapMarkers", new ArrayCodec<>(Vector3i.CODEC, Vector3i[]::new)), - (taskAsset, vector3is) -> taskAsset.mapMarkers = vector3is, + new KeyedCodec<>("MapMarkerPositions", new ArrayCodec<>(Vector3i.CODEC, Vector3i[]::new)), + (taskAsset, positions) -> taskAsset.mapMarkers = positions, taskAsset -> taskAsset.mapMarkers ) .add() .build(); + @Nonnull public static final String TASK_DESCRIPTION_KEY = "server.objectives.{0}.taskSet.{1}.task.{2}"; protected String descriptionId; protected TaskConditionAsset[] taskConditions; @@ -42,7 +46,6 @@ public abstract class ObjectiveTaskAsset { public ObjectiveTaskAsset(String descriptionId, TaskConditionAsset[] taskConditions, Vector3i[] mapMarkers) { this.descriptionId = descriptionId; this.taskConditions = taskConditions; - this.mapMarkers = mapMarkers; } protected ObjectiveTaskAsset() { @@ -69,6 +72,7 @@ public abstract class ObjectiveTaskAsset { return this.taskConditions; } + @Nullable public Vector3i[] getMapMarkers() { return this.mapMarkers; } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/ReachLocationTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/ReachLocationTaskAsset.java index 439963f4..98052113 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/ReachLocationTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/ReachLocationTaskAsset.java @@ -9,6 +9,7 @@ import java.util.Objects; import javax.annotation.Nonnull; public class ReachLocationTaskAsset extends ObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ReachLocationTaskAsset.class, ReachLocationTaskAsset::new, BASE_CODEC) .append( new KeyedCodec<>("TargetLocation", Codec.STRING), diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/TaskSet.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/TaskSet.java index 566227da..1a2e57b9 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/TaskSet.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/TaskSet.java @@ -10,6 +10,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; public class TaskSet { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(TaskSet.class, TaskSet::new) .append(new KeyedCodec<>("DescriptionId", Codec.STRING), (taskSet, s) -> taskSet.descriptionId = s, taskSet -> taskSet.descriptionId) .add() @@ -21,6 +22,7 @@ public class TaskSet { .addValidator(Validators.nonEmptyArray()) .add() .build(); + @Nonnull public static final String TASKSET_DESCRIPTION_KEY = "server.objectives.{0}.taskSet.{1}"; protected String descriptionId; protected ObjectiveTaskAsset[] tasks; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/TreasureMapObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/TreasureMapObjectiveTaskAsset.java index 3d121ac7..285a4f64 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/TreasureMapObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/TreasureMapObjectiveTaskAsset.java @@ -16,6 +16,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class TreasureMapObjectiveTaskAsset extends ObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TreasureMapObjectiveTaskAsset.class, TreasureMapObjectiveTaskAsset::new, BASE_CODEC ) @@ -63,6 +64,7 @@ public class TreasureMapObjectiveTaskAsset extends ObjectiveTaskAsset { } public static class ChestConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TreasureMapObjectiveTaskAsset.ChestConfig.class, TreasureMapObjectiveTaskAsset.ChestConfig::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/UseBlockObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/UseBlockObjectiveTaskAsset.java index e14ff7c3..25670e5d 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/UseBlockObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/UseBlockObjectiveTaskAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class UseBlockObjectiveTaskAsset extends CountObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UseBlockObjectiveTaskAsset.class, UseBlockObjectiveTaskAsset::new, CountObjectiveTaskAsset.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/UseEntityObjectiveTaskAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/UseEntityObjectiveTaskAsset.java index 9e94529b..3beb9bcc 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/UseEntityObjectiveTaskAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/task/UseEntityObjectiveTaskAsset.java @@ -11,6 +11,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class UseEntityObjectiveTaskAsset extends CountObjectiveTaskAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UseEntityObjectiveTaskAsset.class, UseEntityObjectiveTaskAsset::new, CountObjectiveTaskAsset.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/taskcondition/SoloInventoryCondition.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/taskcondition/SoloInventoryCondition.java index 08e8004a..13085880 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/taskcondition/SoloInventoryCondition.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/taskcondition/SoloInventoryCondition.java @@ -17,6 +17,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SoloInventoryCondition extends TaskConditionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(SoloInventoryCondition.class, SoloInventoryCondition::new) .append( new KeyedCodec<>("BlockTagOrItemId", BlockTagOrItemIdField.CODEC), @@ -75,7 +76,11 @@ public class SoloInventoryCondition extends TaskConditionAsset { Inventory inventory = playerComponent.getInventory(); if (this.holdInHand) { ItemStack itemInHand = inventory.getItemInHand(); - return !this.blockTypeOrTagTask.isBlockTypeIncluded(itemInHand.getItemId()) ? false : inventory.getItemInHand().getQuantity() >= this.quantity; + if (itemInHand == null) { + return false; + } else { + return !this.blockTypeOrTagTask.isBlockTypeIncluded(itemInHand.getItemId()) ? false : inventory.getItemInHand().getQuantity() >= this.quantity; + } } else { return inventory.getCombinedHotbarFirst().countItemStacks(itemStack -> this.blockTypeOrTagTask.isBlockTypeIncluded(itemStack.getItemId())) >= this.quantity; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/taskcondition/TaskConditionAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/taskcondition/TaskConditionAsset.java index 559e2cac..09909c1b 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/taskcondition/TaskConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/taskcondition/TaskConditionAsset.java @@ -6,8 +6,10 @@ import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.util.Set; import java.util.UUID; +import javax.annotation.Nonnull; public abstract class TaskConditionAsset { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); protected TaskConditionAsset() { diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/triggercondition/HourRangeTriggerCondition.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/triggercondition/HourRangeTriggerCondition.java index 4ee8872a..d32b15c7 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/triggercondition/HourRangeTriggerCondition.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/triggercondition/HourRangeTriggerCondition.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class HourRangeTriggerCondition extends ObjectiveLocationTriggerCondition { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(HourRangeTriggerCondition.class, HourRangeTriggerCondition::new) .append( new KeyedCodec<>("MinHour", Codec.INTEGER), @@ -26,6 +27,7 @@ public class HourRangeTriggerCondition extends ObjectiveLocationTriggerCondition ) .add() .build(); + @Nonnull protected static final ResourceType WORLD_TIME_RESOURCE_RESOURCE_TYPE = WorldTimeResource.getResourceType(); protected int minHour; protected int maxHour; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/triggercondition/ObjectiveLocationTriggerCondition.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/triggercondition/ObjectiveLocationTriggerCondition.java index 1d18a358..552f1a29 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/triggercondition/ObjectiveLocationTriggerCondition.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/triggercondition/ObjectiveLocationTriggerCondition.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public abstract class ObjectiveLocationTriggerCondition { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/CheckTagWorldHeightRadiusProvider.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/CheckTagWorldHeightRadiusProvider.java index 0bf3db58..30aaf29b 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/CheckTagWorldHeightRadiusProvider.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/CheckTagWorldHeightRadiusProvider.java @@ -17,6 +17,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CheckTagWorldHeightRadiusProvider extends WorldLocationProvider { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CheckTagWorldHeightRadiusProvider.class, CheckTagWorldHeightRadiusProvider::new, BASE_CODEC ) @@ -73,13 +74,16 @@ public class CheckTagWorldHeightRadiusProvider extends WorldLocationProvider { long pos = iterator.next(); int blockX = MathUtil.unpackLeft(pos); int blockZ = MathUtil.unpackRight(pos); - WorldChunk chunk = world.getNonTickingChunk(ChunkUtil.indexChunkFromBlock(blockX, blockZ)); - int blockY = chunk.getHeight(blockX, blockZ); - int blockId = chunk.getBlock(blockX, blockY, blockZ); + long chunkIndex = ChunkUtil.indexChunkFromBlock(blockX, blockZ); + WorldChunk worldChunkComponent = world.getNonTickingChunk(chunkIndex); + if (worldChunkComponent != null) { + int blockY = worldChunkComponent.getHeight(blockX, blockZ); + int blockId = worldChunkComponent.getBlock(blockX, blockY, blockZ); - for (int i = 0; i < this.blockTagsIndexes.length; i++) { - if (BlockType.getAssetMap().getIndexesForTag(this.blockTagsIndexes[i]).contains(blockId)) { - return new Vector3i(blockX, blockY + 1, blockZ); + for (int i = 0; i < this.blockTagsIndexes.length; i++) { + if (BlockType.getAssetMap().getIndexesForTag(this.blockTagsIndexes[i]).contains(blockId)) { + return new Vector3i(blockX, blockY + 1, blockZ); + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/LocationRadiusProvider.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/LocationRadiusProvider.java index 6c363871..7765f40c 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/LocationRadiusProvider.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/LocationRadiusProvider.java @@ -9,10 +9,12 @@ import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.math.util.TrigMathUtil; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.server.core.universe.world.World; +import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class LocationRadiusProvider extends WorldLocationProvider { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(LocationRadiusProvider.class, LocationRadiusProvider::new, BASE_CODEC) .append( new KeyedCodec<>("MinRadius", Codec.INTEGER), @@ -45,15 +47,21 @@ public class LocationRadiusProvider extends WorldLocationProvider { protected int minRadius = 10; protected int maxRadius = 50; - @Nonnull + @Nullable @Override public Vector3i runCondition(@Nonnull World world, @Nonnull Vector3i position) { double angle = Math.random() * (float) (Math.PI * 2); int radius = MathUtil.randomInt(this.minRadius, this.maxRadius); Vector3i newPosition = position.clone(); newPosition.add((int)(radius * TrigMathUtil.cos(angle)), 0, (int)(radius * TrigMathUtil.sin(angle))); - newPosition.y = world.getChunk(ChunkUtil.indexChunkFromBlock(newPosition.x, newPosition.z)).getHeight(newPosition.x, newPosition.z); - return newPosition; + long chunkIndex = ChunkUtil.indexChunkFromBlock(newPosition.x, newPosition.z); + WorldChunk worldChunkComponent = world.getChunk(chunkIndex); + if (worldChunkComponent == null) { + return null; + } else { + newPosition.y = worldChunkComponent.getHeight(newPosition.x, newPosition.z); + return newPosition; + } } @Override diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/LookBlocksBelowProvider.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/LookBlocksBelowProvider.java index 86dbe1ab..415b0412 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/LookBlocksBelowProvider.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/LookBlocksBelowProvider.java @@ -15,6 +15,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class LookBlocksBelowProvider extends WorldLocationProvider { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( LookBlocksBelowProvider.class, LookBlocksBelowProvider::new, BASE_CODEC ) @@ -96,37 +97,48 @@ public class LookBlocksBelowProvider extends WorldLocationProvider { @Override public Vector3i runCondition(@Nonnull World world, @Nonnull Vector3i position) { Vector3i newPosition = position.clone(); - WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(newPosition.x, newPosition.z)); - int baseY = newPosition.y; - int x = newPosition.x; - int y = newPosition.y; - int z = newPosition.z; - int currentCount = 0; + long chunkIndex = ChunkUtil.indexChunkFromBlock(newPosition.x, newPosition.z); + WorldChunk worldChunkComponent = world.getChunk(chunkIndex); + if (worldChunkComponent == null) { + return null; + } else { + int baseY = newPosition.y; + int x = newPosition.x; + int y = newPosition.y; + int z = newPosition.z; + int currentCount = 0; - while (y >= this.minRange && baseY - y <= this.maxRange) { - String blockStateKey = worldChunk.getBlockType(x, y, z).getId(); - boolean found = false; + while (y >= this.minRange && baseY - y <= this.maxRange) { + BlockType blockType = worldChunkComponent.getBlockType(x, y, z); + if (blockType == null) { + y--; + currentCount = 0; + } else { + String blockStateKey = blockType.getId(); + boolean found = false; - for (int i = 0; i < this.blockTagsIndexes.length; i++) { - int blockTagId = this.blockTagsIndexes[i]; - if (BlockType.getAssetMap().getKeysForTag(blockTagId).contains(blockStateKey)) { - found = true; - currentCount++; - break; + for (int i = 0; i < this.blockTagsIndexes.length; i++) { + int blockTagId = this.blockTagsIndexes[i]; + if (BlockType.getAssetMap().getKeysForTag(blockTagId).contains(blockStateKey)) { + found = true; + currentCount++; + break; + } + } + + if (currentCount == this.count) { + break; + } + + y--; + if (!found) { + currentCount = 0; + } } } - if (currentCount == this.count) { - break; - } - - y--; - if (!found) { - currentCount = 0; - } + return currentCount == this.count ? new Vector3i(x, y, z) : null; } - - return currentCount == this.count ? new Vector3i(x, y, z) : null; } @Override diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/WorldLocationProvider.java b/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/WorldLocationProvider.java index 997cff9d..05978739 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/WorldLocationProvider.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/config/worldlocationproviders/WorldLocationProvider.java @@ -8,11 +8,13 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class WorldLocationProvider { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(WorldLocationProvider.class).build(); @Nullable - public abstract Vector3i runCondition(World var1, Vector3i var2); + public abstract Vector3i runCondition(@Nonnull World var1, @Nonnull Vector3i var2); @Override public abstract boolean equals(Object var1); diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/CommonObjectiveHistoryData.java b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/CommonObjectiveHistoryData.java index 82aacd0b..de361cda 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/CommonObjectiveHistoryData.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/CommonObjectiveHistoryData.java @@ -8,7 +8,9 @@ import java.time.Instant; import javax.annotation.Nonnull; public abstract class CommonObjectiveHistoryData { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(CommonObjectiveHistoryData.class) .append( new KeyedCodec<>("Id", Codec.STRING), diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ItemObjectiveRewardHistoryData.java b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ItemObjectiveRewardHistoryData.java index 1aca9d14..1c9ecdf1 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ItemObjectiveRewardHistoryData.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ItemObjectiveRewardHistoryData.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.server.core.asset.type.item.config.Item; import javax.annotation.Nonnull; public final class ItemObjectiveRewardHistoryData extends ObjectiveRewardHistoryData { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ItemObjectiveRewardHistoryData.class, ItemObjectiveRewardHistoryData::new, BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveHistoryData.java b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveHistoryData.java index f59fb7da..83a210d7 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveHistoryData.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveHistoryData.java @@ -12,6 +12,7 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public final class ObjectiveHistoryData extends CommonObjectiveHistoryData { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ObjectiveHistoryData.class, ObjectiveHistoryData::new, BASE_CODEC) .append( new KeyedCodec<>("Rewards", new ArrayCodec<>(ObjectiveRewardHistoryData.CODEC, ObjectiveRewardHistoryData[]::new)), diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveLineHistoryData.java b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveLineHistoryData.java index fb01a326..d35c8095 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveLineHistoryData.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveLineHistoryData.java @@ -12,6 +12,7 @@ import java.util.UUID; import javax.annotation.Nonnull; public final class ObjectiveLineHistoryData extends CommonObjectiveHistoryData { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ObjectiveLineHistoryData.class, ObjectiveLineHistoryData::new, BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveRewardHistoryData.java b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveRewardHistoryData.java index 438727e7..f12f4cd8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveRewardHistoryData.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/historydata/ObjectiveRewardHistoryData.java @@ -2,8 +2,11 @@ package com.hypixel.hytale.builtin.adventure.objectives.historydata; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.lookup.CodecMapCodec; +import javax.annotation.Nonnull; public abstract class ObjectiveRewardHistoryData { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(ObjectiveRewardHistoryData.class).build(); } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/interactions/CanBreakRespawnPointInteraction.java b/src/com/hypixel/hytale/builtin/adventure/objectives/interactions/CanBreakRespawnPointInteraction.java index 1f5f1357..0a942101 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/interactions/CanBreakRespawnPointInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/interactions/CanBreakRespawnPointInteraction.java @@ -23,6 +23,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CanBreakRespawnPointInteraction extends SimpleBlockInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CanBreakRespawnPointInteraction.class, CanBreakRespawnPointInteraction::new, SimpleBlockInteraction.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/interactions/StartObjectiveInteraction.java b/src/com/hypixel/hytale/builtin/adventure/objectives/interactions/StartObjectiveInteraction.java index a1b1e6e2..9c917879 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/interactions/StartObjectiveInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/interactions/StartObjectiveInteraction.java @@ -25,6 +25,7 @@ import javax.annotation.Nonnull; import org.bson.BsonDocument; public class StartObjectiveInteraction extends SimpleInstantInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( StartObjectiveInteraction.class, StartObjectiveInteraction::new, SimpleInstantInteraction.CODEC ) @@ -38,6 +39,7 @@ public class StartObjectiveInteraction extends SimpleInstantInteraction { .addValidator(Validators.nonNull()) .add() .build(); + @Nonnull public static final KeyedCodec OBJECTIVE_UUID = new KeyedCodec<>("ObjectiveUUID", Codec.UUID_BINARY); protected ObjectiveTypeSetup objectiveTypeSetup; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/ObjectiveMarkerProvider.java b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/ObjectiveMarkerProvider.java index c368c50f..4a8a20e8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/ObjectiveMarkerProvider.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/ObjectiveMarkerProvider.java @@ -4,11 +4,10 @@ import com.hypixel.hytale.builtin.adventure.objectives.Objective; import com.hypixel.hytale.builtin.adventure.objectives.ObjectiveDataStore; import com.hypixel.hytale.builtin.adventure.objectives.ObjectivePlugin; import com.hypixel.hytale.builtin.adventure.objectives.task.ObjectiveTask; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import java.util.Set; import java.util.UUID; import javax.annotation.Nonnull; @@ -20,8 +19,7 @@ public class ObjectiveMarkerProvider implements WorldMapManager.MarkerProvider { } @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { - Player player = tracker.getPlayer(); + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { Set activeObjectiveUUIDs = player.getPlayerConfigData().getActiveObjectiveUUIDs(); if (!activeObjectiveUUIDs.isEmpty()) { UUID playerUUID = player.getUuid(); @@ -33,8 +31,8 @@ public class ObjectiveMarkerProvider implements WorldMapManager.MarkerProvider { ObjectiveTask[] tasks = objective.getCurrentTasks(); if (tasks != null) { for (ObjectiveTask task : tasks) { - for (MapMarker marker : task.getMarkers()) { - tracker.trySendMarker(chunkViewRadius, playerChunkX, playerChunkZ, marker); + for (ObjectiveTaskMarker marker : task.getMarkers()) { + collector.add(marker.toProto()); } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/ObjectiveTaskMarker.java b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/ObjectiveTaskMarker.java new file mode 100644 index 00000000..d614ba1c --- /dev/null +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/ObjectiveTaskMarker.java @@ -0,0 +1,58 @@ +package com.hypixel.hytale.builtin.adventure.objectives.markers; + +import com.hypixel.hytale.codec.Codec; +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.math.vector.Transform; +import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.util.PositionUtil; + +public class ObjectiveTaskMarker { + public static final BuilderCodec CODEC = BuilderCodec.builder(ObjectiveTaskMarker.class, ObjectiveTaskMarker::new) + .append(new KeyedCodec<>("Id", Codec.STRING), (marker, o) -> marker.id = o, marker -> marker.id) + .add() + .append(new KeyedCodec<>("Transform", Transform.CODEC), (marker, o) -> marker.transform = o, marker -> marker.transform) + .add() + .append(new KeyedCodec<>("Icon", Codec.STRING), (marker, o) -> marker.icon = o, marker -> marker.icon) + .add() + .append(new KeyedCodec<>("Name", Message.CODEC), (marker, o) -> marker.name = o, marker -> marker.name) + .add() + .build(); + public static final ArrayCodec ARRAY_CODEC = new ArrayCodec<>(CODEC, ObjectiveTaskMarker[]::new); + private String id; + private Transform transform; + private String icon; + private Message name; + + public ObjectiveTaskMarker() { + } + + public ObjectiveTaskMarker(String id, Transform transform, String icon, Message name) { + this.id = id; + this.transform = transform; + this.icon = icon; + this.name = name; + } + + public String getId() { + return this.id; + } + + public Transform getTransform() { + return this.transform; + } + + public String getIcon() { + return this.icon; + } + + public Message getName() { + return this.name; + } + + public MapMarker toProto() { + return new MapMarker(this.id, this.name.getFormattedMessage(), null, this.icon, PositionUtil.toTransformPacket(this.transform), null, null); + } +} diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/objectivelocation/ObjectiveLocationMarker.java b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/objectivelocation/ObjectiveLocationMarker.java index f040318a..6217db9f 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/objectivelocation/ObjectiveLocationMarker.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/objectivelocation/ObjectiveLocationMarker.java @@ -19,6 +19,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ObjectiveLocationMarker implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ObjectiveLocationMarker.class, ObjectiveLocationMarker::new) .append( new KeyedCodec<>("ObjectiveLocationMarkerId", Codec.STRING), @@ -68,7 +69,7 @@ public class ObjectiveLocationMarker implements Component { return this.activeObjective; } - public void setActiveObjective(Objective activeObjective) { + public void setActiveObjective(@Nonnull Objective activeObjective) { this.activeObjective = activeObjective; } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/objectivelocation/ObjectiveLocationMarkerSystems.java b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/objectivelocation/ObjectiveLocationMarkerSystems.java index 9bbd9feb..21871252 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/objectivelocation/ObjectiveLocationMarkerSystems.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/objectivelocation/ObjectiveLocationMarkerSystems.java @@ -286,25 +286,22 @@ public class ObjectiveLocationMarkerSystems { for (Ref playerReference : playerReferences) { PlayerRef playerRefComponent = commandBuffer.getComponent(playerReference, this.playerRefComponentType); - - assert playerRefComponent != null; - - UUIDComponent playerUuidComponent = commandBuffer.getComponent(playerReference, this.uuidComponentType); - - assert playerUuidComponent != null; - - TransformComponent playerTransformComponent = commandBuffer.getComponent(playerReference, this.transformComponentType); - - assert playerTransformComponent != null; - - WeatherTracker playerWeatherTrackerComponent = commandBuffer.getComponent(playerReference, this.weatherTrackerComponentType); - - assert playerWeatherTrackerComponent != null; - - if (isPlayerInSpecificEnvironment(objectiveLocationMarkerComponent, playerWeatherTrackerComponent, playerTransformComponent, commandBuffer)) { - playersInExitArea.add(playerUuidComponent.getUuid()); - if (objectiveLocationMarkerComponent.area.isPlayerInEntryArea(playerTransformComponent.getPosition(), position)) { - playersInEntryArea[playersInEntryAreaSize++] = playerRefComponent; + if (playerRefComponent != null) { + UUIDComponent playerUuidComponent = commandBuffer.getComponent(playerReference, this.uuidComponentType); + if (playerUuidComponent != null) { + TransformComponent playerTransformComponent = commandBuffer.getComponent(playerReference, this.transformComponentType); + if (playerTransformComponent != null) { + WeatherTracker playerWeatherTrackerComponent = commandBuffer.getComponent(playerReference, this.weatherTrackerComponentType); + if (playerWeatherTrackerComponent != null + && isPlayerInSpecificEnvironment( + objectiveLocationMarkerComponent, playerWeatherTrackerComponent, playerTransformComponent, commandBuffer + )) { + playersInExitArea.add(playerUuidComponent.getUuid()); + if (objectiveLocationMarkerComponent.area.isPlayerInEntryArea(playerTransformComponent.getPosition(), position)) { + playersInEntryArea[playersInEntryAreaSize++] = playerRefComponent; + } + } + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarker.java b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarker.java index 519542cd..89f0c2cf 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarker.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarker.java @@ -15,6 +15,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ReachLocationMarker implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ReachLocationMarker.class, ReachLocationMarker::new) .append( new KeyedCodec<>("MarkerId", Codec.STRING), @@ -25,6 +26,7 @@ public class ReachLocationMarker implements Component { .add() .build(); private String markerId; + @Nonnull private final Set players = new HashSet<>(); public static ComponentType getComponentType() { diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarkerAsset.java b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarkerAsset.java index 8f1fb157..dabeb4d9 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarkerAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarkerAsset.java @@ -14,6 +14,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class ReachLocationMarkerAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( ReachLocationMarkerAsset.class, ReachLocationMarkerAsset::new, @@ -39,6 +40,7 @@ public class ReachLocationMarkerAsset implements JsonAssetWithMap VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(ReachLocationMarkerAsset::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data data; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarkerSystems.java b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarkerSystems.java index c3c5f9c2..c6d8e1af 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarkerSystems.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/markers/reachlocation/ReachLocationMarkerSystems.java @@ -38,10 +38,13 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class ReachLocationMarkerSystems { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull private static final ThreadLocal> THREAD_LOCAL_TEMP_UUIDS = ThreadLocal.withInitial(HashSet::new); public static class EnsureNetworkSendable extends HolderSystem { + @Nonnull private final Query query = Query.and(ReachLocationMarker.getComponentType(), Query.not(NetworkId.getComponentType())); @Override @@ -62,6 +65,7 @@ public class ReachLocationMarkerSystems { public static class EntityAdded extends RefSystem { private final ComponentType reachLocationMarkerComponent; + @Nonnull private final ComponentType transformComponentType; @Nonnull private final Query query; @@ -110,8 +114,10 @@ public class ReachLocationMarkerSystems { public static class Ticking extends EntityTickingSystem { private final ComponentType reachLocationMarkerComponent; + @Nonnull private final ComponentType transformComponentType; private final ResourceType, EntityStore>> playerSpatialComponent; + @Nonnull private final ComponentType uuidComponentType = UUIDComponent.getComponentType(); @Nonnull private final Query query; @@ -184,16 +190,15 @@ public class ReachLocationMarkerSystems { for (int i = 0; i < results.size(); i++) { Ref otherEntityReference = results.get(i); UUIDComponent otherUuidComponent = commandBuffer.getComponent(otherEntityReference, this.uuidComponentType); - - assert otherUuidComponent != null; - - UUID otherUuid = otherUuidComponent.getUuid(); - players.add(otherUuid); - if (!previousPlayers.contains(otherUuid)) { - for (ObjectiveTaskRef taskRef : objectiveDataStore.getTaskRefsForType(ReachLocationTask.class)) { - Objective objective = objectiveDataStore.getObjective(taskRef.getObjectiveUUID()); - if (objective != null) { - taskRef.getObjectiveTask().onPlayerReachLocationMarker(store, otherEntityReference, markerId, objective); + if (otherUuidComponent != null) { + UUID otherUuid = otherUuidComponent.getUuid(); + players.add(otherUuid); + if (!previousPlayers.contains(otherUuid)) { + for (ObjectiveTaskRef taskRef : objectiveDataStore.getTaskRefsForType(ReachLocationTask.class)) { + Objective objective = objectiveDataStore.getObjective(taskRef.getObjectiveUUID()); + if (objective != null) { + taskRef.getObjectiveTask().onPlayerReachLocationMarker(store, otherEntityReference, markerId, objective); + } } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/systems/ObjectiveItemEntityRemovalSystem.java b/src/com/hypixel/hytale/builtin/adventure/objectives/systems/ObjectiveItemEntityRemovalSystem.java index 229390aa..b87fccb8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/systems/ObjectiveItemEntityRemovalSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/systems/ObjectiveItemEntityRemovalSystem.java @@ -16,6 +16,7 @@ import java.util.UUID; import javax.annotation.Nonnull; public class ObjectiveItemEntityRemovalSystem extends HolderSystem { + @Nonnull private static final ComponentType COMPONENT_TYPE = ItemComponent.getComponentType(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/task/CountObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/objectives/task/CountObjectiveTask.java index 68e0376c..32d3072b 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/task/CountObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/task/CountObjectiveTask.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public abstract class CountObjectiveTask extends ObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.abstractBuilder(CountObjectiveTask.class, ObjectiveTask.BASE_CODEC) .append(new KeyedCodec<>("Count", Codec.INTEGER), (countTask, integer) -> countTask.count = integer, countTask -> countTask.count) .add() @@ -31,12 +32,6 @@ public abstract class CountObjectiveTask extends ObjectiveTask { return (CountObjectiveTaskAsset)super.getAsset(); } - @Nonnull - @Override - public Message getInfoMessage(@Nonnull Objective objective) { - return super.getInfoMessage(objective).insert(" " + this.count + "/" + this.getAsset().getCount()); - } - @Override public boolean checkCompletion() { return this.count >= this.getAsset().getCount(); @@ -78,7 +73,8 @@ public abstract class CountObjectiveTask extends ObjectiveTask { @Nonnull public com.hypixel.hytale.protocol.ObjectiveTask toPacket(@Nonnull Objective objective) { com.hypixel.hytale.protocol.ObjectiveTask packet = new com.hypixel.hytale.protocol.ObjectiveTask(); - packet.taskDescriptionKey = this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex); + packet.taskDescriptionKey = Message.translation(this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex)) + .getFormattedMessage(); packet.currentCompletion = this.count; packet.completionNeeded = this.getAsset().getCount(); return packet; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/task/CraftObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/objectives/task/CraftObjectiveTask.java index 0e19ef5f..5b9d74a5 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/task/CraftObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/task/CraftObjectiveTask.java @@ -17,6 +17,7 @@ import java.util.Objects; import javax.annotation.Nonnull; public class CraftObjectiveTask extends CountObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CraftObjectiveTask.class, CraftObjectiveTask::new, CountObjectiveTask.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/task/GatherObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/objectives/task/GatherObjectiveTask.java index 5d73b806..caf79621 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/task/GatherObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/task/GatherObjectiveTask.java @@ -25,6 +25,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class GatherObjectiveTask extends CountObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( GatherObjectiveTask.class, GatherObjectiveTask::new, CountObjectiveTask.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/task/ObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/objectives/task/ObjectiveTask.java index 4e6b980a..ccb51bf9 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/task/ObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/task/ObjectiveTask.java @@ -4,6 +4,7 @@ import com.hypixel.hytale.builtin.adventure.objectives.Objective; import com.hypixel.hytale.builtin.adventure.objectives.ObjectivePlugin; import com.hypixel.hytale.builtin.adventure.objectives.config.task.ObjectiveTaskAsset; import com.hypixel.hytale.builtin.adventure.objectives.config.taskcondition.TaskConditionAsset; +import com.hypixel.hytale.builtin.adventure.objectives.markers.ObjectiveTaskMarker; import com.hypixel.hytale.builtin.adventure.objectives.transaction.TransactionRecord; import com.hypixel.hytale.builtin.adventure.objectives.transaction.TransactionUtil; import com.hypixel.hytale.builtin.adventure.objectives.transaction.WorldTransactionRecord; @@ -19,19 +20,14 @@ import com.hypixel.hytale.event.EventRegistry; import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.packets.assets.UpdateObjectiveTask; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.server.core.Message; -import com.hypixel.hytale.server.core.codec.ProtocolCodecs; -import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.io.NetworkSerializer; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.util.PositionUtil; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Set; import java.util.UUID; @@ -40,7 +36,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class ObjectiveTask implements NetworkSerializer { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(ObjectiveTask.class) .append( new KeyedCodec<>("Task", ObjectiveTaskAsset.CODEC), @@ -64,17 +62,18 @@ public abstract class ObjectiveTask implements NetworkSerializer("TaskIndex", Codec.INTEGER), (objectiveTask, integer) -> objectiveTask.taskIndex = integer, objectiveTask -> objectiveTask.taskIndex ) .add() - .append(new KeyedCodec<>("Markers", ProtocolCodecs.MARKER_ARRAY), (objectiveTask, markers) -> { - objectiveTask.markers.clear(); - Collections.addAll(objectiveTask.markers, markers); - }, objectiveTask -> objectiveTask.markers.toArray(MapMarker[]::new)) - .add() .append( new KeyedCodec<>("TaskSetIndex", Codec.INTEGER), (objectiveTask, integer) -> objectiveTask.taskSetIndex = integer, objectiveTask -> objectiveTask.taskSetIndex ) .add() + .append( + new KeyedCodec<>("Markers", ObjectiveTaskMarker.ARRAY_CODEC), + (objectiveTask, markers) -> objectiveTask.markers = new ObjectArrayList<>(Arrays.asList(markers)), + objectiveTask -> objectiveTask.markers.toArray(ObjectiveTaskMarker[]::new) + ) + .add() .build(); protected ObjectiveTaskAsset asset; protected boolean complete = false; @@ -86,7 +85,7 @@ public abstract class ObjectiveTask implements NetworkSerializer markers = new ObjectArrayList<>(); + protected List markers = new ObjectArrayList<>(); protected int taskSetIndex; protected ObjectiveTaskRef taskRef; @@ -123,22 +122,17 @@ public abstract class ObjectiveTask implements NetworkSerializer getMarkers() { + public List getMarkers() { return this.markers; } - public void addMarker(@Nonnull MapMarker marker) { + public void addMarker(@Nonnull ObjectiveTaskMarker marker) { this.markers.add(marker); } public void removeMarker(String id) { - for (MapMarker marker : this.markers) { - if (marker.id.equals(id)) { + for (ObjectiveTaskMarker marker : this.markers) { + if (marker.getId().equals(id)) { this.markers.remove(marker); return; } @@ -162,19 +156,12 @@ public abstract class ObjectiveTask implements NetworkSerializer(), () -> true, null, world.getEventRegistry()); Vector3i[] mapMarkerPositions = this.asset.getMapMarkers(); if (mapMarkerPositions != null) { - String objectiveUUIDString = objective.getObjectiveUUID().toString(); + String objectiveIdStr = objective.getObjectiveUUID().toString(); for (int i = 0; i < mapMarkerPositions.length; i++) { - Vector3i mapMarkerPosition = mapMarkerPositions[i]; - this.addMarker( - new MapMarker( - "ObjectiveMarker_" + objectiveUUIDString + "_" + i, - "Objective", - "Home.png", - PositionUtil.toTransformPacket(new Transform(mapMarkerPosition)), - null - ) - ); + Transform mapMarkerPosition = new Transform(mapMarkerPositions[i]); + String markerId = "ObjectiveMarker_" + objectiveIdStr + "_" + i; + this.addMarker(new ObjectiveTaskMarker(markerId, mapMarkerPosition, "Home.png", Message.translation("server.assetTypes.ObjectiveAsset.title"))); } } @@ -212,15 +199,6 @@ public abstract class ObjectiveTask implements NetworkSerializer componentAccessor) { if (!this.complete) { - if (componentAccessor != null) { - objective.forEachParticipant((participantReference, message) -> { - Player playerComponent = componentAccessor.getComponent(participantReference, Player.getComponentType()); - if (playerComponent != null) { - playerComponent.sendMessage(message); - } - }, Message.translation("server.modules.objective.task.completed").insert(this.getInfoMessage(objective))); - } - this.markers.clear(); this.complete = true; this.completeTransactionRecords(); diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/task/ReachLocationTask.java b/src/com/hypixel/hytale/builtin/adventure/objectives/task/ReachLocationTask.java index 47048778..a61945e6 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/task/ReachLocationTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/task/ReachLocationTask.java @@ -3,6 +3,7 @@ package com.hypixel.hytale.builtin.adventure.objectives.task; import com.hypixel.hytale.builtin.adventure.objectives.Objective; import com.hypixel.hytale.builtin.adventure.objectives.config.task.ObjectiveTaskAsset; import com.hypixel.hytale.builtin.adventure.objectives.config.task.ReachLocationTaskAsset; +import com.hypixel.hytale.builtin.adventure.objectives.markers.ObjectiveTaskMarker; import com.hypixel.hytale.builtin.adventure.objectives.markers.reachlocation.ReachLocationMarker; import com.hypixel.hytale.builtin.adventure.objectives.transaction.TransactionRecord; import com.hypixel.hytale.codec.Codec; @@ -14,18 +15,18 @@ import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.math.vector.Vector3d; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.util.PositionUtil; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ReachLocationTask extends ObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ReachLocationTask.class, ReachLocationTask::new, BASE_CODEC) .append( new KeyedCodec<>("Completed", Codec.BOOLEAN), @@ -42,7 +43,9 @@ public class ReachLocationTask extends ObjectiveTask { .build(); @Nonnull public static String MARKER_ICON = "Home.png"; + @Nonnull private static final ComponentType TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType(); + @Nonnull private static final ComponentType REACH_LOCATION_MARKER_COMPONENT_TYPE = ReachLocationMarker.getComponentType(); private boolean completed; private boolean markerLoaded; @@ -121,11 +124,10 @@ public class ReachLocationTask extends ObjectiveTask { } if (closestLocationName != null) { - this.addMarker( - new MapMarker( - this.getMarkerId(objective), closestLocationName, MARKER_ICON, PositionUtil.toTransformPacket(new Transform(closestPosition)), null - ) + ObjectiveTaskMarker marker = new ObjectiveTaskMarker( + this.getMarkerId(objective), new Transform(closestPosition), MARKER_ICON, Message.raw(closestLocationName) ); + this.addMarker(marker); this.markerLoaded = true; return null; } @@ -146,9 +148,10 @@ public class ReachLocationTask extends ObjectiveTask { if (markerId.equals(this.getAsset().getTargetLocationId())) { String locationName = locationMarkerEntity.getLocationName(); if (locationName != null) { - this.addMarker( - new MapMarker(this.getMarkerId(objective), locationName, MARKER_ICON, PositionUtil.toTransformPacket(new Transform(position)), null) + ObjectiveTaskMarker marker = new ObjectiveTaskMarker( + this.getMarkerId(objective), new Transform(position), MARKER_ICON, Message.raw(locationName) ); + this.addMarker(marker); this.markerLoaded = true; } } @@ -158,7 +161,8 @@ public class ReachLocationTask extends ObjectiveTask { @Nonnull public com.hypixel.hytale.protocol.ObjectiveTask toPacket(@Nonnull Objective objective) { com.hypixel.hytale.protocol.ObjectiveTask packet = new com.hypixel.hytale.protocol.ObjectiveTask(); - packet.taskDescriptionKey = this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex); + packet.taskDescriptionKey = Message.translation(this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex)) + .getFormattedMessage(); packet.currentCompletion = this.completed ? 1 : 0; packet.completionNeeded = 1; return packet; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/task/TreasureMapObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/objectives/task/TreasureMapObjectiveTask.java index 4ca7ecbc..a11d640f 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/task/TreasureMapObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/task/TreasureMapObjectiveTask.java @@ -5,6 +5,7 @@ import com.hypixel.hytale.builtin.adventure.objectives.ObjectivePlugin; import com.hypixel.hytale.builtin.adventure.objectives.blockstates.TreasureChestState; import com.hypixel.hytale.builtin.adventure.objectives.config.task.TreasureMapObjectiveTaskAsset; import com.hypixel.hytale.builtin.adventure.objectives.events.TreasureChestOpeningEvent; +import com.hypixel.hytale.builtin.adventure.objectives.markers.ObjectiveTaskMarker; import com.hypixel.hytale.builtin.adventure.objectives.transaction.RegistrationTransactionRecord; import com.hypixel.hytale.builtin.adventure.objectives.transaction.SpawnTreasureChestTransactionRecord; import com.hypixel.hytale.builtin.adventure.objectives.transaction.TransactionRecord; @@ -21,7 +22,7 @@ import com.hypixel.hytale.math.util.TrigMathUtil; import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3i; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.modules.item.ItemModule; import com.hypixel.hytale.server.core.universe.world.World; @@ -30,7 +31,6 @@ import com.hypixel.hytale.server.core.universe.world.meta.BlockState; import com.hypixel.hytale.server.core.universe.world.meta.BlockStateModule; import com.hypixel.hytale.server.core.universe.world.meta.state.ItemContainerState; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.util.PositionUtil; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.Collections; import java.util.List; @@ -40,6 +40,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class TreasureMapObjectiveTask extends ObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TreasureMapObjectiveTask.class, TreasureMapObjectiveTask::new, BASE_CODEC ) @@ -64,6 +65,7 @@ public class TreasureMapObjectiveTask extends ObjectiveTask { public static final int CHEST_SPAWN_TRY = 500; private int currentCompletion; private int chestCount; + @Nonnull private final List chestUUIDs = new ObjectArrayList<>(); public TreasureMapObjectiveTask(@Nonnull TreasureMapObjectiveTaskAsset asset, int taskSetIndex, int taskIndex) { @@ -148,11 +150,10 @@ public class TreasureMapObjectiveTask extends ObjectiveTask { this.chestUUIDs.add(chestUUID); treasureChestState.getChunk().setState(conditionPosition.getX(), conditionPosition.getY(), conditionPosition.getZ(), treasureChestState); ObjectivePlugin.get().getLogger().at(Level.INFO).log("Spawned chest at: " + conditionPosition); - this.addMarker( - new MapMarker( - this.getChestMarkerIDFromUUID(chestUUID), "Chest", "Home.png", PositionUtil.toTransformPacket(new Transform(conditionPosition)), null - ) + ObjectiveTaskMarker marker = new ObjectiveTaskMarker( + this.getChestMarkerIDFromUUID(chestUUID), new Transform(conditionPosition), "Home.png", Message.translation("server.objectives.treasure.marker") ); + this.addMarker(marker); return transactionRecord; } } @@ -162,20 +163,25 @@ public class TreasureMapObjectiveTask extends ObjectiveTask { private TreasureChestState spawnChestBlock( @Nonnull World world, @Nonnull Vector3i conditionPosition, String chestBlockTypeKey, @Nonnull SpawnTreasureChestTransactionRecord transactionRecord ) { - WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(conditionPosition.x, conditionPosition.z)); - worldChunk.setBlock(conditionPosition.x, conditionPosition.y, conditionPosition.z, chestBlockTypeKey); - BlockState blockState = worldChunk.getState(conditionPosition.x, conditionPosition.y, conditionPosition.z); - if (!(blockState instanceof ItemContainerState)) { - transactionRecord.fail("BlockState is not a container"); + long chunkIndex = ChunkUtil.indexChunkFromBlock(conditionPosition.x, conditionPosition.z); + WorldChunk worldChunk = world.getChunk(chunkIndex); + if (worldChunk == null) { return null; } else { - TreasureChestState treasureChestState = BlockStateModule.get() - .createBlockState(TreasureChestState.class, worldChunk, conditionPosition.clone(), blockState.getBlockType()); - if (treasureChestState == null) { - transactionRecord.fail("Failed to create TreasureChestState!"); + worldChunk.setBlock(conditionPosition.x, conditionPosition.y, conditionPosition.z, chestBlockTypeKey); + BlockState blockState = worldChunk.getState(conditionPosition.x, conditionPosition.y, conditionPosition.z); + if (!(blockState instanceof ItemContainerState)) { + transactionRecord.fail("BlockState is not a container"); return null; } else { - return treasureChestState; + TreasureChestState treasureChestState = BlockStateModule.get() + .createBlockState(TreasureChestState.class, worldChunk, conditionPosition.clone(), blockState.getBlockType()); + if (treasureChestState == null) { + transactionRecord.fail("Failed to create TreasureChestState!"); + return null; + } else { + return treasureChestState; + } } } } @@ -206,7 +212,8 @@ public class TreasureMapObjectiveTask extends ObjectiveTask { @Nonnull public com.hypixel.hytale.protocol.ObjectiveTask toPacket(@Nonnull Objective objective) { com.hypixel.hytale.protocol.ObjectiveTask packet = new com.hypixel.hytale.protocol.ObjectiveTask(); - packet.taskDescriptionKey = this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex); + packet.taskDescriptionKey = Message.translation(this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex)) + .getFormattedMessage(); packet.currentCompletion = this.currentCompletion; packet.completionNeeded = this.chestCount; return packet; diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/task/UseBlockObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/objectives/task/UseBlockObjectiveTask.java index c4c338e1..1a23fc6c 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/task/UseBlockObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/task/UseBlockObjectiveTask.java @@ -16,6 +16,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class UseBlockObjectiveTask extends CountObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UseBlockObjectiveTask.class, UseBlockObjectiveTask::new, CountObjectiveTask.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/task/UseEntityObjectiveTask.java b/src/com/hypixel/hytale/builtin/adventure/objectives/task/UseEntityObjectiveTask.java index a46b494e..9b1ef935 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/task/UseEntityObjectiveTask.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/task/UseEntityObjectiveTask.java @@ -25,6 +25,7 @@ import java.util.UUID; import javax.annotation.Nonnull; public class UseEntityObjectiveTask extends CountObjectiveTask { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UseEntityObjectiveTask.class, UseEntityObjectiveTask::new, CountObjectiveTask.CODEC ) @@ -35,6 +36,10 @@ public class UseEntityObjectiveTask extends CountObjectiveTask { .add() .build(); @Nonnull + private static final Message MESSAGE_SERVER_MODULES_OBJECTIVE_TASK_ALREADY_INTERACTED_WITH_NPC = Message.translation( + "server.modules.objective.task.alreadyInteractedWithNPC" + ); + @Nonnull protected Set npcUUIDs = new HashSet<>(); public UseEntityObjectiveTask(@Nonnull UseEntityObjectiveTaskAsset asset, int taskSetIndex, int taskIndex) { @@ -67,7 +72,7 @@ public class UseEntityObjectiveTask extends CountObjectiveTask { @Nonnull Store store, @Nonnull Ref ref, int qty, @Nonnull Objective objective, @Nonnull PlayerRef playerRef, UUID npcUUID ) { if (!this.npcUUIDs.add(npcUUID)) { - playerRef.sendMessage(Message.translation("server.modules.objective.task.alreadyInteractedWithNPC")); + playerRef.sendMessage(MESSAGE_SERVER_MODULES_OBJECTIVE_TASK_ALREADY_INTERACTED_WITH_NPC); return false; } else { super.increaseTaskCompletion(store, ref, qty, objective); diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/SpawnEntityTransactionRecord.java b/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/SpawnEntityTransactionRecord.java index 81ab8b15..8a13d6a4 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/SpawnEntityTransactionRecord.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/SpawnEntityTransactionRecord.java @@ -10,6 +10,7 @@ import java.util.UUID; import javax.annotation.Nonnull; public class SpawnEntityTransactionRecord extends TransactionRecord { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SpawnEntityTransactionRecord.class, SpawnEntityTransactionRecord::new, BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/SpawnTreasureChestTransactionRecord.java b/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/SpawnTreasureChestTransactionRecord.java index 09f98a32..f6f68c65 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/SpawnTreasureChestTransactionRecord.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/SpawnTreasureChestTransactionRecord.java @@ -14,6 +14,7 @@ import java.util.UUID; import javax.annotation.Nonnull; public class SpawnTreasureChestTransactionRecord extends TransactionRecord { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SpawnTreasureChestTransactionRecord.class, SpawnTreasureChestTransactionRecord::new, BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/TransactionRecord.java b/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/TransactionRecord.java index 8228efb7..edde5caf 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/TransactionRecord.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/transaction/TransactionRecord.java @@ -9,7 +9,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class TransactionRecord { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(TransactionRecord.class) .append( new KeyedCodec<>("Status", new EnumCodec<>(TransactionStatus.class, EnumCodec.EnumStyle.LEGACY)), @@ -53,7 +55,7 @@ public abstract class TransactionRecord { @Nonnull public static TransactionRecord[] appendFailedTransaction( - TransactionRecord[] transactions, @Nonnull T transaction, String reason + @Nullable TransactionRecord[] transactions, @Nonnull T transaction, String reason ) { return appendTransaction(transactions, transaction.fail(reason)); } diff --git a/src/com/hypixel/hytale/builtin/adventure/objectiveshop/CanStartObjectiveRequirement.java b/src/com/hypixel/hytale/builtin/adventure/objectiveshop/CanStartObjectiveRequirement.java index dc96f79a..26f037f8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectiveshop/CanStartObjectiveRequirement.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectiveshop/CanStartObjectiveRequirement.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class CanStartObjectiveRequirement extends ChoiceRequirement { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CanStartObjectiveRequirement.class, CanStartObjectiveRequirement::new, ChoiceRequirement.BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/adventure/objectiveshop/StartObjectiveInteraction.java b/src/com/hypixel/hytale/builtin/adventure/objectiveshop/StartObjectiveInteraction.java index 4cc896af..3d216cf2 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectiveshop/StartObjectiveInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectiveshop/StartObjectiveInteraction.java @@ -16,6 +16,7 @@ import java.util.UUID; import javax.annotation.Nonnull; public class StartObjectiveInteraction extends ChoiceInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( StartObjectiveInteraction.class, StartObjectiveInteraction::new, ChoiceInteraction.BASE_CODEC ) @@ -29,7 +30,7 @@ public class StartObjectiveInteraction extends ChoiceInteraction { .build(); protected String objectiveId; - public StartObjectiveInteraction(String objectiveId) { + public StartObjectiveInteraction(@Nonnull String objectiveId) { this.objectiveId = objectiveId; } diff --git a/src/com/hypixel/hytale/builtin/adventure/reputation/ReputationGameplayConfig.java b/src/com/hypixel/hytale/builtin/adventure/reputation/ReputationGameplayConfig.java index 841c3146..48560956 100644 --- a/src/com/hypixel/hytale/builtin/adventure/reputation/ReputationGameplayConfig.java +++ b/src/com/hypixel/hytale/builtin/adventure/reputation/ReputationGameplayConfig.java @@ -9,6 +9,7 @@ import javax.annotation.Nullable; public class ReputationGameplayConfig { public static final String ID = "Reputation"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ReputationGameplayConfig.class, ReputationGameplayConfig::new) .appendInherited( new KeyedCodec<>("ReputationStorage", new EnumCodec<>(ReputationGameplayConfig.ReputationStorageType.class)), @@ -18,6 +19,7 @@ public class ReputationGameplayConfig { ) .add() .build(); + @Nonnull private static final ReputationGameplayConfig DEFAULT_REPUTATION_GAMEPLAY_CONFIG = new ReputationGameplayConfig(); @Nonnull protected ReputationGameplayConfig.ReputationStorageType reputationStorageType = ReputationGameplayConfig.ReputationStorageType.PerPlayer; @@ -27,6 +29,7 @@ public class ReputationGameplayConfig { return config.getPluginConfig().get(ReputationGameplayConfig.class); } + @Nonnull public static ReputationGameplayConfig getOrDefault(@Nonnull GameplayConfig config) { ReputationGameplayConfig reputationGameplayConfig = get(config); return reputationGameplayConfig != null ? reputationGameplayConfig : DEFAULT_REPUTATION_GAMEPLAY_CONFIG; diff --git a/src/com/hypixel/hytale/builtin/adventure/reputation/ReputationPlugin.java b/src/com/hypixel/hytale/builtin/adventure/reputation/ReputationPlugin.java index dc1402a0..d2e9a9d4 100644 --- a/src/com/hypixel/hytale/builtin/adventure/reputation/ReputationPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/reputation/ReputationPlugin.java @@ -175,17 +175,21 @@ public class ReputationPlugin extends JavaPlugin { public int getReputationValue(@Nonnull Store store, @Nonnull Ref playerEntityRef, @Nonnull String reputationGroupId) { World world = store.getExternalData().getWorld(); Player playerComponent = store.getComponent(playerEntityRef, Player.getComponentType()); - ReputationGameplayConfig reputationGameplayConfig = ReputationGameplayConfig.getOrDefault(world.getGameplayConfig()); - if (reputationGameplayConfig.getReputationStorageType() == ReputationGameplayConfig.ReputationStorageType.PerPlayer) { - ReputationGroup reputationGroup = ReputationGroup.getAssetMap().getAsset(reputationGroupId); - if (reputationGroup != null) { - Object2IntMap reputationData = playerComponent.getPlayerConfigData().getReputationData(); - return this.getReputationValueForGroup(reputationData, reputationGroup); - } else { - return Integer.MIN_VALUE; - } + if (playerComponent == null) { + return Integer.MIN_VALUE; } else { - return this.getReputationValue(store, reputationGroupId); + ReputationGameplayConfig reputationGameplayConfig = ReputationGameplayConfig.getOrDefault(world.getGameplayConfig()); + if (reputationGameplayConfig.getReputationStorageType() == ReputationGameplayConfig.ReputationStorageType.PerPlayer) { + ReputationGroup reputationGroup = ReputationGroup.getAssetMap().getAsset(reputationGroupId); + if (reputationGroup != null) { + Object2IntMap reputationData = playerComponent.getPlayerConfigData().getReputationData(); + return this.getReputationValueForGroup(reputationData, reputationGroup); + } else { + return Integer.MIN_VALUE; + } + } else { + return this.getReputationValue(store, reputationGroupId); + } } } @@ -194,7 +198,7 @@ public class ReputationPlugin extends JavaPlugin { return this.getReputationValue(store, reputationGroupId); } - public int getReputationValue(@Nonnull Store store, String reputationGroupId) { + public int getReputationValue(@Nonnull Store store, @Nonnull String reputationGroupId) { World world = store.getExternalData().getWorld(); ReputationGameplayConfig reputationGameplayConfig = ReputationGameplayConfig.getOrDefault(world.getGameplayConfig()); if (reputationGameplayConfig.getReputationStorageType() != ReputationGameplayConfig.ReputationStorageType.PerWorld) { @@ -204,7 +208,8 @@ public class ReputationPlugin extends JavaPlugin { if (reputationGroup == null) { return Integer.MIN_VALUE; } else { - Object2IntMap reputationData = world.getEntityStore().getStore().getResource(this.reputationDataResourceType).getReputationStats(); + ReputationDataResource reputationDataResource = world.getEntityStore().getStore().getResource(this.reputationDataResourceType); + Object2IntMap reputationData = reputationDataResource.getReputationStats(); return this.getReputationValueForGroup(reputationData, reputationGroup); } } diff --git a/src/com/hypixel/hytale/builtin/adventure/reputation/assets/ReputationGroup.java b/src/com/hypixel/hytale/builtin/adventure/reputation/assets/ReputationGroup.java index 90b8fab9..c18bcb15 100644 --- a/src/com/hypixel/hytale/builtin/adventure/reputation/assets/ReputationGroup.java +++ b/src/com/hypixel/hytale/builtin/adventure/reputation/assets/ReputationGroup.java @@ -26,6 +26,7 @@ public class ReputationGroup implements JsonAssetWithMap reputationRank.initialReputationValue ) .build(); + @Nonnull public static final ValidatorCache VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(ReputationGroup::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data data; @@ -33,6 +34,7 @@ public class ReputationGroup implements JsonAssetWithMap> getAssetStore() { if (ASSET_STORE == null) { ASSET_STORE = AssetRegistry.getAssetStore(ReputationGroup.class); diff --git a/src/com/hypixel/hytale/builtin/adventure/reputation/assets/ReputationRank.java b/src/com/hypixel/hytale/builtin/adventure/reputation/assets/ReputationRank.java index c990e342..15a3b9c5 100644 --- a/src/com/hypixel/hytale/builtin/adventure/reputation/assets/ReputationRank.java +++ b/src/com/hypixel/hytale/builtin/adventure/reputation/assets/ReputationRank.java @@ -29,6 +29,7 @@ public class ReputationRank implements JsonAssetWithMap VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(ReputationRank::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data data; @@ -37,6 +38,7 @@ public class ReputationRank implements JsonAssetWithMap> getAssetStore() { if (ASSET_STORE == null) { ASSET_STORE = AssetRegistry.getAssetStore(ReputationRank.class); diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/GiveItemInteraction.java b/src/com/hypixel/hytale/builtin/adventure/shop/GiveItemInteraction.java index 7a7ac5b2..eb6433aa 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/GiveItemInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/GiveItemInteraction.java @@ -15,6 +15,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class GiveItemInteraction extends ChoiceInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( GiveItemInteraction.class, GiveItemInteraction::new, ChoiceInteraction.BASE_CODEC ) @@ -56,7 +57,9 @@ public class GiveItemInteraction extends ChoiceInteraction { @Override public void run(@Nonnull Store store, @Nonnull Ref ref, @Nonnull PlayerRef playerRef) { Player playerComponent = store.getComponent(ref, Player.getComponentType()); - playerComponent.getInventory().getCombinedHotbarFirst().addItemStack(new ItemStack(this.itemId, this.quantity)); + if (playerComponent != null) { + playerComponent.getInventory().getCombinedHotbarFirst().addItemStack(new ItemStack(this.itemId, this.quantity)); + } } @Nonnull diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/ShopAsset.java b/src/com/hypixel/hytale/builtin/adventure/shop/ShopAsset.java index 5e9bdfaa..88e827ab 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/ShopAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/ShopAsset.java @@ -16,6 +16,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; public class ShopAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( ShopAsset.class, ShopAsset::new, @@ -31,12 +32,14 @@ public class ShopAsset implements JsonAssetWithMap shopAsset.elements ) .build(); + @Nonnull public static final ValidatorCache VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(ShopAsset::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data extraData; protected String id; protected ChoiceElement[] elements; + @Nonnull public static AssetStore> getAssetStore() { if (ASSET_STORE == null) { ASSET_STORE = AssetRegistry.getAssetStore(ShopAsset.class); diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/ShopElement.java b/src/com/hypixel/hytale/builtin/adventure/shop/ShopElement.java index 654981c4..7804e6fc 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/ShopElement.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/ShopElement.java @@ -15,6 +15,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class ShopElement extends ChoiceElement { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ShopElement.class, ShopElement::new, ChoiceElement.BASE_CODEC) .append(new KeyedCodec<>("Cost", Codec.INTEGER), (shopElement, integer) -> shopElement.cost = integer, shopElement -> shopElement.cost) .addValidator(Validators.greaterThanOrEqual(0)) diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/ShopPageSupplier.java b/src/com/hypixel/hytale/builtin/adventure/shop/ShopPageSupplier.java index 4e7e0d82..ad76da23 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/ShopPageSupplier.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/ShopPageSupplier.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class ShopPageSupplier implements OpenCustomUIInteraction.CustomPageSupplier { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ShopPageSupplier.class, ShopPageSupplier::new) .appendInherited( new KeyedCodec<>("ShopId", Codec.STRING), (data, o) -> data.shopId = o, data -> data.shopId, (data, parent) -> data.shopId = parent.shopId @@ -24,7 +25,10 @@ public class ShopPageSupplier implements OpenCustomUIInteraction.CustomPageSuppl @Nonnull @Override public CustomUIPage tryCreate( - Ref ref, ComponentAccessor componentAccessor, @Nonnull PlayerRef playerRef, InteractionContext context + @Nonnull Ref ref, + @Nonnull ComponentAccessor componentAccessor, + @Nonnull PlayerRef playerRef, + @Nonnull InteractionContext context ) { return new ShopPage(playerRef, this.shopId); } diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/ShopPlugin.java b/src/com/hypixel/hytale/builtin/adventure/shop/ShopPlugin.java index 6a4da931..8e41ed5e 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/ShopPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/ShopPlugin.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.server.core.entity.entities.player.pages.choices.Choic import com.hypixel.hytale.server.core.modules.interaction.interaction.config.server.OpenCustomUIInteraction; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; +import com.hypixel.hytale.server.core.plugin.registry.AssetRegistry; import java.util.logging.Level; import javax.annotation.Nonnull; @@ -27,28 +28,27 @@ public class ShopPlugin extends JavaPlugin { @Override protected void setup() { instance = this; - this.getAssetRegistry() - .register( - ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( - ShopAsset.class, new DefaultAssetMap() - ) - .setPath("Shops")) - .setCodec(ShopAsset.CODEC)) - .setKeyFunction(ShopAsset::getId)) - .loadsAfter(Item.class)) - .build() - ); - this.getAssetRegistry() - .register( - ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( - BarterShopAsset.class, new DefaultAssetMap() - ) - .setPath("BarterShops")) - .setCodec(BarterShopAsset.CODEC)) - .setKeyFunction(BarterShopAsset::getId)) - .loadsAfter(Item.class)) - .build() - ); + AssetRegistry assetRegistry = this.getAssetRegistry(); + assetRegistry.register( + ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( + ShopAsset.class, new DefaultAssetMap() + ) + .setPath("Shops")) + .setCodec(ShopAsset.CODEC)) + .setKeyFunction(ShopAsset::getId)) + .loadsAfter(Item.class)) + .build() + ); + assetRegistry.register( + ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( + BarterShopAsset.class, new DefaultAssetMap() + ) + .setPath("BarterShops")) + .setCodec(BarterShopAsset.CODEC)) + .setKeyFunction(BarterShopAsset::getId)) + .loadsAfter(Item.class)) + .build() + ); this.getCodecRegistry(ChoiceElement.CODEC).register("ShopElement", ShopElement.class, ShopElement.CODEC); this.getCodecRegistry(ChoiceInteraction.CODEC).register("GiveItem", GiveItemInteraction.class, GiveItemInteraction.CODEC); this.getCodecRegistry(OpenCustomUIInteraction.PAGE_CODEC).register("Shop", ShopPageSupplier.class, ShopPageSupplier.CODEC); diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterItemStack.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterItemStack.java index 6a795d01..b9714c35 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterItemStack.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterItemStack.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class BarterItemStack { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(BarterItemStack.class, BarterItemStack::new) .append(new KeyedCodec<>("ItemId", Codec.STRING), (stack, s) -> stack.itemId = s, stack -> stack.itemId) .addValidator(Validators.nonNull()) diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterPage.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterPage.java index 411833e2..cfc02d2f 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterPage.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterPage.java @@ -25,9 +25,12 @@ import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.time.Duration; import java.time.Instant; +import java.time.LocalTime; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class BarterPage extends InteractiveCustomUIPage { + @Nullable private final BarterShopAsset shopAsset; public BarterPage(@Nonnull PlayerRef playerRef, @Nonnull String shopId) { @@ -35,7 +38,7 @@ public class BarterPage extends InteractiveCustomUIPage 0) { - int spacersNeeded = cardsPerRow - remainder; + int spacersNeeded = 3 - remainder; for (int s = 0; s < spacersNeeded; s++) { commandBuilder.append("#TradeGrid", "Pages/BarterGridSpacer.ui"); @@ -153,7 +159,7 @@ public class BarterPage extends InteractiveCustomUIPage 0) { WorldTimeResource timeResource = store.getResource(WorldTimeResource.getResourceType()); - Instant gameTime = timeResource != null ? timeResource.getGameTime() : Instant.now(); + Instant gameTime = timeResource.getGameTime(); BarterShopState barterState = BarterShopState.get(); BarterTrade[] trades = barterState.getResolvedTrades(this.shopAsset, gameTime); if (tradeIndex >= 0 && tradeIndex < trades.length) { @@ -214,7 +220,7 @@ public class BarterPage extends InteractiveCustomUIPage ref, @Nonnull Store store, int tradedIndex) { UICommandBuilder commandBuilder = new UICommandBuilder(); WorldTimeResource timeResource = store.getResource(WorldTimeResource.getResourceType()); - Instant gameTime = timeResource != null ? timeResource.getGameTime() : Instant.now(); + Instant gameTime = timeResource.getGameTime(); BarterShopState barterState = BarterShopState.get(); int[] stockArray = barterState.getStockArray(this.shopAsset, gameTime); BarterTrade[] trades = barterState.getResolvedTrades(this.shopAsset, gameTime); @@ -240,7 +246,9 @@ public class BarterPage extends InteractiveCustomUIPage itemId.equals(stack.getItemId())); } - private void removeItemsFromContainer(ItemContainer container, String itemId, int amount) { + private void removeItemsFromContainer(@Nonnull ItemContainer container, @Nonnull String itemId, int amount) { container.removeItemStack(new ItemStack(itemId, amount)); } @@ -282,7 +290,8 @@ public class BarterPage extends InteractiveCustomUIPage= 12 ? "PM" : "AM"; - int displayHour = hour % 12; - if (displayHour == 0) { - displayHour = 12; - } - - String timeString = String.format("%d:00 %s", displayHour, amPm); + LocalTime restockTime = LocalTime.of(this.shopAsset.getRestockHour(), 0); + String timeString = restockTime.toString(); if (daysUntilRefresh <= 0L) { return Message.translation("server.barter.customUI.barterPage.restocksToday").param("restockTime", timeString); } else { @@ -324,9 +327,13 @@ public class BarterPage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder( BarterPage.BarterEventData.class, BarterPage.BarterEventData::new ) diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterShopAsset.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterShopAsset.java index 855d305f..9c231ffa 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterShopAsset.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterShopAsset.java @@ -16,6 +16,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BarterShopAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( BarterShopAsset.class, BarterShopAsset::new, @@ -39,6 +40,7 @@ public class BarterShopAsset implements JsonAssetWithMap("RestockHour", Codec.INTEGER, true), (asset, hour) -> asset.restockHour = hour, asset -> asset.restockHour) .build(); + @Nonnull public static final ValidatorCache VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(BarterShopAsset::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data extraData; @@ -48,8 +50,10 @@ public class BarterShopAsset implements JsonAssetWithMap> getAssetStore() { if (ASSET_STORE == null) { ASSET_STORE = AssetRegistry.getAssetStore(BarterShopAsset.class); diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterShopState.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterShopState.java index e1b0b96f..511b3f63 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterShopState.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterShopState.java @@ -28,9 +28,12 @@ import javax.annotation.Nullable; import org.bson.BsonDocument; public class BarterShopState { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nullable private static BarterShopState instance; private static Path saveDirectory; + @Nonnull public static final BuilderCodec SHOP_INSTANCE_CODEC = BuilderCodec.builder( BarterShopState.ShopInstanceState.class, BarterShopState.ShopInstanceState::new ) @@ -41,6 +44,7 @@ public class BarterShopState { .append(new KeyedCodec<>("ResolveSeed", Codec.LONG, true), (state, seed) -> state.resolveSeed = seed, state -> state.resolveSeed) .add() .build(); + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(BarterShopState.class, BarterShopState::new) .append( new KeyedCodec<>("Shops", new MapCodec<>(SHOP_INSTANCE_CODEC, Object2ObjectOpenHashMap::new, false)), @@ -49,6 +53,7 @@ public class BarterShopState { ) .add() .build(); + @Nonnull private final Map shopStates = new ConcurrentHashMap<>(); public static void initialize(@Nonnull Path dataDirectory) { @@ -114,6 +119,7 @@ public class BarterShopState { instance = null; } + @Nonnull private static Instant calculateNextScheduledRestock(@Nonnull Instant gameTime, int intervalDays, int restockHour) { LocalDateTime dateTime = LocalDateTime.ofInstant(gameTime, ZoneOffset.UTC); long daysSinceEpoch = Duration.between(WorldTimeResource.ZERO_YEAR, gameTime).toDays(); @@ -128,7 +134,7 @@ public class BarterShopState { } @Nonnull - public BarterShopState.ShopInstanceState getOrCreateShopState(BarterShopAsset asset, @Nonnull Instant gameTime) { + public BarterShopState.ShopInstanceState getOrCreateShopState(@Nonnull BarterShopAsset asset, @Nonnull Instant gameTime) { return this.shopStates.computeIfAbsent(asset.getId(), id -> { BarterShopState.ShopInstanceState state = new BarterShopState.ShopInstanceState(); state.resetStockAndResolve(asset); @@ -141,7 +147,7 @@ public class BarterShopState { }); } - public void checkRefresh(BarterShopAsset asset, @Nonnull Instant gameTime) { + public void checkRefresh(@Nonnull BarterShopAsset asset, @Nonnull Instant gameTime) { RefreshInterval interval = asset.getRefreshInterval(); if (interval != null) { BarterShopState.ShopInstanceState state = this.getOrCreateShopState(asset, gameTime); @@ -159,7 +165,7 @@ public class BarterShopState { } } - public int[] getStockArray(BarterShopAsset asset, @Nonnull Instant gameTime) { + public int[] getStockArray(@Nonnull BarterShopAsset asset, @Nonnull Instant gameTime) { this.checkRefresh(asset, gameTime); BarterShopState.ShopInstanceState state = this.getOrCreateShopState(asset, gameTime); if (state.expandStockIfNeeded(asset)) { @@ -170,13 +176,13 @@ public class BarterShopState { } @Nonnull - public BarterTrade[] getResolvedTrades(BarterShopAsset asset, @Nonnull Instant gameTime) { + public BarterTrade[] getResolvedTrades(@Nonnull BarterShopAsset asset, @Nonnull Instant gameTime) { this.checkRefresh(asset, gameTime); BarterShopState.ShopInstanceState state = this.getOrCreateShopState(asset, gameTime); return state.getResolvedTrades(asset); } - public boolean executeTrade(BarterShopAsset asset, int tradeIndex, int quantity, @Nonnull Instant gameTime) { + public boolean executeTrade(@Nonnull BarterShopAsset asset, int tradeIndex, int quantity, @Nonnull Instant gameTime) { this.checkRefresh(asset, gameTime); BarterShopState.ShopInstanceState state = this.getOrCreateShopState(asset, gameTime); boolean success = state.decrementStock(tradeIndex, quantity); @@ -188,9 +194,16 @@ public class BarterShopState { } public static class ShopInstanceState { - private int[] currentStock = new int[0]; + @Nonnull + public static final BarterTrade[] BARTER_TRADES = new BarterTrade[0]; + @Nonnull + public static final int[] INTS = new int[0]; + private int[] currentStock = INTS; + @Nullable private Instant nextRefreshTime; + @Nullable private Long resolveSeed; + @Nullable private transient BarterTrade[] resolvedTrades; public ShopInstanceState() { @@ -210,7 +223,7 @@ public class BarterShopState { return this.nextRefreshTime; } - public void setNextRefreshTime(Instant time) { + public void setNextRefreshTime(@Nonnull Instant time) { this.nextRefreshTime = time; } @@ -226,7 +239,7 @@ public class BarterShopState { @Nonnull public BarterTrade[] getResolvedTrades(@Nonnull BarterShopAsset asset) { if (!asset.hasTradeSlots()) { - return asset.getTrades() != null ? asset.getTrades() : new BarterTrade[0]; + return asset.getTrades() != null ? asset.getTrades() : BARTER_TRADES; } else if (this.resolvedTrades != null) { return this.resolvedTrades; } else { @@ -250,9 +263,9 @@ public class BarterShopState { result.addAll(slot.resolve(random)); } - return result.toArray(new BarterTrade[0]); + return result.toArray(BARTER_TRADES); } else { - return new BarterTrade[0]; + return BARTER_TRADES; } } @@ -273,7 +286,7 @@ public class BarterShopState { } /** @deprecated */ - public void resetStock(BarterShopAsset asset) { + public void resetStock(@Nonnull BarterShopAsset asset) { BarterTrade[] trades = this.getResolvedTrades(asset); if (this.currentStock.length != trades.length) { this.currentStock = new int[trades.length]; @@ -284,7 +297,7 @@ public class BarterShopState { } } - public boolean expandStockIfNeeded(BarterShopAsset asset) { + public boolean expandStockIfNeeded(@Nonnull BarterShopAsset asset) { BarterTrade[] trades = this.getResolvedTrades(asset); if (this.currentStock.length >= trades.length) { return false; diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterTrade.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterTrade.java index 534e7f76..be7e8f75 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterTrade.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/BarterTrade.java @@ -9,6 +9,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; public class BarterTrade { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(BarterTrade.class, BarterTrade::new) .append(new KeyedCodec<>("Output", BarterItemStack.CODEC), (trade, stack) -> trade.output = stack, trade -> trade.output) .addValidator(Validators.nonNull()) diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/FixedTradeSlot.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/FixedTradeSlot.java index 0b3789a6..b6ef78cb 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/FixedTradeSlot.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/FixedTradeSlot.java @@ -9,6 +9,7 @@ import java.util.Random; import javax.annotation.Nonnull; public class FixedTradeSlot extends TradeSlot { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(FixedTradeSlot.class, FixedTradeSlot::new) .append(new KeyedCodec<>("Trade", BarterTrade.CODEC), (slot, trade) -> slot.trade = trade, slot -> slot.trade) .addValidator(Validators.nonNull()) diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/PoolTradeSlot.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/PoolTradeSlot.java index 96103bc2..3990fbca 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/PoolTradeSlot.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/PoolTradeSlot.java @@ -12,6 +12,7 @@ import java.util.Random; import javax.annotation.Nonnull; public class PoolTradeSlot extends TradeSlot { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PoolTradeSlot.class, PoolTradeSlot::new) .append(new KeyedCodec<>("SlotCount", Codec.INTEGER), (slot, count) -> slot.slotCount = count, slot -> slot.slotCount) .addValidator(Validators.greaterThanOrEqual(1)) @@ -54,7 +55,7 @@ public class PoolTradeSlot extends TradeSlot { int toSelect = Math.min(this.slotCount, available.size()); for (int i = 0; i < toSelect; i++) { - int selectedIndex = this.selectWeightedIndex(available, random); + int selectedIndex = selectWeightedIndex(available, random); if (selectedIndex >= 0) { WeightedTrade selected = available.remove(selectedIndex); result.add(selected.toBarterTrade(random)); @@ -70,7 +71,7 @@ public class PoolTradeSlot extends TradeSlot { return this.slotCount; } - private int selectWeightedIndex(@Nonnull List trades, @Nonnull Random random) { + private static int selectWeightedIndex(@Nonnull List trades, @Nonnull Random random) { if (trades.isEmpty()) { return -1; } else { diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/RefreshInterval.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/RefreshInterval.java index acd57de7..e5459342 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/RefreshInterval.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/RefreshInterval.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class RefreshInterval { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(RefreshInterval.class, RefreshInterval::new) .append(new KeyedCodec<>("Days", Codec.INTEGER), (interval, i) -> interval.days = i, interval -> interval.days) .addValidator(Validators.greaterThanOrEqual(1)) diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/TradeSlot.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/TradeSlot.java index 1d1fdd38..e89d9d7e 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/TradeSlot.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/TradeSlot.java @@ -6,7 +6,9 @@ import java.util.Random; import javax.annotation.Nonnull; public abstract class TradeSlot { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final TradeSlot[] EMPTY_ARRAY = new TradeSlot[0]; protected TradeSlot() { diff --git a/src/com/hypixel/hytale/builtin/adventure/shop/barter/WeightedTrade.java b/src/com/hypixel/hytale/builtin/adventure/shop/barter/WeightedTrade.java index de75ee33..7cf087ed 100644 --- a/src/com/hypixel/hytale/builtin/adventure/shop/barter/WeightedTrade.java +++ b/src/com/hypixel/hytale/builtin/adventure/shop/barter/WeightedTrade.java @@ -11,6 +11,7 @@ import java.util.Random; import javax.annotation.Nonnull; public class WeightedTrade implements IWeightedElement { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(WeightedTrade.class, WeightedTrade::new) .append(new KeyedCodec<>("Weight", Codec.DOUBLE), (wt, w) -> wt.weight = w, wt -> wt.weight) .add() @@ -25,6 +26,7 @@ public class WeightedTrade implements IWeightedElement { .append(new KeyedCodec<>("Stock", Codec.INT_ARRAY), (wt, arr) -> wt.stockRange = arr, wt -> wt.stockRange) .add() .build(); + @Nonnull public static final WeightedTrade[] EMPTY_ARRAY = new WeightedTrade[0]; protected double weight = 100.0; protected BarterItemStack output; diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/interaction/server/TeleporterInteraction.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/interaction/server/TeleporterInteraction.java index 0b664dd6..2b198beb 100644 --- a/src/com/hypixel/hytale/builtin/adventure/teleporter/interaction/server/TeleporterInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/interaction/server/TeleporterInteraction.java @@ -101,7 +101,7 @@ public class TeleporterInteraction extends SimpleBlockInteraction { BlockModule.BlockStateInfo blockStateInfoComponent = blockRef.getStore().getComponent(blockRef, BlockModule.BlockStateInfo.getComponentType()); if (blockStateInfoComponent != null) { Ref chunkRef = blockStateInfoComponent.getChunkRef(); - if (chunkRef != null || chunkRef.isValid()) { + if (chunkRef.isValid()) { Teleporter teleporter = chunkStore.getStore().getComponent(blockRef, Teleporter.getComponentType()); if (teleporter != null) { Ref ref = context.getEntity(); diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/page/TeleporterSettingsPageSupplier.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/page/TeleporterSettingsPageSupplier.java index d23c56a4..4107122a 100644 --- a/src/com/hypixel/hytale/builtin/adventure/teleporter/page/TeleporterSettingsPageSupplier.java +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/page/TeleporterSettingsPageSupplier.java @@ -57,7 +57,10 @@ public class TeleporterSettingsPageSupplier implements OpenCustomUIInteraction.C @Nullable @Override public CustomUIPage tryCreate( - @Nonnull Ref ref, ComponentAccessor componentAccessor, @Nonnull PlayerRef playerRef, @Nonnull InteractionContext context + @Nonnull Ref ref, + @Nonnull ComponentAccessor componentAccessor, + @Nonnull PlayerRef playerRef, + @Nonnull InteractionContext context ) { BlockPosition targetBlock = context.getTargetBlock(); if (targetBlock == null) { @@ -66,10 +69,11 @@ public class TeleporterSettingsPageSupplier implements OpenCustomUIInteraction.C Store store = ref.getStore(); World world = store.getExternalData().getWorld(); ChunkStore chunkStore = world.getChunkStore(); + Store chunkComponentStore = chunkStore.getStore(); Ref chunkRef = chunkStore.getChunkReference(ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z)); - BlockComponentChunk blockComponentChunk = chunkRef == null - ? null - : chunkStore.getStore().getComponent(chunkRef, BlockComponentChunk.getComponentType()); + BlockComponentChunk blockComponentChunk = chunkRef != null && chunkRef.isValid() + ? chunkComponentStore.getComponent(chunkRef, BlockComponentChunk.getComponentType()) + : null; if (blockComponentChunk == null) { return null; } else { @@ -83,10 +87,10 @@ public class TeleporterSettingsPageSupplier implements OpenCustomUIInteraction.C Holder holder = ChunkStore.REGISTRY.newHolder(); holder.putComponent(BlockModule.BlockStateInfo.getComponentType(), new BlockModule.BlockStateInfo(blockIndex, chunkRef)); holder.ensureComponent(Teleporter.getComponentType()); - blockRef = world.getChunkStore().getStore().addEntity(holder, AddReason.SPAWN); + blockRef = chunkComponentStore.addEntity(holder, AddReason.SPAWN); } - return new TeleporterSettingsPage(playerRef, blockRef, this.mode, this.activeState); + return blockRef != null && blockRef.isValid() ? new TeleporterSettingsPage(playerRef, blockRef, this.mode, this.activeState) : null; } } } diff --git a/src/com/hypixel/hytale/builtin/ambience/systems/AmbientEmitterSystems.java b/src/com/hypixel/hytale/builtin/ambience/systems/AmbientEmitterSystems.java index 55ab3e1d..401f7f5d 100644 --- a/src/com/hypixel/hytale/builtin/ambience/systems/AmbientEmitterSystems.java +++ b/src/com/hypixel/hytale/builtin/ambience/systems/AmbientEmitterSystems.java @@ -3,8 +3,10 @@ package com.hypixel.hytale.builtin.ambience.systems; import com.hypixel.hytale.builtin.ambience.AmbiencePlugin; import com.hypixel.hytale.builtin.ambience.components.AmbientEmitterComponent; import com.hypixel.hytale.component.AddReason; +import com.hypixel.hytale.component.Archetype; import com.hypixel.hytale.component.ArchetypeChunk; import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.NonSerialized; import com.hypixel.hytale.component.Ref; @@ -23,16 +25,18 @@ import com.hypixel.hytale.server.core.prefab.PrefabCopyableComponent; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.util.logging.Level; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class AmbientEmitterSystems { public static class EntityAdded extends HolderSystem { + @Nonnull private final Query query = Query.and(AmbientEmitterComponent.getComponentType(), TransformComponent.getComponentType()); @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - if (!holder.getArchetype().contains(NetworkId.getComponentType())) { - holder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId())); + Archetype archetype = holder.getArchetype(); + ComponentType networkIdComponentType = NetworkId.getComponentType(); + if (!archetype.contains(networkIdComponentType)) { + holder.addComponent(networkIdComponentType, new NetworkId(store.getExternalData().takeNextNetworkId())); } holder.ensureComponent(Intangible.getComponentType()); @@ -43,6 +47,7 @@ public class AmbientEmitterSystems { public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { } + @Nonnull @Override public Query getQuery() { return this.query; @@ -50,6 +55,7 @@ public class AmbientEmitterSystems { } public static class EntityRefAdded extends RefSystem { + @Nonnull private final Query query = Query.and(AmbientEmitterComponent.getComponentType(), TransformComponent.getComponentType()); @Override @@ -91,7 +97,7 @@ public class AmbientEmitterSystems { } } - @Nullable + @Nonnull @Override public Query getQuery() { return this.query; @@ -99,6 +105,7 @@ public class AmbientEmitterSystems { } public static class Ticking extends EntityTickingSystem { + @Nonnull private final Query query = Query.and(AmbientEmitterComponent.getComponentType(), TransformComponent.getComponentType()); @Override @@ -109,29 +116,33 @@ public class AmbientEmitterSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - AmbientEmitterComponent emitter = archetypeChunk.getComponent(index, AmbientEmitterComponent.getComponentType()); + AmbientEmitterComponent emitterComponent = archetypeChunk.getComponent(index, AmbientEmitterComponent.getComponentType()); - assert emitter != null; + assert emitterComponent != null; - TransformComponent transform = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); - assert transform != null; + assert transformComponent != null; - if (emitter.getSpawnedEmitter() != null && emitter.getSpawnedEmitter().isValid()) { - TransformComponent ownedEmitterTransform = store.getComponent(emitter.getSpawnedEmitter(), TransformComponent.getComponentType()); - if (transform.getPosition().distanceSquaredTo(ownedEmitterTransform.getPosition()) > 1.0) { - ownedEmitterTransform.setPosition(transform.getPosition()); + Ref spawnedEmitterRef = emitterComponent.getSpawnedEmitter(); + if (spawnedEmitterRef != null && spawnedEmitterRef.isValid()) { + TransformComponent ownedEmitterTransform = commandBuffer.getComponent(spawnedEmitterRef, TransformComponent.getComponentType()); + if (ownedEmitterTransform != null) { + if (transformComponent.getPosition().distanceSquaredTo(ownedEmitterTransform.getPosition()) > 1.0) { + ownedEmitterTransform.setPosition(transformComponent.getPosition()); + } } } else { + Ref ref = archetypeChunk.getReferenceTo(index); AmbiencePlugin.get() .getLogger() .at(Level.WARNING) - .log("Ambient emitter lost at %s: %d %s", transform.getPosition(), archetypeChunk.getReferenceTo(index).getIndex(), emitter.getSoundEventId()); - commandBuffer.removeEntity(archetypeChunk.getReferenceTo(index), RemoveReason.REMOVE); + .log("Ambient emitter lost at %s: %d %s", transformComponent.getPosition(), ref.getIndex(), emitterComponent.getSoundEventId()); + commandBuffer.removeEntity(ref, RemoveReason.REMOVE); } } - @Nullable + @Nonnull @Override public Query getQuery() { return this.query; diff --git a/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorGamePacketHandler.java b/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorGamePacketHandler.java index 5a5a61ed..a09509d5 100644 --- a/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorGamePacketHandler.java +++ b/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorGamePacketHandler.java @@ -65,28 +65,22 @@ public class AssetEditorGamePacketHandler implements SubPacketHandler { if (ref != null && ref.isValid()) { Store store = ref.getStore(); World world = store.getExternalData().getWorld(); - world.execute( - () -> { + CompletableFuture.runAsync(() -> { Player playerComponent = store.getComponent(ref, Player.getComponentType()); if (!this.lacksPermission(playerComponent, true)) { - CompletableFuture.runAsync( - () -> { - LOGGER.at(Level.INFO).log("%s updating json asset at %s", this.packetHandler.getPlayerRef().getUsername(), packet.path); - EditorClient mockClient = new EditorClient(playerRef); - AssetEditorPlugin.get() - .handleJsonAssetUpdate( - mockClient, - packet.path != null ? new AssetPath(packet.path) : null, - packet.assetType, - packet.assetIndex, - packet.commands, - packet.token - ); - } - ); + ; } - } - ); + }, world) + .thenRunAsync( + () -> { + LOGGER.at(Level.INFO).log("%s updating json asset at %s", this.packetHandler.getPlayerRef().getUsername(), packet.path); + EditorClient mockClient = new EditorClient(playerRef); + AssetEditorPlugin.get() + .handleJsonAssetUpdate( + mockClient, packet.path != null ? new AssetPath(packet.path) : null, packet.assetType, packet.assetIndex, packet.commands, packet.token + ); + } + ); } else { throw new RuntimeException("Unable to process AssetEditorUpdateJsonAsset packet. Player ref is invalid!"); } diff --git a/src/com/hypixel/hytale/builtin/beds/BedsPlugin.java b/src/com/hypixel/hytale/builtin/beds/BedsPlugin.java index f4cbb5c4..884d00ad 100644 --- a/src/com/hypixel/hytale/builtin/beds/BedsPlugin.java +++ b/src/com/hypixel/hytale/builtin/beds/BedsPlugin.java @@ -16,6 +16,7 @@ import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Int import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; public class BedsPlugin extends JavaPlugin { private static BedsPlugin instance; @@ -27,7 +28,7 @@ public class BedsPlugin extends JavaPlugin { return instance; } - public BedsPlugin(JavaPluginInit init) { + public BedsPlugin(@Nonnull JavaPluginInit init) { super(init); } diff --git a/src/com/hypixel/hytale/builtin/beds/interactions/BedInteraction.java b/src/com/hypixel/hytale/builtin/beds/interactions/BedInteraction.java index 813a81e8..0628ea4c 100644 --- a/src/com/hypixel/hytale/builtin/beds/interactions/BedInteraction.java +++ b/src/com/hypixel/hytale/builtin/beds/interactions/BedInteraction.java @@ -79,48 +79,50 @@ public class BedInteraction extends SimpleBlockInteraction { int blockIndex = ChunkUtil.indexBlockInColumn(pos.x, pos.y, pos.z); Ref blockRef = blockComponentChunk.getEntityReference(blockIndex); - if (blockRef == null) { + if (blockRef == null || !blockRef.isValid()) { Holder holder = ChunkStore.REGISTRY.newHolder(); holder.putComponent(BlockModule.BlockStateInfo.getComponentType(), new BlockModule.BlockStateInfo(blockIndex, chunkReference)); holder.ensureComponent(RespawnBlock.getComponentType()); blockRef = chunkStore.addEntity(holder, AddReason.SPAWN); } - RespawnBlock respawnBlockComponent = chunkStore.getComponent(blockRef, RespawnBlock.getComponentType()); - if (respawnBlockComponent != null) { - UUID ownerUUID = respawnBlockComponent.getOwnerUUID(); - PageManager pageManager = player.getPageManager(); - boolean isOwner = playerUuid.equals(ownerUUID); - if (isOwner) { - BlockPosition rawTarget = context.getMetaStore().getMetaObject(TARGET_BLOCK_RAW); - Vector3f whereWasHit = new Vector3f(rawTarget.x + 0.5F, rawTarget.y + 0.5F, rawTarget.z + 0.5F); - BlockMountAPI.BlockMountResult result = BlockMountAPI.mountOnBlock(ref, commandBuffer, pos, whereWasHit); - if (result instanceof BlockMountAPI.DidNotMount) { - player.sendMessage(Message.translation("server.interactions.didNotMount").param("state", result.toString())); - } else if (result instanceof BlockMountAPI.Mounted) { - commandBuffer.putComponent(ref, PlayerSomnolence.getComponentType(), PlayerSleep.NoddingOff.createComponent()); - } - } else if (ownerUUID != null) { - player.sendMessage(MESSAGE_SERVER_CUSTOM_UI_RESPAWN_POINT_CLAIMED); - } else { - PlayerRespawnPointData[] respawnPoints = player.getPlayerConfigData().getPerWorldData(world.getName()).getRespawnPoints(); - RespawnConfig respawnConfig = world.getGameplayConfig().getRespawnConfig(); - int radiusLimitRespawnPoint = respawnConfig.getRadiusLimitRespawnPoint(); - PlayerRespawnPointData[] nearbyRespawnPoints = this.getNearbySavedRespawnPoints( - pos, respawnBlockComponent, respawnPoints, radiusLimitRespawnPoint - ); - if (nearbyRespawnPoints != null) { - pageManager.openCustomPage( - ref, - store, - new OverrideNearbyRespawnPointPage(playerRefComponent, type, pos, respawnBlockComponent, nearbyRespawnPoints, radiusLimitRespawnPoint) - ); - } else if (respawnPoints != null && respawnPoints.length >= respawnConfig.getMaxRespawnPointsPerPlayer()) { - pageManager.openCustomPage( - ref, store, new SelectOverrideRespawnPointPage(playerRefComponent, type, pos, respawnBlockComponent, respawnPoints) - ); + if (blockRef != null && blockRef.isValid()) { + RespawnBlock respawnBlockComponent = chunkStore.getComponent(blockRef, RespawnBlock.getComponentType()); + if (respawnBlockComponent != null) { + UUID ownerUUID = respawnBlockComponent.getOwnerUUID(); + PageManager pageManager = player.getPageManager(); + boolean isOwner = playerUuid.equals(ownerUUID); + if (isOwner) { + BlockPosition targetBlockPosition = context.getMetaStore().getMetaObject(TARGET_BLOCK_RAW); + Vector3f whereWasHit = new Vector3f(targetBlockPosition.x + 0.5F, targetBlockPosition.y + 0.5F, targetBlockPosition.z + 0.5F); + BlockMountAPI.BlockMountResult result = BlockMountAPI.mountOnBlock(ref, commandBuffer, pos, whereWasHit); + if (result instanceof BlockMountAPI.DidNotMount) { + player.sendMessage(Message.translation("server.interactions.didNotMount").param("state", result.toString())); + } else if (result instanceof BlockMountAPI.Mounted) { + commandBuffer.putComponent(ref, PlayerSomnolence.getComponentType(), PlayerSleep.NoddingOff.createComponent()); + } + } else if (ownerUUID != null) { + player.sendMessage(MESSAGE_SERVER_CUSTOM_UI_RESPAWN_POINT_CLAIMED); } else { - pageManager.openCustomPage(ref, store, new SetNameRespawnPointPage(playerRefComponent, type, pos, respawnBlockComponent)); + PlayerRespawnPointData[] respawnPoints = player.getPlayerConfigData().getPerWorldData(world.getName()).getRespawnPoints(); + RespawnConfig respawnConfig = world.getGameplayConfig().getRespawnConfig(); + int radiusLimitRespawnPoint = respawnConfig.getRadiusLimitRespawnPoint(); + PlayerRespawnPointData[] nearbyRespawnPoints = getNearbySavedRespawnPoints(pos, respawnPoints, radiusLimitRespawnPoint); + if (nearbyRespawnPoints != null) { + pageManager.openCustomPage( + ref, + store, + new OverrideNearbyRespawnPointPage( + playerRefComponent, type, pos, respawnBlockComponent, nearbyRespawnPoints, radiusLimitRespawnPoint + ) + ); + } else if (respawnPoints != null && respawnPoints.length >= respawnConfig.getMaxRespawnPointsPerPlayer()) { + pageManager.openCustomPage( + ref, store, new SelectOverrideRespawnPointPage(playerRefComponent, type, pos, respawnBlockComponent, respawnPoints) + ); + } else { + pageManager.openCustomPage(ref, store, new SetNameRespawnPointPage(playerRefComponent, type, pos, respawnBlockComponent)); + } } } } @@ -135,11 +137,8 @@ public class BedInteraction extends SimpleBlockInteraction { } @Nullable - private PlayerRespawnPointData[] getNearbySavedRespawnPoints( - @Nonnull Vector3i currentRespawnPointPosition, - @Nonnull RespawnBlock respawnBlock, - @Nullable PlayerRespawnPointData[] respawnPoints, - int radiusLimitRespawnPoint + private static PlayerRespawnPointData[] getNearbySavedRespawnPoints( + @Nonnull Vector3i currentRespawnPointPosition, @Nullable PlayerRespawnPointData[] respawnPoints, int radiusLimitRespawnPoint ) { if (respawnPoints != null && respawnPoints.length != 0) { ObjectArrayList nearbyRespawnPointList = new ObjectArrayList<>(); diff --git a/src/com/hypixel/hytale/builtin/beds/respawn/OverrideNearbyRespawnPointPage.java b/src/com/hypixel/hytale/builtin/beds/respawn/OverrideNearbyRespawnPointPage.java index a02520ba..eb8a1f50 100644 --- a/src/com/hypixel/hytale/builtin/beds/respawn/OverrideNearbyRespawnPointPage.java +++ b/src/com/hypixel/hytale/builtin/beds/respawn/OverrideNearbyRespawnPointPage.java @@ -19,17 +19,22 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class OverrideNearbyRespawnPointPage extends RespawnPointPage { + @Nonnull + private static final String PAGE_OVERRIDE_NEARBY_SPAWN_POINT_PAGE = "Pages/OverrideNearbyRespawnPointPage.ui"; + @Nonnull private final Vector3i respawnPointPosition; + @Nonnull private final RespawnBlock respawnPointToAdd; + @Nonnull private final PlayerRespawnPointData[] nearbyRespawnPoints; - private int radiusLimitRespawnPoint; + private final int radiusLimitRespawnPoint; public OverrideNearbyRespawnPointPage( @Nonnull PlayerRef playerRef, - InteractionType interactionType, - Vector3i respawnPointPosition, - RespawnBlock respawnPointToAdd, - PlayerRespawnPointData[] nearbyRespawnPoints, + @Nonnull InteractionType interactionType, + @Nonnull Vector3i respawnPointPosition, + @Nonnull RespawnBlock respawnPointToAdd, + @Nonnull PlayerRespawnPointData[] nearbyRespawnPoints, int radiusLimitRespawnPoint ) { super(playerRef, interactionType); @@ -84,7 +89,9 @@ public class OverrideNearbyRespawnPointPage extends RespawnPointPage { this.setRespawnPointForPlayer(ref, store, this.respawnPointPosition, this.respawnPointToAdd, respawnPointName, this.nearbyRespawnPoints); } else if ("Cancel".equals(data.getAction())) { Player playerComponent = store.getComponent(ref, Player.getComponentType()); - playerComponent.getPageManager().setPage(ref, store, Page.None); + if (playerComponent != null) { + playerComponent.getPageManager().setPage(ref, store, Page.None); + } } } } diff --git a/src/com/hypixel/hytale/builtin/beds/respawn/RespawnPointPage.java b/src/com/hypixel/hytale/builtin/beds/respawn/RespawnPointPage.java index c276f842..f8cedf57 100644 --- a/src/com/hypixel/hytale/builtin/beds/respawn/RespawnPointPage.java +++ b/src/com/hypixel/hytale/builtin/beds/respawn/RespawnPointPage.java @@ -33,9 +33,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class RespawnPointPage extends InteractiveCustomUIPage { - private final int RESPAWN_NAME_MAX_LENGTH = 32; + @Nonnull + private static final Message MESSAGE_SERVER_CUSTOM_UI_NEED_TO_SET_NAME = Message.translation("server.customUI.needToSetName"); + private static final int RESPAWN_NAME_MAX_LENGTH = 32; - public RespawnPointPage(@Nonnull PlayerRef playerRef, InteractionType interactionType) { + public RespawnPointPage(@Nonnull PlayerRef playerRef, @Nonnull InteractionType interactionType) { super( playerRef, interactionType == InteractionType.Use ? CustomPageLifetime.CanDismissOrCloseThroughInteraction : CustomPageLifetime.CanDismiss, @@ -56,7 +58,7 @@ public abstract class RespawnPointPage extends InteractiveCustomUIPage 32) { this.displayError(Message.translation("server.customUI.respawnNameTooLong").param("maxLength", 32)); } else { @@ -66,48 +68,54 @@ public abstract class RespawnPointPage extends InteractiveCustomUIPage chunkReference = chunkStore.getChunkReference(ChunkUtil.indexChunkFromBlock(position.x, position.z)); - if (chunkReference != null) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(position.x, position.z); + Ref chunkReference = chunkStore.getChunkReference(chunkIndex); + if (chunkReference != null && chunkReference.isValid()) { BlockComponentChunk blockComponentChunk = chunkStore.getStore().getComponent(chunkReference, BlockComponentChunk.getComponentType()); - Ref blockRef = blockComponentChunk.getEntityReference(ChunkUtil.indexBlockInColumn(position.x, position.y, position.z)); - if (blockRef != null) { - RespawnBlock respawnBlock = chunkStore.getStore().getComponent(blockRef, RespawnBlock.getComponentType()); - if (respawnBlock != null) { - respawnBlock.setOwnerUUID(null); - WorldChunk worldChunk = chunkStore.getStore().getComponent(chunkReference, WorldChunk.getComponentType()); - if (worldChunk != null) { - worldChunk.markNeedsSaving(); + if (blockComponentChunk != null) { + int blockIndex = ChunkUtil.indexBlockInColumn(position.x, position.y, position.z); + Ref blockRef = blockComponentChunk.getEntityReference(blockIndex); + if (blockRef != null && blockRef.isValid()) { + RespawnBlock respawnBlock = chunkStore.getStore().getComponent(blockRef, RespawnBlock.getComponentType()); + if (respawnBlock != null) { + respawnBlock.setOwnerUUID(null); + WorldChunk worldChunk = chunkStore.getStore().getComponent(chunkReference, WorldChunk.getComponentType()); + if (worldChunk != null) { + worldChunk.markNeedsSaving(); + } } } } @@ -155,10 +167,15 @@ public abstract class RespawnPointPage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder( RespawnPointPage.RespawnPointEventData.class, RespawnPointPage.RespawnPointEventData::new ) diff --git a/src/com/hypixel/hytale/builtin/beds/respawn/SelectOverrideRespawnPointPage.java b/src/com/hypixel/hytale/builtin/beds/respawn/SelectOverrideRespawnPointPage.java index 0a6fe524..6d9403fa 100644 --- a/src/com/hypixel/hytale/builtin/beds/respawn/SelectOverrideRespawnPointPage.java +++ b/src/com/hypixel/hytale/builtin/beds/respawn/SelectOverrideRespawnPointPage.java @@ -20,19 +20,28 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class SelectOverrideRespawnPointPage extends RespawnPointPage { + @Nonnull + private static final Message MESSAGE_SERVER_CUSTOM_UI_NEED_TO_SELECT_RESPAWN_POINT = Message.translation("server.customUI.needToSelectRespawnPoint"); + @Nonnull private static final Value DEFAULT_RESPAWN_BUTTON_STYLE = Value.ref("Pages/OverrideRespawnPointButton.ui", "DefaultRespawnButtonStyle"); + @Nonnull private static final Value SELECTED_RESPAWN_BUTTON_STYLE = Value.ref("Pages/OverrideRespawnPointButton.ui", "SelectedRespawnButtonStyle"); + @Nonnull + private static final String PAGE_SELECT_OVERRIDE_RESPAWN_POINT_PAGE = "Pages/SelectOverrideRespawnPointPage.ui"; + @Nonnull private final Vector3i respawnPointToAddPosition; + @Nonnull private final RespawnBlock respawnPointToAdd; + @Nonnull private final PlayerRespawnPointData[] respawnPoints; private int selectedRespawnPointIndex = -1; public SelectOverrideRespawnPointPage( @Nonnull PlayerRef playerRef, - InteractionType interactionType, - Vector3i respawnPointToAddPosition, - RespawnBlock respawnPointToAdd, - PlayerRespawnPointData[] respawnPoints + @Nonnull InteractionType interactionType, + @Nonnull Vector3i respawnPointToAddPosition, + @Nonnull RespawnBlock respawnPointToAdd, + @Nonnull PlayerRespawnPointData[] respawnPoints ) { super(playerRef, interactionType); this.respawnPointToAddPosition = respawnPointToAddPosition; @@ -81,7 +90,7 @@ public class SelectOverrideRespawnPointPage extends RespawnPointPage { this.sendUpdate(); } else if (data.getRespawnPointName() != null) { if (this.selectedRespawnPointIndex == -1) { - this.displayError(Message.translation("server.customUI.needToSelectRespawnPoint")); + this.displayError(MESSAGE_SERVER_CUSTOM_UI_NEED_TO_SELECT_RESPAWN_POINT); return; } @@ -90,7 +99,9 @@ public class SelectOverrideRespawnPointPage extends RespawnPointPage { ); } else if ("Cancel".equals(data.getAction())) { Player playerComponent = store.getComponent(ref, Player.getComponentType()); - playerComponent.getPageManager().setPage(ref, store, Page.None); + if (playerComponent != null) { + playerComponent.getPageManager().setPage(ref, store, Page.None); + } } } diff --git a/src/com/hypixel/hytale/builtin/beds/respawn/SetNameRespawnPointPage.java b/src/com/hypixel/hytale/builtin/beds/respawn/SetNameRespawnPointPage.java index bfec4ed2..40d11400 100644 --- a/src/com/hypixel/hytale/builtin/beds/respawn/SetNameRespawnPointPage.java +++ b/src/com/hypixel/hytale/builtin/beds/respawn/SetNameRespawnPointPage.java @@ -19,10 +19,14 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class SetNameRespawnPointPage extends RespawnPointPage { + @Nonnull private final Vector3i respawnBlockPosition; + @Nonnull private final RespawnBlock respawnBlock; - public SetNameRespawnPointPage(@Nonnull PlayerRef playerRef, InteractionType interactionType, Vector3i respawnBlockPosition, RespawnBlock respawnBlock) { + public SetNameRespawnPointPage( + @Nonnull PlayerRef playerRef, @Nonnull InteractionType interactionType, @Nonnull Vector3i respawnBlockPosition, @Nonnull RespawnBlock respawnBlock + ) { super(playerRef, interactionType); this.respawnBlockPosition = respawnBlockPosition; this.respawnBlock = respawnBlock; @@ -69,7 +73,9 @@ public class SetNameRespawnPointPage extends RespawnPointPage { this.setRespawnPointForPlayer(ref, store, this.respawnBlockPosition, this.respawnBlock, respawnPointName); } else if ("Cancel".equals(data.getAction())) { Player playerComponent = store.getComponent(ref, Player.getComponentType()); - playerComponent.getPageManager().setPage(ref, store, Page.None); + if (playerComponent != null) { + playerComponent.getPageManager().setPage(ref, store, Page.None); + } } } } diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSleep.java b/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSleep.java index 1f0aeb54..68b35e8a 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSleep.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSleep.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.builtin.beds.sleep.components; import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; import java.time.Instant; +import javax.annotation.Nonnull; public sealed interface PlayerSleep permits PlayerSleep.FullyAwake, PlayerSleep.MorningWakeUp, PlayerSleep.NoddingOff, PlayerSleep.Slumber { public static enum FullyAwake implements PlayerSleep { @@ -9,7 +10,8 @@ public sealed interface PlayerSleep permits PlayerSleep.FullyAwake, PlayerSleep. } public record MorningWakeUp(Instant gameTimeStart) implements PlayerSleep { - public static PlayerSomnolence createComponent(WorldTimeResource worldTimeResource) { + @Nonnull + public static PlayerSomnolence createComponent(@Nonnull WorldTimeResource worldTimeResource) { Instant now = worldTimeResource.getGameTime(); PlayerSleep.MorningWakeUp state = new PlayerSleep.MorningWakeUp(now); return new PlayerSomnolence(state); @@ -17,6 +19,7 @@ public sealed interface PlayerSleep permits PlayerSleep.FullyAwake, PlayerSleep. } public record NoddingOff(Instant realTimeStart) implements PlayerSleep { + @Nonnull public static PlayerSomnolence createComponent() { Instant now = Instant.now(); PlayerSleep.NoddingOff state = new PlayerSleep.NoddingOff(now); @@ -25,7 +28,8 @@ public sealed interface PlayerSleep permits PlayerSleep.FullyAwake, PlayerSleep. } public record Slumber(Instant gameTimeStart) implements PlayerSleep { - public static PlayerSomnolence createComponent(WorldTimeResource worldTimeResource) { + @Nonnull + public static PlayerSomnolence createComponent(@Nonnull WorldTimeResource worldTimeResource) { Instant now = worldTimeResource.getGameTime(); PlayerSleep.Slumber state = new PlayerSleep.Slumber(now); return new PlayerSomnolence(state); diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSomnolence.java b/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSomnolence.java index 4bb516cc..ca7b560e 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSomnolence.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSomnolence.java @@ -4,10 +4,13 @@ import com.hypixel.hytale.builtin.beds.BedsPlugin; import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PlayerSomnolence implements Component { + @Nonnull public static PlayerSomnolence AWAKE = new PlayerSomnolence(PlayerSleep.FullyAwake.INSTANCE); + @Nonnull private PlayerSleep state = PlayerSleep.FullyAwake.INSTANCE; public static ComponentType getComponentType() { @@ -17,10 +20,11 @@ public class PlayerSomnolence implements Component { public PlayerSomnolence() { } - public PlayerSomnolence(PlayerSleep state) { + public PlayerSomnolence(@Nonnull PlayerSleep state) { this.state = state; } + @Nonnull public PlayerSleep getSleepState() { return this.state; } diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/components/SleepTracker.java b/src/com/hypixel/hytale/builtin/beds/sleep/components/SleepTracker.java index d8e4de8b..d315512d 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/components/SleepTracker.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/components/SleepTracker.java @@ -5,9 +5,11 @@ import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.protocol.packets.world.UpdateSleepState; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SleepTracker implements Component { + @Nonnull private UpdateSleepState lastSentPacket = new UpdateSleepState(false, false, null, null); public static ComponentType getComponentType() { @@ -15,7 +17,7 @@ public class SleepTracker implements Component { } @Nullable - public UpdateSleepState generatePacketToSend(UpdateSleepState state) { + public UpdateSleepState generatePacketToSend(@Nonnull UpdateSleepState state) { if (this.lastSentPacket.equals(state)) { return null; } else { diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/resources/WorldSlumber.java b/src/com/hypixel/hytale/builtin/beds/sleep/resources/WorldSlumber.java index b1e60e4e..7e88f773 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/resources/WorldSlumber.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/resources/WorldSlumber.java @@ -4,16 +4,21 @@ import com.hypixel.hytale.protocol.InstantData; import com.hypixel.hytale.protocol.packets.world.SleepClock; import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; import java.time.Instant; +import javax.annotation.Nonnull; public final class WorldSlumber implements WorldSleep { + @Nonnull private final Instant startInstant; + @Nonnull private final Instant targetInstant; + @Nonnull private final InstantData startInstantData; + @Nonnull private final InstantData targetInstantData; private final float irlDurationSeconds; - private float progressSeconds = 0.0F; + private float progressSeconds; - public WorldSlumber(Instant startInstant, Instant targetInstant, float irlDurationSeconds) { + public WorldSlumber(@Nonnull Instant startInstant, @Nonnull Instant targetInstant, float irlDurationSeconds) { this.startInstant = startInstant; this.targetInstant = targetInstant; this.startInstantData = WorldTimeResource.instantToInstantData(startInstant); @@ -21,18 +26,22 @@ public final class WorldSlumber implements WorldSleep { this.irlDurationSeconds = irlDurationSeconds; } + @Nonnull public Instant getStartInstant() { return this.startInstant; } + @Nonnull public Instant getTargetInstant() { return this.targetInstant; } + @Nonnull public InstantData getStartInstantData() { return this.startInstantData; } + @Nonnull public InstantData getTargetInstantData() { return this.targetInstantData; } @@ -41,7 +50,7 @@ public final class WorldSlumber implements WorldSleep { return this.progressSeconds; } - public void incProgressSeconds(float seconds) { + public void incrementProgressSeconds(float seconds) { this.progressSeconds += seconds; this.progressSeconds = Math.min(this.progressSeconds, this.irlDurationSeconds); } @@ -50,6 +59,7 @@ public final class WorldSlumber implements WorldSleep { return this.irlDurationSeconds; } + @Nonnull public SleepClock createSleepClock() { float progress = this.progressSeconds / this.irlDurationSeconds; return new SleepClock(this.startInstantData, this.targetInstantData, progress, this.irlDurationSeconds); diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/resources/WorldSomnolence.java b/src/com/hypixel/hytale/builtin/beds/sleep/resources/WorldSomnolence.java index 84e3906b..d1e63e53 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/resources/WorldSomnolence.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/resources/WorldSomnolence.java @@ -8,12 +8,14 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class WorldSomnolence implements Resource { + @Nonnull private WorldSleep state = WorldSleep.Awake.INSTANCE; public static ResourceType getResourceType() { return BedsPlugin.getInstance().getWorldSomnolenceResourceType(); } + @Nonnull public WorldSleep getState() { return this.state; } diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/EnterBedSystem.java b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/EnterBedSystem.java index 69b60910..4978a52d 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/EnterBedSystem.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/EnterBedSystem.java @@ -21,8 +21,16 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class EnterBedSystem extends RefChangeSystem { - public static final Query QUERY = Query.and(MountedComponent.getComponentType(), PlayerRef.getComponentType()); + @Nonnull + private static final Message MESSAGE_SERVER_INTERACTIONS_SLEEP_GAME_TIME_PAUSED = Message.translation("server.interactions.sleep.gameTimePaused"); + @Nonnull + private static final Message MESSAGE_SERVER_INTERACTIONS_SLEEP_NOT_WITHIN_HOURS = Message.translation("server.interactions.sleep.notWithinHours"); + @Nonnull + private static final Message MESSAGE_SERVER_INTERACTIONS_SLEEP_DISABLED = Message.translation("server.interactions.sleep.disabled"); + @Nonnull + private static final Query QUERY = Query.and(MountedComponent.getComponentType(), PlayerRef.getComponentType()); + @Nonnull @Override public ComponentType componentType() { return MountedComponent.getComponentType(); @@ -36,7 +44,7 @@ public class EnterBedSystem extends RefChangeSystem ref, @Nonnull MountedComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - this.check(ref, component, store); + check(ref, component, store); } public void onComponentSet( @@ -46,7 +54,7 @@ public class EnterBedSystem extends RefChangeSystem store, @Nonnull CommandBuffer commandBuffer ) { - this.check(ref, newComponent, store); + check(ref, newComponent, store); } public void onComponentRemoved( @@ -54,13 +62,13 @@ public class EnterBedSystem extends RefChangeSystem ref, MountedComponent component, Store store) { + public static void check(@Nonnull Ref ref, @Nonnull MountedComponent component, @Nonnull Store store) { if (component.getBlockMountType() == BlockMountType.Bed) { - this.onEnterBed(ref, store); + onEnterBed(ref, store); } } - public void onEnterBed(Ref ref, Store store) { + public static void onEnterBed(@Nonnull Ref ref, @Nonnull Store store) { World world = store.getExternalData().getWorld(); CanSleepInWorld.Result canSleepResult = CanSleepInWorld.check(world); if (canSleepResult.isNegative()) { @@ -68,24 +76,25 @@ public class EnterBedSystem extends RefChangeSystem= 12; - int displayHour = hour % 12; - if (displayHour == 0) { - displayHour = 12; - } - - String msgKey = isPM ? "server.interactions.sleep.timePM" : "server.interactions.sleep.timeAM"; - return Message.translation(msgKey).param("h", displayHour).param("m", String.format("%02d", minute)); + // 08: istore 2 + // 09: aload 1 + // 0a: iload 2 + // 0b: invokedynamic typeSwitch (Ljava/lang/Object;I)I bsm=java/lang/runtime/SwitchBootstraps.typeSwitch (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; args=[ null.invoke Ljava/lang/Enum$EnumDesc;, com/hypixel/hytale/builtin/beds/sleep/systems/world/CanSleepInWorld$NotDuringSleepHoursRange ] + // 10: lookupswitch 45 2 0 28 1 34 + // 2c: getstatic com/hypixel/hytale/builtin/beds/sleep/systems/player/EnterBedSystem.MESSAGE_SERVER_INTERACTIONS_SLEEP_GAME_TIME_PAUSED Lcom/hypixel/hytale/server/core/Message; + // 2f: goto 40 + // 32: aload 1 + // 33: checkcast com/hypixel/hytale/builtin/beds/sleep/systems/world/CanSleepInWorld$NotDuringSleepHoursRange + // 36: astore 3 + // 37: getstatic com/hypixel/hytale/builtin/beds/sleep/systems/player/EnterBedSystem.MESSAGE_SERVER_INTERACTIONS_SLEEP_NOT_WITHIN_HOURS Lcom/hypixel/hytale/server/core/Message; + // 3a: goto 40 + // 3d: getstatic com/hypixel/hytale/builtin/beds/sleep/systems/player/EnterBedSystem.MESSAGE_SERVER_INTERACTIONS_SLEEP_DISABLED Lcom/hypixel/hytale/server/core/Message; + // 40: areturn } + @Nonnull private static Message formatDuration(@Nonnull Duration duration) { long totalMinutes = duration.toMinutes(); long hours = totalMinutes / 60L; diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/UpdateSleepPacketSystem.java b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/UpdateSleepPacketSystem.java index da936c2a..96155ca3 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/UpdateSleepPacketSystem.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/UpdateSleepPacketSystem.java @@ -20,9 +20,9 @@ import com.hypixel.hytale.protocol.packets.world.UpdateSleepState; 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.storage.EntityStore; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.UUID; @@ -30,11 +30,15 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class UpdateSleepPacketSystem extends DelayedEntitySystem { + @Nonnull public static final Query QUERY = Query.and(PlayerRef.getComponentType(), PlayerSomnolence.getComponentType(), SleepTracker.getComponentType()); public static final Duration SPAN_BEFORE_BLACK_SCREEN = Duration.ofMillis(1200L); public static final int MAX_SAMPLE_COUNT = 5; + @Nonnull private static final UUID[] EMPTY_UUIDS = new UUID[0]; + @Nonnull private static final UpdateSleepState PACKET_NO_SLEEP_UI = new UpdateSleepState(false, false, null, null); + private static final float SYSTEM_INTERVAL_S = 0.25F; @Override public Query getQuery() { @@ -68,6 +72,7 @@ public class UpdateSleepPacketSystem extends DelayedEntitySystem { } } + @Nonnull private UpdateSleepState createSleepPacket(@Nonnull Store store, int index, @Nonnull ArchetypeChunk archetypeChunk) { World world = store.getExternalData().getWorld(); WorldSomnolence worldSomnolence = store.getResource(WorldSomnolence.getResourceType()); @@ -101,7 +106,7 @@ public class UpdateSleepPacketSystem extends DelayedEntitySystem { @Nullable private SleepMultiplayer createSleepMultiplayer(@Nonnull Store store) { World world = store.getExternalData().getWorld(); - List playerRefs = new ArrayList<>(world.getPlayerRefs()); + List playerRefs = new ObjectArrayList<>(world.getPlayerRefs()); playerRefs.removeIf(playerRefx -> playerRefx.getReference() == null); if (playerRefs.size() <= 1) { return null; @@ -109,7 +114,7 @@ public class UpdateSleepPacketSystem extends DelayedEntitySystem { playerRefs.sort(Comparator.comparingLong(refx -> refx.getUuid().hashCode() + world.hashCode())); int sleepersCount = 0; int awakeCount = 0; - List awakeSampleList = new ArrayList<>(playerRefs.size()); + List awakeSampleList = new ObjectArrayList<>(playerRefs.size()); for (PlayerRef playerRef : playerRefs) { Ref ref = playerRef.getReference(); diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/WakeUpOnDismountSystem.java b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/WakeUpOnDismountSystem.java index 05e4fb9f..d0472652 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/WakeUpOnDismountSystem.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/WakeUpOnDismountSystem.java @@ -14,6 +14,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class WakeUpOnDismountSystem extends RefChangeSystem { + @Nonnull @Override public ComponentType componentType() { return MountedComponent.getComponentType(); diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/CanSleepInWorld.java b/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/CanSleepInWorld.java index fb8bb967..67af7cf3 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/CanSleepInWorld.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/CanSleepInWorld.java @@ -6,9 +6,11 @@ import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.time.LocalDateTime; +import javax.annotation.Nonnull; public final class CanSleepInWorld { - public static CanSleepInWorld.Result check(World world) { + @Nonnull + public static CanSleepInWorld.Result check(@Nonnull World world) { if (world.getWorldConfig().isGameTimePaused()) { return CanSleepInWorld.Status.GAME_TIME_PAUSED; } else { diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/StartSlumberSystem.java b/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/StartSlumberSystem.java index d996248f..c0bdc569 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/StartSlumberSystem.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/StartSlumberSystem.java @@ -22,8 +22,11 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; public class StartSlumberSystem extends DelayedSystem { - public static final Duration NODDING_OFF_DURATION = Duration.ofMillis(3200L); - public static final Duration WAKE_UP_AUTOSLEEP_DELAY = Duration.ofHours(1L); + @Nonnull + private static final Duration NODDING_OFF_DURATION = Duration.ofMillis(3200L); + @Nonnull + private static final Duration WAKE_UP_AUTOSLEEP_DELAY = Duration.ofHours(1L); + private static final float SYSTEM_INTERVAL_S = 0.3F; public StartSlumberSystem() { super(0.3F); @@ -34,7 +37,7 @@ public class StartSlumberSystem extends DelayedSystem { this.checkIfEveryoneIsReadyToSleep(store); } - private void checkIfEveryoneIsReadyToSleep(Store store) { + private void checkIfEveryoneIsReadyToSleep(@Nonnull Store store) { World world = store.getExternalData().getWorld(); Collection playerRefs = world.getPlayerRefs(); if (!playerRefs.isEmpty()) { @@ -43,7 +46,7 @@ public class StartSlumberSystem extends DelayedSystem { WorldSomnolence worldSomnolenceResource = store.getResource(WorldSomnolence.getResourceType()); WorldSleep worldState = worldSomnolenceResource.getState(); if (worldState == WorldSleep.Awake.INSTANCE) { - if (this.isEveryoneReadyToSleep(store)) { + if (isEveryoneReadyToSleep(store)) { WorldTimeResource timeResource = store.getResource(WorldTimeResource.getResourceType()); Instant now = timeResource.getGameTime(); Instant target = this.computeWakeupInstant(now, wakeUpHour); @@ -71,21 +74,22 @@ public class StartSlumberSystem extends DelayedSystem { return wakeUpTime.toInstant(ZoneOffset.UTC); } - private static float computeIrlSeconds(Instant startInstant, Instant targetInstant) { + private static float computeIrlSeconds(@Nonnull Instant startInstant, @Nonnull Instant targetInstant) { long ms = Duration.between(startInstant, targetInstant).toMillis(); long hours = TimeUnit.MILLISECONDS.toHours(ms); double seconds = Math.max(3.0, hours / 6.0); return (float)Math.ceil(seconds); } - private boolean isEveryoneReadyToSleep(ComponentAccessor store) { + private static boolean isEveryoneReadyToSleep(@Nonnull ComponentAccessor store) { World world = store.getExternalData().getWorld(); Collection playerRefs = world.getPlayerRefs(); if (playerRefs.isEmpty()) { return false; } else { for (PlayerRef playerRef : playerRefs) { - if (!isReadyToSleep(store, playerRef.getReference())) { + Ref ref = playerRef.getReference(); + if (ref != null && ref.isValid() && !isReadyToSleep(store, ref)) { return false; } } @@ -94,27 +98,31 @@ public class StartSlumberSystem extends DelayedSystem { } } - public static boolean isReadyToSleep(ComponentAccessor store, Ref ref) { - PlayerSomnolence somnolence = store.getComponent(ref, PlayerSomnolence.getComponentType()); - if (somnolence == null) { - return false; + public static boolean isReadyToSleep(@Nonnull ComponentAccessor store, @Nonnull Ref ref) { + if (!ref.isValid()) { + return true; } else { - PlayerSleep sleepState = somnolence.getSleepState(); + PlayerSomnolence somnolence = store.getComponent(ref, PlayerSomnolence.getComponentType()); + if (somnolence == null) { + return false; + } else { + PlayerSleep sleepState = somnolence.getSleepState(); - return switch (sleepState) { - case PlayerSleep.FullyAwake fullyAwake -> false; - case PlayerSleep.MorningWakeUp morningWakeUp -> { - WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType()); - Instant readyTime = morningWakeUp.gameTimeStart().plus(WAKE_UP_AUTOSLEEP_DELAY); - yield worldTimeResource.getGameTime().isAfter(readyTime); - } - case PlayerSleep.NoddingOff noddingOff -> { - Instant sleepStart = noddingOff.realTimeStart().plus(NODDING_OFF_DURATION); - yield Instant.now().isAfter(sleepStart); - } - case PlayerSleep.Slumber slumber -> true; - default -> throw new MatchException(null, null); - }; + return switch (sleepState) { + case PlayerSleep.FullyAwake ignored -> false; + case PlayerSleep.MorningWakeUp morningWakeUp -> { + WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType()); + Instant readyTime = morningWakeUp.gameTimeStart().plus(WAKE_UP_AUTOSLEEP_DELAY); + yield worldTimeResource.getGameTime().isAfter(readyTime); + } + case PlayerSleep.NoddingOff noddingOff -> { + Instant sleepStart = noddingOff.realTimeStart().plus(NODDING_OFF_DURATION); + yield Instant.now().isAfter(sleepStart); + } + case PlayerSleep.Slumber ignoredx -> true; + default -> throw new MatchException(null, null); + }; + } } } } diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/UpdateWorldSlumberSystem.java b/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/UpdateWorldSlumberSystem.java index c32e76f7..7e7c031f 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/UpdateWorldSlumberSystem.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/systems/world/UpdateWorldSlumberSystem.java @@ -16,7 +16,6 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.time.Duration; import java.time.Instant; import java.util.Collection; -import java.util.Iterator; import javax.annotation.Nonnull; public class UpdateWorldSlumberSystem extends TickingSystem { @@ -25,7 +24,7 @@ public class UpdateWorldSlumberSystem extends TickingSystem { World world = store.getExternalData().getWorld(); WorldSomnolence worldSomnolence = store.getResource(WorldSomnolence.getResourceType()); if (worldSomnolence.getState() instanceof WorldSlumber slumber) { - slumber.incProgressSeconds(dt); + slumber.incrementProgressSeconds(dt); boolean sleepingIsOver = slumber.getProgressSeconds() >= slumber.getIrlDurationSeconds() || isSomeoneAwake(store); if (sleepingIsOver) { worldSomnolence.setState(WorldSleep.Awake.INSTANCE); @@ -46,6 +45,7 @@ public class UpdateWorldSlumberSystem extends TickingSystem { } } + @Nonnull private static Instant computeWakeupTime(@Nonnull WorldSlumber slumber) { float progress = slumber.getProgressSeconds() / slumber.getIrlDurationSeconds(); long totalNanos = Duration.between(slumber.getStartInstant(), slumber.getTargetInstant()).toNanos(); @@ -59,19 +59,20 @@ public class UpdateWorldSlumberSystem extends TickingSystem { if (playerRefs.isEmpty()) { return false; } else { - Iterator var3 = playerRefs.iterator(); - if (var3.hasNext()) { - PlayerRef playerRef = (PlayerRef)var3.next(); - PlayerSomnolence somnolenceComponent = store.getComponent(playerRef.getReference(), PlayerSomnolence.getComponentType()); - if (somnolenceComponent == null) { - return true; - } else { + for (PlayerRef playerRef : playerRefs) { + Ref ref = playerRef.getReference(); + if (ref != null && ref.isValid()) { + PlayerSomnolence somnolenceComponent = store.getComponent(ref, PlayerSomnolence.getComponentType()); + if (somnolenceComponent == null) { + return true; + } + PlayerSleep sleepState = somnolenceComponent.getSleepState(); return sleepState instanceof PlayerSleep.FullyAwake; } - } else { - return false; } + + return false; } } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPacketHandler.java b/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPacketHandler.java index e26ff51d..f83af713 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPacketHandler.java +++ b/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPacketHandler.java @@ -32,6 +32,7 @@ import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSelectionTool import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSelectionToolReplyWithClipboard; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSelectionTransform; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSelectionUpdate; +import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSetEntityCollision; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSetEntityLight; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSetEntityPickupEnabled; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSetEntityScale; @@ -60,9 +61,12 @@ import com.hypixel.hytale.server.core.modules.entity.component.DynamicLight; import com.hypixel.hytale.server.core.modules.entity.component.EntityScaleComponent; import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; import com.hypixel.hytale.server.core.modules.entity.component.Interactable; +import com.hypixel.hytale.server.core.modules.entity.component.NPCMarkerComponent; import com.hypixel.hytale.server.core.modules.entity.component.PersistentDynamicLight; import com.hypixel.hytale.server.core.modules.entity.component.PropComponent; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; +import com.hypixel.hytale.server.core.modules.entity.hitboxcollision.HitboxCollision; +import com.hypixel.hytale.server.core.modules.entity.hitboxcollision.HitboxCollisionConfig; import com.hypixel.hytale.server.core.modules.entity.item.PreventPickup; import com.hypixel.hytale.server.core.modules.interaction.Interactions; import com.hypixel.hytale.server.core.prefab.selection.mask.BlockPattern; @@ -109,6 +113,7 @@ public class BuilderToolsPacketHandler implements SubPacketHandler { this.packetHandler.registerHandler(421, p -> this.handle((BuilderToolSetEntityPickupEnabled)p)); this.packetHandler.registerHandler(422, p -> this.handle((BuilderToolSetEntityLight)p)); this.packetHandler.registerHandler(423, p -> this.handle((BuilderToolSetNPCDebug)p)); + this.packetHandler.registerHandler(425, p -> this.handle((BuilderToolSetEntityCollision)p)); } } @@ -441,7 +446,7 @@ public class BuilderToolsPacketHandler implements SubPacketHandler { } if (prototypeSettings.getBlockChangesForPlaySelectionToolPasteMode() == null) { - s.select(initialSelectionMin, initialSelectionMax, "SelectionTranslatePacket", componentAccessor); + s.select(initialSelectionMin, initialSelectionMax, "server.builderTools.selectReasons.selectionTranslatePacket", componentAccessor); if (packet.cutOriginal) { s.copyOrCut( r, @@ -507,7 +512,7 @@ public class BuilderToolsPacketHandler implements SubPacketHandler { finalKeepEmptyBlocks, componentAccessor ); - s.select(initialSelectionMin, initialSelectionMax, "SelectionTranslatePacket", componentAccessor); + s.select(initialSelectionMin, initialSelectionMax, "server.builderTools.selectReasons.selectionTranslatePacket", componentAccessor); s.transformSelectionPoints(transformationMatrix, rotationOrigin); if (large) { playerComponent.sendMessage(Message.translation("server.builderTools.selection.large.complete")); @@ -578,19 +583,30 @@ public class BuilderToolsPacketHandler implements SubPacketHandler { if (ref != null && ref.isValid()) { Store store = ref.getStore(); World world = store.getExternalData().getWorld(); - world.execute(() -> { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); + world.execute( + () -> { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - if (hasPermission(playerComponent, "hytale.editor.selection.clipboard")) { - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> { - s.select(this.fromBlockPosition(packet.selectionMin), this.fromBlockPosition(packet.selectionMax), "Extrude", componentAccessor); - s.stack(r, new Vector3i(packet.xNormal, packet.yNormal, packet.zNormal), packet.numStacks, true, 0, componentAccessor); - }); + if (hasPermission(playerComponent, "hytale.editor.selection.clipboard")) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + BuilderToolsPlugin.addToQueue( + playerComponent, + playerRef, + (r, s, componentAccessor) -> { + s.select( + this.fromBlockPosition(packet.selectionMin), + this.fromBlockPosition(packet.selectionMax), + "server.builderTools.selectReasons.extrude", + componentAccessor + ); + s.stack(r, new Vector3i(packet.xNormal, packet.yNormal, packet.zNormal), packet.numStacks, true, 0, componentAccessor); + } + ); + } } - }); + ); } else { throw new RuntimeException("Unable to process BuilderToolStackArea packet. Player ref is invalid!"); } @@ -912,11 +928,14 @@ public class BuilderToolsPacketHandler implements SubPacketHandler { if (hasPermission(playerComponent)) { Ref entityReference = world.getEntityStore().getRefFromNetworkId(packet.entityId); if (entityReference != null) { - UUIDComponent uuidComponent = store.getComponent(entityReference, UUIDComponent.getComponentType()); - if (uuidComponent != null) { - UUID uuid = uuidComponent.getUuid(); - String command = packet.enabled ? "npc debug set display --entity " + uuid : "npc debug clear --entity " + uuid; - CommandManager.get().handleCommand(playerComponent, command); + NPCMarkerComponent npcMarker = store.getComponent(entityReference, NPCMarkerComponent.getComponentType()); + if (npcMarker != null) { + UUIDComponent uuidComponent = store.getComponent(entityReference, UUIDComponent.getComponentType()); + if (uuidComponent != null) { + UUID uuid = uuidComponent.getUuid(); + String command = packet.enabled ? "npc debug set display --entity " + uuid : "npc debug clear --entity " + uuid; + CommandManager.get().handleCommand(playerComponent, command); + } } } } @@ -925,4 +944,35 @@ public class BuilderToolsPacketHandler implements SubPacketHandler { throw new RuntimeException("Unable to process BuilderToolSetNPCDebug packet. Player ref is invalid!"); } } + + public void handle(@Nonnull BuilderToolSetEntityCollision packet) { + PlayerRef playerRef = this.packetHandler.getPlayerRef(); + Ref ref = playerRef.getReference(); + if (ref != null && ref.isValid()) { + Store store = ref.getStore(); + World world = store.getExternalData().getWorld(); + world.execute(() -> { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (hasPermission(playerComponent)) { + Ref entityReference = world.getEntityStore().getRefFromNetworkId(packet.entityId); + if (entityReference != null) { + PropComponent propComponent = store.getComponent(entityReference, PropComponent.getComponentType()); + NPCMarkerComponent npcMarker = store.getComponent(entityReference, NPCMarkerComponent.getComponentType()); + if (propComponent != null || npcMarker != null) { + if (packet.collisionType != null && !packet.collisionType.isEmpty()) { + HitboxCollisionConfig hitboxCollisionConfig = HitboxCollisionConfig.getAssetMap().getAsset(packet.collisionType); + if (hitboxCollisionConfig != null) { + store.putComponent(entityReference, HitboxCollision.getComponentType(), new HitboxCollision(hitboxCollisionConfig)); + } + } else { + store.removeComponent(entityReference, HitboxCollision.getComponentType()); + } + } + } + } + }); + } else { + throw new RuntimeException("Unable to process BuilderToolSetEntityCollision packet. Player ref is invalid!"); + } + } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPlugin.java b/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPlugin.java index 68f6ac22..242323af 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPlugin.java +++ b/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPlugin.java @@ -3716,10 +3716,8 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, } if (reason != null) { - Message reasonMessage = Message.translation(reason); this.sendFeedback( - Message.translation("server.builderTools.selectedWithReason") - .param("reason", reasonMessage) + Message.translation(reason) .param("x1", pos1.getX()) .param("y1", pos1.getY()) .param("z1", pos1.getZ()) @@ -4111,6 +4109,17 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, public void save( @Nonnull Ref ref, @Nonnull String name, boolean relativize, boolean overwrite, ComponentAccessor componentAccessor + ) { + this.save(ref, name, relativize, overwrite, false, componentAccessor); + } + + public void save( + @Nonnull Ref ref, + @Nonnull String name, + boolean relativize, + boolean overwrite, + boolean clearSupport, + ComponentAccessor componentAccessor ) { if (this.selection == null) { this.sendErrorFeedback(ref, Message.translation("server.builderTools.noSelection"), componentAccessor); @@ -4127,15 +4136,19 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, } else { try { BlockSelection postClone = relativize ? this.selection.relativize() : this.selection.cloneSelection(); + if (clearSupport) { + postClone.clearAllSupportValues(); + } + prefabStore.saveServerPrefab(name, postClone, overwrite); this.sendUpdate(); this.sendFeedback(Message.translation("server.builderTools.savedSelectionToPrefab").param("name", name), componentAccessor); - } catch (PrefabSaveException var14) { - switch (var14.getType()) { + } catch (PrefabSaveException var15) { + switch (var15.getType()) { case ERROR: - BuilderToolsPlugin.get().getLogger().at(Level.WARNING).withCause(var14).log("Exception saving prefab %s", name); + BuilderToolsPlugin.get().getLogger().at(Level.WARNING).withCause(var15).log("Exception saving prefab %s", name); this.sendFeedback( - Message.translation("server.builderTools.errorSavingPrefab").param("name", name).param("message", var14.getCause().getMessage()), + Message.translation("server.builderTools.errorSavingPrefab").param("name", name).param("message", var15.getCause().getMessage()), componentAccessor ); break; @@ -4164,7 +4177,7 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, boolean includeEmpty, @Nonnull ComponentAccessor componentAccessor ) { - this.saveFromSelection(ref, name, relativize, overwrite, includeEntities, includeEmpty, null, componentAccessor); + this.saveFromSelection(ref, name, relativize, overwrite, includeEntities, includeEmpty, null, false, componentAccessor); } public void saveFromSelection( @@ -4175,6 +4188,7 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, boolean includeEntities, boolean includeEmpty, @Nullable Vector3i playerAnchor, + boolean clearSupport, @Nonnull ComponentAccessor componentAccessor ) { if (this.selection != null && (!this.selection.getSelectionMin().equals(Vector3i.ZERO) || !this.selection.getSelectionMax().equals(Vector3i.ZERO))) { @@ -4272,14 +4286,18 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, try { BlockSelection postClone = relativize ? tempSelection.relativize() : tempSelection.cloneSelection(); + if (clearSupport) { + postClone.clearAllSupportValues(); + } + prefabStore.saveServerPrefab(name, postClone, overwrite); this.sendFeedback(Message.translation("server.builderTools.savedSelectionToPrefab").param("name", name), componentAccessor); - } catch (PrefabSaveException var47) { - switch (var47.getType()) { + } catch (PrefabSaveException var48) { + switch (var48.getType()) { case ERROR: - BuilderToolsPlugin.get().getLogger().at(Level.WARNING).withCause(var47).log("Exception saving prefab %s", name); + BuilderToolsPlugin.get().getLogger().at(Level.WARNING).withCause(var48).log("Exception saving prefab %s", name); this.sendFeedback( - Message.translation("server.builderTools.errorSavingPrefab").param("name", name).param("message", var47.getCause().getMessage()), + Message.translation("server.builderTools.errorSavingPrefab").param("name", name).param("message", var48.getCause().getMessage()), componentAccessor ); break; diff --git a/src/com/hypixel/hytale/builtin/buildertools/commands/PrefabCommand.java b/src/com/hypixel/hytale/builtin/buildertools/commands/PrefabCommand.java index d2ff071a..2923e11d 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/commands/PrefabCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/commands/PrefabCommand.java @@ -321,6 +321,8 @@ public class PrefabCommand extends AbstractCommandCollection { private final FlagArg emptyFlag = this.withFlagArg("empty", "server.commands.prefab.save.empty.desc"); @Nonnull private final FlagArg playerAnchorFlag = this.withFlagArg("playerAnchor", "server.commands.prefab.save.playerAnchor.desc"); + @Nonnull + private final FlagArg clearSupportFlag = this.withFlagArg("clearSupport", "server.commands.editprefab.save.clearSupport.desc"); public PrefabSaveDirectCommand() { super("server.commands.prefab.save.desc"); @@ -338,11 +340,12 @@ public class PrefabCommand extends AbstractCommandCollection { boolean overwrite = this.overwriteFlag.get(context); boolean entities = this.entitiesFlag.get(context); boolean empty = this.emptyFlag.get(context); + boolean clearSupport = this.clearSupportFlag.get(context); Vector3i playerAnchor = this.getPlayerAnchor(ref, store, this.playerAnchorFlag.get(context)); BuilderToolsPlugin.addToQueue( playerComponent, playerRef, - (r, s, componentAccessor) -> s.saveFromSelection(r, name, true, overwrite, entities, empty, playerAnchor, componentAccessor) + (r, s, componentAccessor) -> s.saveFromSelection(r, name, true, overwrite, entities, empty, playerAnchor, clearSupport, componentAccessor) ); } diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabEditSession.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabEditSession.java index 21d9226d..64dcd066 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabEditSession.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabEditSession.java @@ -21,7 +21,7 @@ import com.hypixel.hytale.server.core.prefab.selection.standard.BlockSelection; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.util.PositionUtil; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.nio.file.Path; import java.util.Map; @@ -252,13 +252,8 @@ public class PrefabEditSession implements Resource { public static MapMarker createPrefabMarker(@Nonnull PrefabEditingMetadata metadata) { String fileName = metadata.getPrefabPath().getFileName().toString(); String prefabName = fileName.replace(".prefab.json", ""); - return new MapMarker( - "prefab-" + metadata.getUuid(), - prefabName, - "Prefab.png", - PositionUtil.toTransformPacket(new Transform(metadata.getAnchorEntityPosition().toVector3d())), - null - ); + Transform transform = new Transform(metadata.getAnchorEntityPosition()); + return new MapMarkerBuilder("prefab-" + metadata.getUuid(), "Prefab.png", transform).withCustomName(prefabName).build(); } @Nonnull diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabEditSessionManager.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabEditSessionManager.java index c6b8e9ce..dbf34010 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabEditSessionManager.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabEditSessionManager.java @@ -105,35 +105,34 @@ public class PrefabEditSessionManager { private void onPlayerReady(@Nonnull PlayerReadyEvent event) { Ref playerRef = event.getPlayer().getReference(); + if (playerRef != null && playerRef.isValid()) { + Store store = playerRef.getStore(); + World world = store.getExternalData().getWorld(); + world.execute(() -> { + UUIDComponent uuidComponent = store.getComponent(playerRef, UUIDComponent.getComponentType()); - assert playerRef != null && !playerRef.isValid(); + assert uuidComponent != null; - Store store = playerRef.getStore(); - World world = store.getExternalData().getWorld(); - world.execute(() -> { - UUIDComponent uuidComponent = store.getComponent(playerRef, UUIDComponent.getComponentType()); + UUID playerUUID = uuidComponent.getUuid(); + if (this.inProgressTeleportations.containsKey(playerUUID)) { + this.inProgressTeleportations.remove(playerUUID); + MovementStatesComponent movementStatesComponent = store.getComponent(playerRef, MovementStatesComponent.getComponentType()); - assert uuidComponent != null; + assert movementStatesComponent != null; - UUID playerUUID = uuidComponent.getUuid(); - if (this.inProgressTeleportations.containsKey(playerUUID)) { - this.inProgressTeleportations.remove(playerUUID); - MovementStatesComponent movementStatesComponent = store.getComponent(playerRef, MovementStatesComponent.getComponentType()); + MovementStates movementStates = movementStatesComponent.getMovementStates(); + Player playerComponent = store.getComponent(playerRef, Player.getComponentType()); - assert movementStatesComponent != null; + assert playerComponent != null; - MovementStates movementStates = movementStatesComponent.getMovementStates(); - Player playerComponent = store.getComponent(playerRef, Player.getComponentType()); - - assert playerComponent != null; - - playerComponent.applyMovementStates(playerRef, new SavedMovementStates(true), movementStates, store); - PlayerRef playerRefComponent = store.getComponent(playerRef, PlayerRef.getComponentType()); - if (playerRefComponent != null) { - this.givePrefabSelectorTool(playerComponent, playerRefComponent); + playerComponent.applyMovementStates(playerRef, new SavedMovementStates(true), movementStates, store); + PlayerRef playerRefComponent = store.getComponent(playerRef, PlayerRef.getComponentType()); + if (playerRefComponent != null) { + this.givePrefabSelectorTool(playerComponent, playerRefComponent); + } } - } - }); + }); + } } private void givePrefabSelectorTool(@Nonnull Player playerComponent, @Nonnull PlayerRef playerRef) { diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabMarkerProvider.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabMarkerProvider.java index 5751f6ef..7859101a 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabMarkerProvider.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/PrefabMarkerProvider.java @@ -5,21 +5,20 @@ import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import javax.annotation.Nonnull; public class PrefabMarkerProvider implements WorldMapManager.MarkerProvider { public static final PrefabMarkerProvider INSTANCE = new PrefabMarkerProvider(); @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { PrefabEditSessionManager sessionManager = BuilderToolsPlugin.get().getPrefabEditSessionManager(); - Player player = tracker.getPlayer(); PrefabEditSession session = sessionManager.getPrefabEditSession(player.getUuid()); if (session != null && session.getWorldName().equals(world.getName())) { for (PrefabEditingMetadata metadata : session.getLoadedPrefabMetadata().values()) { MapMarker marker = PrefabEditSession.createPrefabMarker(metadata); - tracker.trySendMarker(chunkViewRadius, playerChunkX, playerChunkZ, marker); + collector.add(marker); } } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveAsCommand.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveAsCommand.java index 1e047723..5142c349 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveAsCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveAsCommand.java @@ -41,6 +41,7 @@ public class PrefabEditSaveAsCommand extends AbstractAsyncPlayerCommand { private final FlagArg overwriteArg = this.withFlagArg("overwrite", "server.commands.editprefab.save.overwrite.desc"); private final FlagArg emptyArg = this.withFlagArg("empty", "server.commands.editprefab.save.empty.desc"); private final FlagArg noUpdateArg = this.withFlagArg("noUpdate", "server.commands.editprefab.saveAs.noUpdate.desc"); + private final FlagArg clearSupportArg = this.withFlagArg("clearSupport", "server.commands.editprefab.save.clearSupport.desc"); public PrefabEditSaveAsCommand() { super("saveas", "server.commands.editprefab.saveAs.desc"); @@ -67,6 +68,7 @@ public class PrefabEditSaveAsCommand extends AbstractAsyncPlayerCommand { prefabSaverSettings.setEntities(!this.noEntitiesArg.provided(context)); prefabSaverSettings.setOverwriteExisting(this.overwriteArg.get(context)); prefabSaverSettings.setEmpty(this.emptyArg.get(context)); + prefabSaverSettings.setClearSupportValues(this.clearSupportArg.get(context)); Path prefabRootPath = this.prefabPathArg.get(context).getPrefabPath(); if (!PathUtil.isChildOf(prefabRootPath, prefabRootPath.resolve(this.fileNameArg.get(context))) && !SingleplayerModule.isOwner(playerRef)) { context.sendMessage(Message.translation("server.builderTools.attemptedToSaveOutsidePrefabsDir")); diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveCommand.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveCommand.java index 4e30f9d6..7c36eade 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveCommand.java @@ -39,6 +39,8 @@ public class PrefabEditSaveCommand extends AbstractAsyncPlayerCommand { private final FlagArg emptyArg = this.withFlagArg("empty", "server.commands.editprefab.save.empty.desc"); @Nonnull private final FlagArg confirmArg = this.withFlagArg("confirm", "server.commands.editprefab.save.confirm.desc"); + @Nonnull + private final FlagArg clearSupportArg = this.withFlagArg("clearSupport", "server.commands.editprefab.save.clearSupport.desc"); private static boolean isPathInAllowedPrefabDirectory(@Nonnull Path path) { PrefabStore prefabStore = PrefabStore.get(); @@ -71,6 +73,7 @@ public class PrefabEditSaveCommand extends AbstractAsyncPlayerCommand { prefabSaverSettings.setEntities(!this.noEntitiesArg.provided(context)); prefabSaverSettings.setOverwriteExisting(true); prefabSaverSettings.setEmpty(this.emptyArg.get(context)); + prefabSaverSettings.setClearSupportValues(this.clearSupportArg.get(context)); boolean confirm = this.confirmArg.provided(context); if (!this.saveAllArg.provided(context)) { PrefabEditingMetadata selectedPrefab = prefabEditSession.getSelectedPrefab(playerRef.getUuid()); diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/saving/PrefabSaver.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/saving/PrefabSaver.java index ca44c8ed..94980768 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/saving/PrefabSaver.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/saving/PrefabSaver.java @@ -190,16 +190,8 @@ public class PrefabSaver { } } - selection.addBlockAtWorldPos( - x, - y, - z, - block, - sectionComponent.getRotationIndex(x, y, z), - filler, - blockPhysicsComponent != null ? blockPhysicsComponent.get(x, y, z) : 0, - holder - ); + int supportValue = settings.isClearSupportValues() ? 0 : (blockPhysicsComponent != null ? blockPhysicsComponent.get(x, y, z) : 0); + selection.addBlockAtWorldPos(x, y, z, block, sectionComponent.getRotationIndex(x, y, z), filler, supportValue, holder); blockCount++; } diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/saving/PrefabSaverSettings.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/saving/PrefabSaverSettings.java index d207fbb7..26dbbd00 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/saving/PrefabSaverSettings.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/saving/PrefabSaverSettings.java @@ -7,6 +7,7 @@ public class PrefabSaverSettings { private boolean blocks; private boolean entities; private boolean keepAnchors; + private boolean clearSupportValues; public boolean isRelativize() { return this.relativize; @@ -55,4 +56,12 @@ public class PrefabSaverSettings { public void setKeepAnchors(boolean keepAnchors) { this.keepAnchors = keepAnchors; } + + public boolean isClearSupportValues() { + return this.clearSupportValues; + } + + public void setClearSupportValues(boolean clearSupportValues) { + this.clearSupportValues = clearSupportValues; + } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/ui/PrefabEditorSaveSettingsPage.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/ui/PrefabEditorSaveSettingsPage.java index 170a78a6..ff06fc8d 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/ui/PrefabEditorSaveSettingsPage.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/ui/PrefabEditorSaveSettingsPage.java @@ -75,6 +75,7 @@ public class PrefabEditorSaveSettingsPage extends InteractiveCustomUIPage prefabsToSave = new ObjectArrayList<>(); @@ -496,6 +499,7 @@ public class PrefabEditorSaveSettingsPage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder( @@ -515,6 +519,8 @@ public class PrefabEditorSaveSettingsPage extends InteractiveCustomUIPage("@Overwrite", Codec.BOOLEAN), (o, overwrite) -> o.overwrite = overwrite, o -> o.overwrite) .add() + .append(new KeyedCodec<>("@ClearSupport", Codec.BOOLEAN), (o, clearSupport) -> o.clearSupport = clearSupport, o -> o.clearSupport) + .add() .append(new KeyedCodec<>("@BrowserSearch", Codec.STRING), (o, browserSearchStr) -> o.browserSearchStr = browserSearchStr, o -> o.browserSearchStr) .add() .append(new KeyedCodec<>("PrefabUuid", Codec.STRING), (o, prefabUuid) -> o.prefabUuid = prefabUuid, o -> o.prefabUuid) @@ -525,6 +531,7 @@ public class PrefabEditorSaveSettingsPage extends InteractiveCustomUIPage { if (data.fromClipboard) { - s.save(r, data.name, true, data.overwrite, componentAccessor); + s.save(r, data.name, true, data.overwrite, data.clearSupport, componentAccessor); } else { - s.saveFromSelection(r, data.name, true, data.overwrite, data.entities, data.empty, playerAnchor, componentAccessor); + s.saveFromSelection(r, data.name, true, data.overwrite, data.entities, data.empty, playerAnchor, data.clearSupport, componentAccessor); } }); break; @@ -113,6 +115,7 @@ public class PrefabSavePage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder(PrefabSavePage.PageData.class, PrefabSavePage.PageData::new) .append( new KeyedCodec<>("Action", new EnumCodec<>(PrefabSavePage.Action.class, EnumCodec.EnumStyle.LEGACY)), @@ -132,6 +135,8 @@ public class PrefabSavePage extends InteractiveCustomUIPage("@UsePlayerAnchor", Codec.BOOLEAN), (o, usePlayerAnchor) -> o.usePlayerAnchor = usePlayerAnchor, o -> o.usePlayerAnchor) .add() + .append(new KeyedCodec<>("@ClearSupport", Codec.BOOLEAN), (o, clearSupport) -> o.clearSupport = clearSupport, o -> o.clearSupport) + .add() .build(); public PrefabSavePage.Action action; public String name; @@ -140,6 +145,7 @@ public class PrefabSavePage extends InteractiveCustomUIPage numStepsArg = this.withDefaultArg( - "steps", "The number of operations to step through", ArgTypes.INTEGER, 1, "A single step" + "steps", "server.commands.scriptedbrushes.step.steps.desc", ArgTypes.INTEGER, 1, "server.commands.scriptedbrushes.step.steps.default" ) .addValidator(Validators.range(1, 100)); public BrushConfigDebugStepCommand() { - super("step", "Advance one or more steps into your order of operations brush config debug"); + super("step", "server.commands.scriptedbrushes.step.desc"); } @Override diff --git a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigExitCommand.java b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigExitCommand.java index 878e3c2b..805e995c 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigExitCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigExitCommand.java @@ -13,7 +13,7 @@ import javax.annotation.Nonnull; public class BrushConfigExitCommand extends AbstractPlayerCommand { public BrushConfigExitCommand() { - super("exit", "Exit a running debug state or stop an incomplete execution"); + super("exit", "server.commands.scriptedbrushes.exit.desc"); } @Override diff --git a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigListCommand.java b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigListCommand.java index ab4305fd..58cf544e 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigListCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigListCommand.java @@ -22,7 +22,7 @@ import javax.annotation.Nonnull; public class BrushConfigListCommand extends AbstractPlayerCommand { public BrushConfigListCommand() { - super("list", "List the brush config operations that are currently set"); + super("list", "server.commands.scriptedbrushes.list.desc"); } @Override diff --git a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigLoadCommand.java b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigLoadCommand.java index badc828b..46ba518c 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigLoadCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/commands/BrushConfigLoadCommand.java @@ -27,7 +27,7 @@ public class BrushConfigLoadCommand extends AbstractPlayerCommand { ); public BrushConfigLoadCommand() { - super("load", "Load a scripted brush by name, or open the brush picker UI if no name is provided"); + super("load", "server.commands.scriptedbrushes.load.desc"); this.addUsageVariant(new BrushConfigLoadCommand.LoadByNameCommand()); } @@ -57,14 +57,14 @@ public class BrushConfigLoadCommand extends AbstractPlayerCommand { @Nonnull private final RequiredArg brushNameArg = this.withRequiredArg( "brushName", - "The name of the scripted brush asset to load", + "server.commands.scriptedbrushes.load.brushName.desc", new AssetArgumentType( "server.commands.parsing.argtype.asset.scriptedbrush.name", ScriptedBrushAsset.class, "server.commands.parsing.argtype.asset.scriptedbrush.usage" ) ); public LoadByNameCommand() { - super("Load a scripted brush by name"); + super("server.commands.scriptedbrushes.load.byName.desc"); } @Override diff --git a/src/com/hypixel/hytale/builtin/commandmacro/EchoCommand.java b/src/com/hypixel/hytale/builtin/commandmacro/EchoCommand.java index 3703f082..bfcd8eab 100644 --- a/src/com/hypixel/hytale/builtin/commandmacro/EchoCommand.java +++ b/src/com/hypixel/hytale/builtin/commandmacro/EchoCommand.java @@ -8,10 +8,10 @@ import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase; import javax.annotation.Nonnull; public class EchoCommand extends CommandBase { - private final RequiredArg messageArg = this.withRequiredArg("message", "The message to send to the user of this command", ArgTypes.STRING); + private final RequiredArg messageArg = this.withRequiredArg("message", "server.commands.echos.message.desc", ArgTypes.STRING); public EchoCommand() { - super("echo", "Echos the text you input to the user"); + super("echo", "server.commands.echos.desc"); } @Override diff --git a/src/com/hypixel/hytale/builtin/crafting/interaction/OpenBenchPageInteraction.java b/src/com/hypixel/hytale/builtin/crafting/interaction/OpenBenchPageInteraction.java index 30352943..956bc48e 100644 --- a/src/com/hypixel/hytale/builtin/crafting/interaction/OpenBenchPageInteraction.java +++ b/src/com/hypixel/hytale/builtin/crafting/interaction/OpenBenchPageInteraction.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.builtin.crafting.interaction; import com.hypixel.hytale.builtin.crafting.component.CraftingManager; import com.hypixel.hytale.builtin.crafting.state.BenchState; -import com.hypixel.hytale.builtin.crafting.window.BenchWindow; +import com.hypixel.hytale.builtin.crafting.window.CraftingWindow; import com.hypixel.hytale.builtin.crafting.window.DiagramCraftingWindow; import com.hypixel.hytale.builtin.crafting.window.SimpleCraftingWindow; import com.hypixel.hytale.builtin.crafting.window.StructuralCraftingWindow; @@ -82,19 +82,17 @@ public class OpenBenchPageInteraction extends SimpleBlockInteraction { Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType()); if (playerComponent != null) { CraftingManager craftingManagerComponent = commandBuffer.getComponent(ref, CraftingManager.getComponentType()); - - assert craftingManagerComponent != null; - - if (!craftingManagerComponent.hasBenchSet()) { + if (craftingManagerComponent != null && !craftingManagerComponent.hasBenchSet()) { if (world.getState(targetBlock.x, targetBlock.y, targetBlock.z, true) instanceof BenchState benchState) { - BenchWindow benchWindow = (BenchWindow)(switch (this.pageType) { + CraftingWindow benchWindow = (CraftingWindow)(switch (this.pageType) { case SIMPLE_CRAFTING -> new SimpleCraftingWindow(benchState); case DIAGRAM_CRAFTING -> new DiagramCraftingWindow(ref, commandBuffer, benchState); case STRUCTURAL_CRAFTING -> new StructuralCraftingWindow(benchState); }); UUIDComponent uuidComponent = commandBuffer.getComponent(ref, UUIDComponent.getComponentType()); - - assert uuidComponent != null; + if (uuidComponent == null) { + return; + } UUID uuid = uuidComponent.getUuid(); if (benchState.getWindows().putIfAbsent(uuid, benchWindow) == null) { @@ -113,7 +111,7 @@ public class OpenBenchPageInteraction extends SimpleBlockInteraction { ) { } - private static enum PageType { + public static enum PageType { SIMPLE_CRAFTING, DIAGRAM_CRAFTING, STRUCTURAL_CRAFTING; diff --git a/src/com/hypixel/hytale/builtin/crafting/interaction/OpenProcessingBenchInteraction.java b/src/com/hypixel/hytale/builtin/crafting/interaction/OpenProcessingBenchInteraction.java index 7596b7c2..9d7653d9 100644 --- a/src/com/hypixel/hytale/builtin/crafting/interaction/OpenProcessingBenchInteraction.java +++ b/src/com/hypixel/hytale/builtin/crafting/interaction/OpenProcessingBenchInteraction.java @@ -70,36 +70,37 @@ public class OpenProcessingBenchInteraction extends SimpleBlockInteraction { world.getChunk(ChunkUtil.indexChunkFromBlock(x, z)).setState(x, pos.getY(), z, (BlockState)null); } else { UUIDComponent uuidComponent = commandBuffer.getComponent(ref, UUIDComponent.getComponentType()); + if (uuidComponent != null) { + UUID uuid = uuidComponent.getUuid(); + ProcessingBenchWindow window = new ProcessingBenchWindow(benchState); + Map windows = benchState.getWindows(); + if (windows.putIfAbsent(uuid, window) == null) { + benchState.updateFuelValues(); + if (playerComponent.getPageManager().setPageWithWindows(ref, store, Page.Bench, true, window)) { + window.registerCloseEvent(event -> { + windows.remove(uuid, window); + BlockType currentBlockType = world.getBlockType(pos); + if (currentBlockType != null) { + String interactionState = BlockAccessor.getCurrentInteractionState(currentBlockType); + if (windows.isEmpty() && !"Processing".equals(interactionState) && !"ProcessCompleted".equals(interactionState)) { + world.setBlockInteractionState(pos, currentBlockType, "default"); + } - assert uuidComponent != null; + int soundEventIndexx = blockType.getBench().getLocalCloseSoundEventIndex(); + if (soundEventIndexx != 0) { + SoundUtil.playSoundEvent2d(ref, soundEventIndexx, SoundCategory.UI, commandBuffer); + } + } + }); + int soundEventIndex = blockType.getBench().getLocalOpenSoundEventIndex(); + if (soundEventIndex == 0) { + return; + } - UUID uuid = uuidComponent.getUuid(); - ProcessingBenchWindow window = new ProcessingBenchWindow(benchState); - Map windows = benchState.getWindows(); - if (windows.putIfAbsent(uuid, window) == null) { - benchState.updateFuelValues(); - if (playerComponent.getPageManager().setPageWithWindows(ref, store, Page.Bench, true, window)) { - window.registerCloseEvent(event -> { + SoundUtil.playSoundEvent2d(ref, soundEventIndex, SoundCategory.UI, commandBuffer); + } else { windows.remove(uuid, window); - BlockType currentBlockType = world.getBlockType(pos); - String interactionState = BlockAccessor.getCurrentInteractionState(currentBlockType); - if (windows.isEmpty() && !"Processing".equals(interactionState) && !"ProcessCompleted".equals(interactionState)) { - world.setBlockInteractionState(pos, currentBlockType, "default"); - } - - int soundEventIndexx = blockType.getBench().getLocalCloseSoundEventIndex(); - if (soundEventIndexx != 0) { - SoundUtil.playSoundEvent2d(ref, soundEventIndexx, SoundCategory.UI, commandBuffer); - } - }); - int soundEventIndex = blockType.getBench().getLocalOpenSoundEventIndex(); - if (soundEventIndex == 0) { - return; } - - SoundUtil.playSoundEvent2d(ref, soundEventIndex, SoundCategory.UI, commandBuffer); - } else { - windows.remove(uuid, window); } } } diff --git a/src/com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.java b/src/com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.java index 726d4f3c..e6fc1390 100644 --- a/src/com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.java +++ b/src/com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.java @@ -21,8 +21,6 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3f; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.SoundCategory; -import com.hypixel.hytale.protocol.Transform; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.server.core.asset.type.blockhitbox.BlockBoundingBoxes; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple; @@ -30,7 +28,6 @@ import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.BenchTie import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.ProcessingBench; import com.hypixel.hytale.server.core.asset.type.item.config.CraftingRecipe; import com.hypixel.hytale.server.core.asset.type.item.config.Item; -import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.inventory.MaterialQuantity; import com.hypixel.hytale.server.core.inventory.ResourceQuantity; @@ -47,7 +44,6 @@ import com.hypixel.hytale.server.core.inventory.transaction.ListTransaction; import com.hypixel.hytale.server.core.inventory.transaction.MaterialSlotTransaction; import com.hypixel.hytale.server.core.inventory.transaction.MaterialTransaction; import com.hypixel.hytale.server.core.inventory.transaction.ResourceTransaction; -import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entity.item.ItemComponent; import com.hypixel.hytale.server.core.universe.world.SoundUtil; import com.hypixel.hytale.server.core.universe.world.World; @@ -56,12 +52,9 @@ import com.hypixel.hytale.server.core.universe.world.chunk.state.TickableBlockSt import com.hypixel.hytale.server.core.universe.world.meta.BlockState; import com.hypixel.hytale.server.core.universe.world.meta.state.DestroyableBlockState; import com.hypixel.hytale.server.core.universe.world.meta.state.ItemContainerBlockState; -import com.hypixel.hytale.server.core.universe.world.meta.state.MarkerBlockState; import com.hypixel.hytale.server.core.universe.world.meta.state.PlacedByBlockState; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.util.PositionUtil; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.Collections; @@ -70,20 +63,13 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; -import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.bson.BsonDocument; -public class ProcessingBenchState - extends BenchState - implements TickableBlockState, - ItemContainerBlockState, - DestroyableBlockState, - MarkerBlockState, - PlacedByBlockState { +public class ProcessingBenchState extends BenchState implements TickableBlockState, ItemContainerBlockState, DestroyableBlockState, PlacedByBlockState { public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static final boolean EXACT_RESOURCE_AMOUNTS = true; public static final Codec CODEC = BuilderCodec.builder(ProcessingBenchState.class, ProcessingBenchState::new, BenchState.CODEC) @@ -101,8 +87,6 @@ public class ProcessingBenchState .add() .append(new KeyedCodec<>("NextExtra", Codec.INTEGER), (state, b) -> state.nextExtra = b, state -> state.nextExtra) .add() - .append(new KeyedCodec<>("Marker", WorldMapManager.MarkerReference.CODEC), (state, o) -> state.marker = o, state -> state.marker) - .add() .append(new KeyedCodec<>("RecipeId", Codec.STRING), (state, o) -> state.recipeId = o, state -> state.recipeId) .add() .build(); @@ -111,7 +95,6 @@ public class ProcessingBenchState private static final float EJECT_VERTICAL_VELOCITY = 3.25F; public static final String PROCESSING = "Processing"; public static final String PROCESS_COMPLETED = "ProcessCompleted"; - protected WorldMapManager.MarkerReference marker; private ProcessingBench processingBench; private ItemContainer inputContainer; private ItemContainer fuelContainer; @@ -647,10 +630,6 @@ public class ProcessingBenchState world.execute(() -> entityStore.addEntities(itemEntityHolders, AddReason.SPAWN)); } } - - if (this.marker != null) { - this.marker.remove(); - } } public CombinedItemContainer getItemContainer() { @@ -775,12 +754,6 @@ public class ProcessingBenchState this.getChunk().setBlockInteractionState(this.getBlockPosition(), blockType, state); } - @Override - public void setMarker(WorldMapManager.MarkerReference marker) { - this.marker = marker; - this.markNeedsSave(); - } - @Override public void placedBy( @Nonnull Ref playerRef, @@ -788,28 +761,6 @@ public class ProcessingBenchState @Nonnull BlockState blockState, @Nonnull ComponentAccessor componentAccessor ) { - if (blockTypeKey.equals(this.processingBench.getIconItem()) && this.processingBench.getIcon() != null) { - Player playerComponent = componentAccessor.getComponent(playerRef, Player.getComponentType()); - - assert playerComponent != null; - - TransformComponent transformComponent = componentAccessor.getComponent(playerRef, TransformComponent.getComponentType()); - - assert transformComponent != null; - - Transform transformPacket = PositionUtil.toTransformPacket(transformComponent.getTransform()); - transformPacket.orientation.yaw = 0.0F; - transformPacket.orientation.pitch = 0.0F; - transformPacket.orientation.roll = 0.0F; - MapMarker marker = new MapMarker( - this.processingBench.getIconId() + "-" + UUID.randomUUID(), - this.processingBench.getIconName(), - this.processingBench.getIcon(), - transformPacket, - null - ); - ((MarkerBlockState)blockState).setMarker(WorldMapManager.createPlayerMarker(playerRef, marker, componentAccessor)); - } } private void playSound(@Nonnull World world, int soundEventIndex, @Nonnull ComponentAccessor componentAccessor) { diff --git a/src/com/hypixel/hytale/builtin/fluid/FluidCommand.java b/src/com/hypixel/hytale/builtin/fluid/FluidCommand.java index 0d00c3d1..769b5241 100644 --- a/src/com/hypixel/hytale/builtin/fluid/FluidCommand.java +++ b/src/com/hypixel/hytale/builtin/fluid/FluidCommand.java @@ -30,7 +30,7 @@ public class FluidCommand extends AbstractCommandCollection { private static final SingleArgumentType FLUID_ARG = new AssetArgumentType("Fluid", Fluid.class, ""); public FluidCommand() { - super("fluid", "Fluid debug commands"); + super("fluid", "server.commands.fluid.desc"); this.addSubCommand(new FluidCommand.SetCommand()); this.addSubCommand(new FluidCommand.GetCommand()); this.addSubCommand(new FluidCommand.SetRadiusCommand()); @@ -45,7 +45,7 @@ public class FluidCommand extends AbstractCommandCollection { private final OptionalArg targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION); public GetCommand() { - super("get", "Gets the fluid at the target position"); + super("get", "server.commands.fluid.get.desc"); } @Override @@ -101,7 +101,7 @@ public class FluidCommand extends AbstractCommandCollection { private final OptionalArg targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION); public SetCommand() { - super("set", "Changes the fluid at the target position"); + super("set", "server.commands.fluid.set.desc"); } @Override @@ -172,7 +172,7 @@ public class FluidCommand extends AbstractCommandCollection { private final OptionalArg targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION); public SetRadiusCommand() { - super("setradius", "Changes the fluid at the player position in a given radius"); + super("setradius", "server.commands.fluid.setradius.desc"); } @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/Indexer.java b/src/com/hypixel/hytale/builtin/hytalegenerator/Indexer.java deleted file mode 100644 index 99ed4a11..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/Indexer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator; - -import java.util.HashMap; -import java.util.Map; - -public class Indexer { - private Map ids = new HashMap<>(); - - public int getIdFor(Object o) { - return this.ids.computeIfAbsent(o, k -> this.ids.size()); - } - - public int size() { - return this.ids.size(); - } -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/Registry.java b/src/com/hypixel/hytale/builtin/hytalegenerator/Registry.java new file mode 100644 index 00000000..f72b0a48 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/Registry.java @@ -0,0 +1,42 @@ +package com.hypixel.hytale.builtin.hytalegenerator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import javax.annotation.Nonnull; + +public class Registry { + private Map objectToId = new HashMap<>(); + private Map idToObject = new HashMap<>(); + + public int getIdOrRegister(T object) { + Integer id = this.objectToId.get(object); + if (id != null) { + return id; + } else { + id = this.objectToId.size(); + this.idToObject.put(id, object); + this.objectToId.put(object, id); + return id; + } + } + + public T getObject(int id) { + return this.idToObject.get(id); + } + + public int size() { + return this.objectToId.size(); + } + + @Nonnull + public List getAllValues() { + return new ArrayList<>(this.idToObject.values()); + } + + public void forEach(@Nonnull BiConsumer consumer) { + this.idToObject.forEach(consumer::accept); + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/ReusableList.java b/src/com/hypixel/hytale/builtin/hytalegenerator/ReusableList.java new file mode 100644 index 00000000..cb1ff6ed --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/ReusableList.java @@ -0,0 +1,57 @@ +package com.hypixel.hytale.builtin.hytalegenerator; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; + +public class ReusableList { + private final List data = new ArrayList<>(0); + private int softSize = 0; + + public void expandAndSet(T element) { + if (this.isAtHardCapacity()) { + this.data.add(element); + } else { + this.data.set(this.softSize, element); + } + + this.softSize++; + } + + @Nullable + public T expandAndGet() { + if (this.isAtHardCapacity()) { + this.data.add(null); + return null; + } else { + T result = this.data.get(this.softSize); + this.softSize++; + return result; + } + } + + public int getSoftSize() { + return this.softSize; + } + + public int getHardSize() { + return this.data.size(); + } + + public boolean isAtHardCapacity() { + return this.softSize == this.data.size(); + } + + @Nullable + public T get(int index) { + if (index >= this.softSize) { + throw new IndexOutOfBoundsException(); + } else { + return this.data.get(index); + } + } + + public void clear() { + this.softSize = 0; + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/VectorUtil.java b/src/com/hypixel/hytale/builtin/hytalegenerator/VectorUtil.java index c736224c..f129b8a3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/VectorUtil.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/VectorUtil.java @@ -29,15 +29,24 @@ public class VectorUtil { return nearestPoint.distanceTo(pointVec); } - public static double distanceToLine3d(@Nonnull Vector3d point, @Nonnull Vector3d p0, @Nonnull Vector3d p1) { - Vector3d lineVec = p1.clone().addScaled(p0, -1.0); - Vector3d pointVec = point.clone().addScaled(p0, -1.0); - double lineLength = lineVec.length(); - Vector3d lineUnitVec = lineVec.clone().setLength(1.0); - Vector3d pointVecScaled = pointVec.clone().scale(1.0 / lineLength); - double t = lineUnitVec.dot(pointVecScaled); - Vector3d nearestPoint = lineVec.clone().scale(t); - return nearestPoint.distanceTo(pointVec); + public static double distanceToLine3d( + @Nonnull Vector3d point, + @Nonnull Vector3d p0, + @Nonnull Vector3d p1, + @Nonnull Vector3d rLineVec, + @Nonnull Vector3d rPointVec, + @Nonnull Vector3d rLineUnitVec, + @Nonnull Vector3d rPointVecScaled, + @Nonnull Vector3d rNearestPoint + ) { + rLineVec.assign(p1).subtract(p0); + rPointVec.assign(point).subtract(p0); + double lineLength = rLineVec.length(); + rLineUnitVec.assign(rLineVec).setLength(1.0); + rPointVecScaled.assign(rPointVec).scale(1.0 / lineLength); + double t = rLineUnitVec.dot(rPointVecScaled); + rNearestPoint.assign(rLineVec).scale(t); + return rNearestPoint.distanceTo(rPointVec); } @Nonnull @@ -54,15 +63,24 @@ public class VectorUtil { } @Nonnull - public static Vector3d nearestPointOnLine3d(@Nonnull Vector3d point, @Nonnull Vector3d p0, @Nonnull Vector3d p1) { - Vector3d lineVec = p1.clone().addScaled(p0, -1.0); - Vector3d pointVec = point.clone().addScaled(p0, -1.0); - double lineLength = lineVec.length(); - Vector3d lineUnitVec = lineVec.clone().setLength(1.0); - Vector3d pointVecScaled = pointVec.clone().scale(1.0 / lineLength); - double t = lineUnitVec.dot(pointVecScaled); - Vector3d nearestPoint = lineVec.clone().scale(t); - return nearestPoint.add(p0); + public static void nearestPointOnLine3d( + @Nonnull Vector3d point, + @Nonnull Vector3d p0, + @Nonnull Vector3d p1, + @Nonnull Vector3d vector_out, + @Nonnull Vector3d rLineVec, + @Nonnull Vector3d rPointVec, + @Nonnull Vector3d rLineUnitVec, + @Nonnull Vector3d rPointVecScaled + ) { + rLineVec.assign(p1).subtract(p0); + rPointVec.assign(point).subtract(p0); + double lineLength = rLineVec.length(); + rLineUnitVec.assign(rLineVec).setLength(1.0); + rPointVecScaled.assign(rPointVec).scale(1.0 / lineLength); + double t = rLineUnitVec.dot(rPointVecScaled); + vector_out.assign(rLineVec).scale(t); + vector_out.add(p0); } public static boolean[] shortestSegmentBetweenTwoSegments( @@ -163,87 +181,6 @@ public class VectorUtil { } } - public static double shortestDistanceBetweenTwoSegments( - @Nonnull Vector3d a0, @Nonnull Vector3d a1, @Nonnull Vector3d b0, @Nonnull Vector3d b1, boolean clamp - ) { - Vector3d A = a1.clone().addScaled(a0, -1.0); - Vector3d B = b1.clone().addScaled(b0, -1.0); - double magA = A.length(); - double magB = B.length(); - Vector3d _A = A.clone().scale(1.0 / magA); - Vector3d _B = B.clone().scale(1.0 / magB); - Vector3d cross = _A.cross(_B); - double denom = Math.pow(cross.length(), 2.0); - if (denom == 0.0) { - double d0 = _A.dot(b0.clone().addScaled(a0, -1.0)); - if (clamp) { - double d1 = _A.dot(b1.clone().addScaled(a0, -1.0)); - if (d0 <= 0.0 && d1 <= 0.0) { - if (Math.abs(d0) < Math.abs(d1)) { - return a0.distanceTo(b0); - } - - return a0.distanceTo(b1); - } - - if (d0 >= magA && d1 >= magA) { - if (Math.abs(d0) < Math.abs(d1)) { - return a1.distanceTo(b0); - } - - return a1.distanceTo(b1); - } - } - - return distanceToLine3d(a0, b0, b1); - } else { - Vector3d t = b0.clone().addScaled(a0, -1.0); - double detA = determinant(t, _B, cross); - double detB = determinant(t, _A, cross); - double t0 = detA / denom; - double t1 = detB / denom; - Vector3d pA = _A.clone().scale(t0).add(a0); - Vector3d pB = _B.clone().scale(t1).add(b0); - if (clamp) { - if (t0 < 0.0) { - pA = a0.clone(); - } else if (t0 > magA) { - pA = a1.clone(); - } - - if (t1 < 0.0) { - pB = b0.clone(); - } else if (t1 > magB) { - pB = b1.clone(); - } - - if (t0 < 0.0 || t0 > magA) { - double dot = _B.dot(pA.clone().addScaled(b0, -1.0)); - if (dot < 0.0) { - dot = 0.0; - } else if (dot > magB) { - dot = magB; - } - - pB = b0.clone().add(_B.clone().scale(dot)); - } - - if (t1 < 0.0 || t1 > magA) { - double dot = _A.dot(pB.clone().addScaled(a0, -1.0)); - if (dot < 0.0) { - dot = 0.0; - } else if (dot > magA) { - dot = magA; - } - - pA = a0.clone().add(_A.clone().scale(dot)); - } - } - - return pA.distanceTo(pB); - } - } - public static double determinant(@Nonnull Vector3d v1, @Nonnull Vector3d v2) { Vector3d crossProduct = v1.cross(v2); return crossProduct.length(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/biomes/BiomeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/biomes/BiomeAsset.java index cf983f1c..9465a3cd 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/biomes/BiomeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/biomes/BiomeAsset.java @@ -19,8 +19,8 @@ import com.hypixel.hytale.builtin.hytalegenerator.assets.terrains.DensityTerrain import com.hypixel.hytale.builtin.hytalegenerator.assets.terrains.TerrainAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.tintproviders.ConstantTintProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.tintproviders.TintProviderAsset; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; -import com.hypixel.hytale.builtin.hytalegenerator.biome.SimpleBiomeType; +import com.hypixel.hytale.builtin.hytalegenerator.biome.Biome; +import com.hypixel.hytale.builtin.hytalegenerator.biome.SimpleBiome; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.environmentproviders.EnvironmentProvider; import com.hypixel.hytale.builtin.hytalegenerator.material.Material; @@ -30,7 +30,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProv import com.hypixel.hytale.builtin.hytalegenerator.propdistributions.Assignments; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.builtin.hytalegenerator.tintproviders.TintProvider; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; @@ -123,28 +122,26 @@ public class BiomeAsset implements JsonAssetWithMap materialProvider = this.materialProviderAsset - .build(new MaterialProviderAsset.Argument(parentSeed, materialCache, referenceBundle, workerIndexer)); - Density density = this.terrainAsset.buildDensity(parentSeed, referenceBundle, workerIndexer); + .build(new MaterialProviderAsset.Argument(parentSeed, materialCache, referenceBundle)); + Density density = this.terrainAsset.buildDensity(parentSeed, referenceBundle); EnvironmentProvider environments = EnvironmentProvider.noEnvironmentProvider(); if (this.environmentProviderAsset != null) { - environments = this.environmentProviderAsset.build(new EnvironmentProviderAsset.Argument(parentSeed, materialCache, referenceBundle, workerIndexer)); + environments = this.environmentProviderAsset.build(new EnvironmentProviderAsset.Argument(parentSeed, materialCache, referenceBundle)); } TintProvider tints = TintProvider.noTintProvider(); if (this.tintProviderAsset != null) { - tints = this.tintProviderAsset.build(new TintProviderAsset.Argument(parentSeed, materialCache, referenceBundle, workerIndexer)); + tints = this.tintProviderAsset.build(new TintProviderAsset.Argument(parentSeed, materialCache, referenceBundle)); } - SimpleBiomeType biome = new SimpleBiomeType(this.biomeName, density, materialProvider, environments, tints); + SimpleBiome biome = new SimpleBiome(this.biomeName, density, materialProvider, environments, tints); for (PropRuntimeAsset fieldAsset : this.propRuntimeAssets) { if (!fieldAsset.isSkip()) { - PositionProvider positionProvider = fieldAsset.buildPositionProvider(parentSeed, referenceBundle, workerIndexer); - Assignments distribution = fieldAsset.buildPropDistribution(parentSeed, materialCache, fieldAsset.getRuntime(), referenceBundle, workerIndexer); + PositionProvider positionProvider = fieldAsset.buildPositionProvider(parentSeed, referenceBundle); + Assignments distribution = fieldAsset.buildPropDistribution(parentSeed, materialCache, fieldAsset.getRuntime(), referenceBundle); PropField field = new PropField(fieldAsset.getRuntime(), distribution, positionProvider); biome.addPropFieldTo(field); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/Cache2dDensityAsset_Deprecated.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/Cache2dDensityAsset_Deprecated.java index 57497028..fa2cf7ce 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/Cache2dDensityAsset_Deprecated.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/Cache2dDensityAsset_Deprecated.java @@ -27,7 +27,7 @@ public class Cache2dDensityAsset_Deprecated extends DensityAsset { if (input == null) { return new ConstantValueDensity(0.0); } else { - Density cacheDensity = new MultiCacheDensity(input, argument.workerIndexer.getWorkerCount(), CacheDensityAsset.DEFAULT_CAPACITY); + Density cacheDensity = new MultiCacheDensity(input, CacheDensityAsset.DEFAULT_CAPACITY); return new YOverrideDensity(cacheDensity, this.y); } } else { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CacheDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CacheDensityAsset.java index 3e24e376..b09d62b5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CacheDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CacheDensityAsset.java @@ -27,8 +27,8 @@ public class CacheDensityAsset extends DensityAsset { return this.build(argument); } else { return (Density)(this.capacity == 1 - ? new CacheDensity(this.buildFirstInput(argument), argument.workerIndexer.getWorkerCount()) - : new MultiCacheDensity(this.buildFirstInput(argument), argument.workerIndexer.getWorkerCount(), this.capacity)); + ? new CacheDensity(this.buildFirstInput(argument)) + : new MultiCacheDensity(this.buildFirstInput(argument), this.capacity)); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise2DDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise2DDensityAsset.java index ff07756c..d930188a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise2DDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise2DDensityAsset.java @@ -35,7 +35,7 @@ public class CellNoise2DDensityAsset extends DensityAsset { SeedBox childSeed = argument.parentSeed.child(this.seedKey); CellNoiseField noise = new CellNoiseField(childSeed.createSupplier().get(), this.scaleX, 1.0, this.scaleZ, this.jitter, this.octaves, this.cellType); Noise2dDensity noiseDensity = new Noise2dDensity(noise); - Density cacheDensity = new MultiCacheDensity(noiseDensity, argument.workerIndexer.getWorkerCount(), CacheDensityAsset.DEFAULT_CAPACITY); + Density cacheDensity = new MultiCacheDensity(noiseDensity, CacheDensityAsset.DEFAULT_CAPACITY); return new YOverrideDensity(cacheDensity, 0.0); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DensityAsset.java index 93de92d4..06d08275 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DensityAsset.java @@ -19,7 +19,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.WorldSt import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; @@ -52,14 +51,14 @@ public abstract class DensityAsset implements JsonAssetWithMap threadInstances; + + public Exported(boolean i, @Nonnull DensityAsset asset) { + this.isSingleInstance = i; + this.asset = asset; + this.threadInstances = new ConcurrentHashMap<>(); + } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ExportedDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ExportedDensityAsset.java index fd4c84d6..2bbcf462 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ExportedDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ExportedDensityAsset.java @@ -26,12 +26,15 @@ public class ExportedDensityAsset extends DensityAsset { LoggerUtil.getLogger() .severe("Couldn't find Density asset exported with name: '" + this.exportName + "'. This could indicate a defect in the HytaleGenerator assets."); return this.firstInput().build(argument); - } else if (exported.singleInstance) { - if (exported.builtInstance == null) { - exported.builtInstance = this.firstInput().build(argument); + } else if (exported.isSingleInstance) { + Thread thread = Thread.currentThread(); + Density builtInstance = exported.threadInstances.get(thread); + if (builtInstance == null) { + builtInstance = this.firstInput().build(argument); + exported.threadInstances.put(thread, builtInstance); } - return exported.builtInstance; + return builtInstance; } else { return this.firstInput().build(argument); } @@ -45,7 +48,7 @@ public class ExportedDensityAsset extends DensityAsset { this.cleanUpInputs(); DensityAsset.Exported exported = getExportedAsset(this.exportName); if (exported != null) { - exported.builtInstance = null; + exported.threadInstances.clear(); for (DensityAsset input : this.inputs()) { input.cleanUp(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ImportedDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ImportedDensityAsset.java index 4260a55e..4e8ab463 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ImportedDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ImportedDensityAsset.java @@ -23,18 +23,21 @@ public class ImportedDensityAsset extends DensityAsset { if (this.isSkipped()) { return new ConstantValueDensity(0.0); } else { - DensityAsset.Exported asset = getExportedAsset(this.importedNodeName); - if (asset == null) { + DensityAsset.Exported exported = getExportedAsset(this.importedNodeName); + if (exported == null) { LoggerUtil.getLogger().warning("Couldn't find Density asset exported with name: '" + this.importedNodeName + "'. Using empty Node instead."); return new ConstantValueDensity(0.0); - } else if (asset.singleInstance) { - if (asset.builtInstance == null) { - asset.builtInstance = asset.asset.build(argument); + } else if (exported.isSingleInstance) { + Thread thread = Thread.currentThread(); + Density builtInstance = exported.threadInstances.get(thread); + if (builtInstance == null) { + builtInstance = exported.asset.build(argument); + exported.threadInstances.put(thread, builtInstance); } - return asset.builtInstance; + return builtInstance; } else { - return asset.asset.build(argument); + return exported.asset.build(argument); } } } @@ -55,7 +58,7 @@ public class ImportedDensityAsset extends DensityAsset { this.cleanUpInputs(); DensityAsset.Exported exported = getExportedAsset(this.importedNodeName); if (exported != null) { - exported.builtInstance = null; + exported.threadInstances.clear(); for (DensityAsset input : this.inputs()) { input.cleanUp(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsPinchDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsPinchDensityAsset.java index fd15b137..521b0a57 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsPinchDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsPinchDensityAsset.java @@ -53,17 +53,16 @@ public class PositionsPinchDensityAsset extends DensityAsset { return (Density)(this.isHorizontal ? new PositionsHorizontalPinchDensity( this.buildFirstInput(argument), - this.positionProviderAsset.build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle, argument.workerIndexer)), + this.positionProviderAsset.build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle)), this.pinchCurveAsset.build(), this.maxDistance, this.normalizeDistance, this.positionsMinY, - this.positionsMaxY, - argument.workerIndexer.getWorkerCount() + this.positionsMaxY ) : new PositionsPinchDensity( this.buildFirstInput(argument), - this.positionProviderAsset.build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle, argument.workerIndexer)), + this.positionProviderAsset.build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle)), this.pinchCurveAsset.build(), this.maxDistance, this.normalizeDistance diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsTwistDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsTwistDensityAsset.java index 15d20c48..f71ae530 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsTwistDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsTwistDensityAsset.java @@ -48,7 +48,7 @@ public class PositionsTwistDensityAsset extends DensityAsset { ? new ConstantValueDensity(0.0) : new PositionsTwistDensity( this.buildFirstInput(argument), - this.positionProviderAsset.build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle, argument.workerIndexer)), + this.positionProviderAsset.build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle)), this.pinchCurveAsset.build(), this.twistAxis, this.maxDistance, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise2dDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise2dDensityAsset.java index 72905b30..49cf25d3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise2dDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise2dDensityAsset.java @@ -53,7 +53,7 @@ public class SimplexNoise2dDensityAsset extends DensityAsset { .withNumberOfOctaves(this.octaves) .build(); Noise2dDensity noiseDensity = new Noise2dDensity(noise); - Density cacheDensity = new MultiCacheDensity(noiseDensity, argument.workerIndexer.getWorkerCount(), CacheDensityAsset.DEFAULT_CAPACITY); + Density cacheDensity = new MultiCacheDensity(noiseDensity, CacheDensityAsset.DEFAULT_CAPACITY); return new YOverrideDensity(cacheDensity, 0.0); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/Positions3DDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/Positions3DDensityAsset.java index a8450c01..323abe92 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/Positions3DDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/Positions3DDensityAsset.java @@ -42,8 +42,7 @@ public class Positions3DDensityAsset extends DensityAsset { if (this.isSkipped()) { return new ConstantValueDensity(0.0); } else { - PositionProvider positionsField = this.positionProviderAsset - .build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle, argument.workerIndexer)); + PositionProvider positionsField = this.positionProviderAsset.build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle)); Double2DoubleFunction curve = this.curveAsset.build(); CurveReturnType returnType = new CurveReturnType(curve); return new PositionsDensity(positionsField, returnType, new EuclideanDistanceFunction(), this.maxDistance); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/PositionsCellNoiseDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/PositionsCellNoiseDensityAsset.java index 6ac5df36..be3b0eb8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/PositionsCellNoiseDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/PositionsCellNoiseDensityAsset.java @@ -50,9 +50,8 @@ public class PositionsCellNoiseDensityAsset extends DensityAsset { if (this.isSkipped()) { return new ConstantValueDensity(0.0); } else { - PositionProvider positionsField = this.positionProviderAsset - .build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle, argument.workerIndexer)); - ReturnType returnType = this.returnTypeAsset.build(argument.parentSeed, argument.referenceBundle, argument.workerIndexer); + PositionProvider positionsField = this.positionProviderAsset.build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle)); + ReturnType returnType = this.returnTypeAsset.build(argument.parentSeed, argument.referenceBundle); returnType.setMaxDistance(this.maxDistance); DistanceFunction distanceFunction = this.distanceFunctionAsset.build(argument.parentSeed, this.maxDistance); return new PositionsDensity(positionsField, returnType, distanceFunction, this.maxDistance); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/CellValueReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/CellValueReturnTypeAsset.java index 8dd7b059..998ce847 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/CellValueReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/CellValueReturnTypeAsset.java @@ -9,7 +9,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; @@ -29,10 +28,10 @@ public class CellValueReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { - Density densityNode = this.densityAsset.build(new DensityAsset.Argument(parentSeed, referenceBundle, workerIndexer)); - Density cache = new MultiCacheDensity(densityNode, workerIndexer.getWorkerCount(), CacheDensityAsset.DEFAULT_CAPACITY); - return new CellValueReturnType(cache, this.defaultValue, workerIndexer.getWorkerCount()); + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { + Density densityNode = this.densityAsset.build(new DensityAsset.Argument(parentSeed, referenceBundle)); + Density cache = new MultiCacheDensity(densityNode, CacheDensityAsset.DEFAULT_CAPACITY); + return new CellValueReturnType(cache, this.defaultValue); } @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/CurveReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/CurveReturnTypeAsset.java index bc0d4dbe..fbc08552 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/CurveReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/CurveReturnTypeAsset.java @@ -6,7 +6,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; @@ -23,7 +22,7 @@ public class CurveReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { Double2DoubleFunction curve = this.curveAsset.build(); return new CurveReturnType(curve); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/DensityReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/DensityReturnTypeAsset.java index f803454b..c0103f9b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/DensityReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/DensityReturnTypeAsset.java @@ -14,7 +14,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; @@ -44,8 +43,8 @@ public class DensityReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { - DensityAsset.Argument densityArgument = new DensityAsset.Argument(parentSeed, referenceBundle, workerIndexer); + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { + DensityAsset.Argument densityArgument = new DensityAsset.Argument(parentSeed, referenceBundle); Density choiceDensity = this.choiceDensityAsset.build(densityArgument); HashMap delimiterMap = new HashMap<>(this.delimiterAssets.length); @@ -53,8 +52,8 @@ public class DensityReturnTypeAsset extends ReturnTypeAsset { delimiterMap.put(new Range((float)delimiter.from, (float)delimiter.to), delimiter.densityAsset.build(densityArgument)); } - Density cache = new MultiCacheDensity(choiceDensity, workerIndexer.getWorkerCount(), CacheDensityAsset.DEFAULT_CAPACITY); - return new DensityReturnType(cache, delimiterMap, true, this.defaultValue, workerIndexer.getWorkerCount()); + Density cache = new MultiCacheDensity(choiceDensity, CacheDensityAsset.DEFAULT_CAPACITY); + return new DensityReturnType(cache, delimiterMap, true, this.defaultValue); } public static class DelimiterAsset implements JsonAssetWithMap> { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2AddReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2AddReturnTypeAsset.java index 23135721..adc1718f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2AddReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2AddReturnTypeAsset.java @@ -4,7 +4,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; @@ -16,7 +15,7 @@ public class Distance2AddReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { return new Distance2AddReturnType(); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2DivReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2DivReturnTypeAsset.java index 9ff6a0da..02311da2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2DivReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2DivReturnTypeAsset.java @@ -4,7 +4,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; @@ -16,7 +15,7 @@ public class Distance2DivReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { return new Distance2DivReturnType(); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2MulReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2MulReturnTypeAsset.java index 68e9361b..6f6faa3e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2MulReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2MulReturnTypeAsset.java @@ -4,7 +4,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; @@ -16,7 +15,7 @@ public class Distance2MulReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { return new Distance2MulReturnType(); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2ReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2ReturnTypeAsset.java index 39a20aa4..38d208db 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2ReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2ReturnTypeAsset.java @@ -4,7 +4,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; @@ -16,7 +15,7 @@ public class Distance2ReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { return new Distance2ReturnType(); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2SubReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2SubReturnTypeAsset.java index c86360d8..6406b9af 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2SubReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/Distance2SubReturnTypeAsset.java @@ -4,7 +4,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; @@ -16,7 +15,7 @@ public class Distance2SubReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { return new Distance2SubReturnType(); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/DistanceReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/DistanceReturnTypeAsset.java index 9258cef7..d0e610a8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/DistanceReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/DistanceReturnTypeAsset.java @@ -4,7 +4,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.return import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; @@ -16,7 +15,7 @@ public class DistanceReturnTypeAsset extends ReturnTypeAsset { @Nonnull @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { return new DistanceReturnType(); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/ImportedReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/ImportedReturnTypeAsset.java index 8923cdf2..a8db9be3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/ImportedReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/ImportedReturnTypeAsset.java @@ -4,7 +4,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; @@ -23,7 +22,7 @@ public class ImportedReturnTypeAsset extends ReturnTypeAsset { private String importedAssetName = ""; @Override - public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public ReturnType build(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle) { ReturnTypeAsset asset = getExportedAsset(this.importedAssetName); if (asset == null) { Logger.getLogger("Density") @@ -42,7 +41,7 @@ public class ImportedReturnTypeAsset extends ReturnTypeAsset { } }; } else { - return asset.build(parentSeed, referenceBundle, workerIndexer); + return asset.build(parentSeed, referenceBundle); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/ReturnTypeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/ReturnTypeAsset.java index c481ecca..5423d34c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/ReturnTypeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/returntypes/ReturnTypeAsset.java @@ -9,7 +9,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.LoggerUtil; import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.positions.returntypes.ReturnType; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; @@ -43,7 +42,7 @@ public abstract class ReturnTypeAsset implements JsonAssetWithMap threadInstances; + + public Exported(boolean isSingleInstance, @Nonnull VectorProviderAsset asset) { + this.isSingleInstance = isSingleInstance; + this.asset = asset; + this.threadInstances = new ConcurrentHashMap<>(); + } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/WorldStructureAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/WorldStructureAsset.java index 6119b92d..075ebd22 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/WorldStructureAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/WorldStructureAsset.java @@ -6,11 +6,9 @@ import com.hypixel.hytale.assetstore.codec.ContainedAssetCodec; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; import com.hypixel.hytale.assetstore.map.JsonAssetWithMap; import com.hypixel.hytale.builtin.hytalegenerator.assets.Cleanable; -import com.hypixel.hytale.builtin.hytalegenerator.biomemap.BiomeMap; import com.hypixel.hytale.builtin.hytalegenerator.material.MaterialCache; -import com.hypixel.hytale.builtin.hytalegenerator.material.SolidMaterial; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; +import com.hypixel.hytale.builtin.hytalegenerator.worldstructure.WorldStructure; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.codecs.array.ArrayCodec; @@ -29,11 +27,7 @@ public abstract class WorldStructureAsset implements Cleanable, JsonAssetWithMap protected WorldStructureAsset() { } - public abstract BiomeMap buildBiomeMap(@Nonnull WorldStructureAsset.Argument var1); - - public abstract int getBiomeTransitionDistance(); - - public abstract int getMaxBiomeEdgeDistance(); + public abstract WorldStructure build(@Nonnull WorldStructureAsset.Argument var1); public String getId() { return this.id; @@ -46,18 +40,15 @@ public abstract class WorldStructureAsset implements Cleanable, JsonAssetWithMap public static class Argument { public MaterialCache materialCache; public SeedBox parentSeed; - public WorkerIndexer workerIndexer; - public Argument(@Nonnull MaterialCache materialCache, @Nonnull SeedBox parentSeed, @Nonnull WorkerIndexer workerIndexer) { + public Argument(@Nonnull MaterialCache materialCache, @Nonnull SeedBox parentSeed) { this.materialCache = materialCache; this.parentSeed = parentSeed; - this.workerIndexer = workerIndexer; } public Argument(@Nonnull WorldStructureAsset.Argument argument) { this.materialCache = argument.materialCache; this.parentSeed = argument.parentSeed; - this.workerIndexer = argument.workerIndexer; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/basic/BasicWorldStructureAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/basic/BasicWorldStructureAsset.java index ac51f3bf..6140e74b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/basic/BasicWorldStructureAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/basic/BasicWorldStructureAsset.java @@ -3,20 +3,20 @@ package com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.basic; import com.hypixel.hytale.assetstore.codec.ContainedAssetCodec; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; import com.hypixel.hytale.builtin.hytalegenerator.LoggerUtil; +import com.hypixel.hytale.builtin.hytalegenerator.Registry; import com.hypixel.hytale.builtin.hytalegenerator.assets.biomes.BiomeAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.density.ConstantDensityAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.density.DensityAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.WorldStructureAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.mapcontentfield.BaseHeightContentFieldAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.mapcontentfield.ContentFieldAsset; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; -import com.hypixel.hytale.builtin.hytalegenerator.biomemap.BiomeMap; -import com.hypixel.hytale.builtin.hytalegenerator.biomemap.SimpleBiomeMap; +import com.hypixel.hytale.builtin.hytalegenerator.biome.Biome; import com.hypixel.hytale.builtin.hytalegenerator.cartas.SimpleNoiseCarta; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.rangemaps.DoubleRange; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.BaseHeightReference; import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; +import com.hypixel.hytale.builtin.hytalegenerator.worldstructure.WorldStructure; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; @@ -69,7 +69,7 @@ public class BasicWorldStructureAsset extends WorldStructureAsset { @Nullable @Override - public BiomeMap buildBiomeMap(@Nonnull WorldStructureAsset.Argument argument) { + public WorldStructure build(@Nonnull WorldStructureAsset.Argument argument) { ReferenceBundle referenceBundle = new ReferenceBundle(); for (int i = this.contentFieldAssets.length - 1; i >= 0; i--) { @@ -81,16 +81,18 @@ public class BasicWorldStructureAsset extends WorldStructureAsset { } } - HashMap biomeAssetToBiomeType = new HashMap<>(); + HashMap biomeAssetToBiomeType = new HashMap<>(); BiomeAsset defaultBiomeAsset = (BiomeAsset)((DefaultAssetMap)BiomeAsset.getAssetStore().getAssetMap()).getAsset(this.defaultBiomeId); if (defaultBiomeAsset == null) { LoggerUtil.getLogger().warning("Couldn't find Biome asset with id: " + this.defaultBiomeId); return null; } else { - BiomeType defaultBiome = defaultBiomeAsset.build(argument.materialCache, argument.parentSeed, referenceBundle, argument.workerIndexer); + Biome defaultBiome = defaultBiomeAsset.build(argument.materialCache, argument.parentSeed, referenceBundle); biomeAssetToBiomeType.put(defaultBiomeAsset, defaultBiome); Density noise = this.densityAsset.build(DensityAsset.from(argument, referenceBundle)); - SimpleNoiseCarta carta = new SimpleNoiseCarta<>(noise, defaultBiome); + Registry biomeRegistry = new Registry<>(); + int defaultBiomeId = biomeRegistry.getIdOrRegister(defaultBiome); + SimpleNoiseCarta carta = new SimpleNoiseCarta<>(noise, defaultBiomeId); for (BiomeRangeAsset asset : this.biomeRangeAssets) { DoubleRange range = asset.getRange(); @@ -98,35 +100,23 @@ public class BasicWorldStructureAsset extends WorldStructureAsset { if (biomeAsset == null) { LoggerUtil.getLogger().warning("Couldn't find biome asset with name " + asset.getBiomeAssetId()); } else { - BiomeType biome; + Biome biome; if (biomeAssetToBiomeType.containsKey(biomeAsset)) { biome = biomeAssetToBiomeType.get(biomeAsset); } else { - biome = biomeAsset.build(argument.materialCache, argument.parentSeed, referenceBundle, argument.workerIndexer); + biome = biomeAsset.build(argument.materialCache, argument.parentSeed, referenceBundle); biomeAssetToBiomeType.put(biomeAsset, biome); } - carta.put(range, biome); + carta.put(range, biomeRegistry.getIdOrRegister(biome)); } } - SimpleBiomeMap biomeMap = new SimpleBiomeMap<>(carta); - int defaultRadius = Math.max(1, this.biomeTransitionDistance / 2); - biomeMap.setDefaultRadius(defaultRadius); - return biomeMap; + int biomeTransitionRadius = Math.max(1, this.biomeTransitionDistance / 2); + return new WorldStructure(carta, biomeRegistry, biomeTransitionRadius, this.maxBiomeEdgeDistance); } } - @Override - public int getBiomeTransitionDistance() { - return this.biomeTransitionDistance; - } - - @Override - public int getMaxBiomeEdgeDistance() { - return this.maxBiomeEdgeDistance; - } - @Override public void cleanUp() { this.densityAsset.cleanUp(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/biome/BiomeType.java b/src/com/hypixel/hytale/builtin/hytalegenerator/biome/Biome.java similarity index 70% rename from src/com/hypixel/hytale/builtin/hytalegenerator/biome/BiomeType.java rename to src/com/hypixel/hytale/builtin/hytalegenerator/biome/Biome.java index e1cdffdd..68caea26 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/biome/BiomeType.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/biome/Biome.java @@ -3,7 +3,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.biome; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import javax.annotation.Nonnull; -public interface BiomeType extends MaterialSource, PropsSource, EnvironmentSource, TintSource { +public interface Biome extends MaterialSource, PropsSource, EnvironmentSource, TintSource { String getBiomeName(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiomeType.java b/src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiome.java similarity index 96% rename from src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiomeType.java rename to src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiome.java index b31777e8..92dde53e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiomeType.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiome.java @@ -11,7 +11,7 @@ import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; -public class SimpleBiomeType implements BiomeType { +public class SimpleBiome implements Biome { private final Density terrainDensity; private final MaterialProvider materialProvider; private final List propFields; @@ -19,7 +19,7 @@ public class SimpleBiomeType implements BiomeType { private final TintProvider tintProvider; private final String biomeName; - public SimpleBiomeType( + public SimpleBiome( @Nonnull String biomeName, @Nonnull Density terrainDensity, @Nonnull MaterialProvider materialProvider, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/biomemap/BiomeMap.java b/src/com/hypixel/hytale/builtin/hytalegenerator/biomemap/BiomeMap.java deleted file mode 100644 index da393b94..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/biomemap/BiomeMap.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.biomemap; - -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiCarta; - -public abstract class BiomeMap extends BiCarta { -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/biomemap/SimpleBiomeMap.java b/src/com/hypixel/hytale/builtin/hytalegenerator/biomemap/SimpleBiomeMap.java deleted file mode 100644 index 86488962..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/biomemap/SimpleBiomeMap.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.biomemap; - -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiCarta; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; - -public class SimpleBiomeMap extends BiomeMap { - private int defaultTransitionRadius; - private Map pairHashToRadius; - private BiCarta carta; - - public SimpleBiomeMap(@Nonnull BiCarta carta) { - this.carta = carta; - this.defaultTransitionRadius = 1; - this.pairHashToRadius = new HashMap<>(); - } - - public void setDefaultRadius(int defaultRadius) { - if (defaultRadius <= 0) { - throw new IllegalArgumentException(); - } else { - this.defaultTransitionRadius = defaultRadius; - } - } - - public BiomeType apply(int x, int z, @Nonnull WorkerIndexer.Id id) { - return this.carta.apply(x, z, id); - } - - @Override - public List allPossibleValues() { - return this.carta.allPossibleValues(); - } -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/cartas/SimpleNoiseCarta.java b/src/com/hypixel/hytale/builtin/hytalegenerator/cartas/SimpleNoiseCarta.java index 8831fef9..381befe1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/cartas/SimpleNoiseCarta.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/cartas/SimpleNoiseCarta.java @@ -32,7 +32,6 @@ public class SimpleNoiseCarta extends BiCarta { public T apply(int x, int z, @Nonnull WorkerIndexer.Id id) { Density.Context context = new Density.Context(); context.position = new Vector3d(x, 0.0, z); - context.workerId = id; double noiseValue = this.density.process(context); T value = this.rangeMap.get(noiseValue); return value == null ? this.defaultValue : value; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkRequest.java b/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkRequest.java index 6eacfd6c..4d2695c0 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkRequest.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkRequest.java @@ -13,10 +13,12 @@ public record ChunkRequest(@Nonnull ChunkRequest.GeneratorProfile generatorProfi @Nonnull private final String worldStructureName; private int seed; + private int worldCounter; - public GeneratorProfile(@Nonnull String worldStructureName, int seed) { + public GeneratorProfile(@Nonnull String worldStructureName, int seed, int worldCounter) { this.worldStructureName = worldStructureName; this.seed = seed; + this.worldCounter = worldCounter; } @Nonnull @@ -33,25 +35,20 @@ public record ChunkRequest(@Nonnull ChunkRequest.GeneratorProfile generatorProfi } @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } else if (obj != null && obj.getClass() == this.getClass()) { - ChunkRequest.GeneratorProfile that = (ChunkRequest.GeneratorProfile)obj; - return Objects.equals(this.worldStructureName, that.worldStructureName) && this.seed == that.seed; - } else { - return false; - } + public boolean equals(Object o) { + return !(o instanceof ChunkRequest.GeneratorProfile that) + ? false + : this.seed == that.seed && this.worldCounter == that.worldCounter && Objects.equals(this.worldStructureName, that.worldStructureName); } @Override public int hashCode() { - return Objects.hash(this.worldStructureName, this.seed); + return Objects.hash(this.worldStructureName, this.seed, this.worldCounter); } @Override public String toString() { - return "GeneratorProfile[worldStructureName=" + this.worldStructureName + ", seed=" + this.seed + "]"; + return "GeneratorProfile{worldStructureName='" + this.worldStructureName + "', seed=" + this.seed + ", worldCounter=" + this.worldCounter + "}"; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/commands/ViewportCommand.java b/src/com/hypixel/hytale/builtin/hytalegenerator/commands/ViewportCommand.java index f0e6f13c..74d6832b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/commands/ViewportCommand.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/commands/ViewportCommand.java @@ -27,18 +27,16 @@ import javax.annotation.Nullable; public class ViewportCommand extends AbstractPlayerCommand { @Nonnull - private final FlagArg deleteFlag = this.withFlagArg("delete", "Deletes the existing Viewport instance."); + private final FlagArg deleteFlag = this.withFlagArg("delete", "server.commands.viewport.delete.desc"); @Nonnull - private final OptionalArg radiusArg = this.withOptionalArg( - "radius", "Creates a viewport with the given radius in chunks around the player.", ArgTypes.INTEGER - ); + private final OptionalArg radiusArg = this.withOptionalArg("radius", "server.commands.viewport.radius.desc", ArgTypes.INTEGER); @Nonnull private final AssetManager assetManager; @Nullable private Runnable activeTask; public ViewportCommand(@Nonnull AssetManager assetManager) { - super("Viewport", "Establishes a worldgen viewport on the selected region."); + super("Viewport", "server.commands.viewport.desc"); this.assetManager = assetManager; } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/Density.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/Density.java index f66cab3d..c2fb1e97 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/Density.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/Density.java @@ -5,7 +5,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.environmentproviders.Environme import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.MaterialProvider; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.TerrainDensityProvider; import com.hypixel.hytale.builtin.hytalegenerator.patterns.Pattern; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.builtin.hytalegenerator.tintproviders.TintProvider; import com.hypixel.hytale.builtin.hytalegenerator.vectorproviders.VectorProvider; import com.hypixel.hytale.math.vector.Vector3d; @@ -25,8 +24,6 @@ public abstract class Density { public static class Context { @Nonnull public Vector3d position; - @Nonnull - public WorkerIndexer.Id workerId; @Nullable public Vector3d densityAnchor; @Nullable @@ -39,7 +36,6 @@ public abstract class Density { public Context() { this.position = new Vector3d(); - this.workerId = WorkerIndexer.Id.UNKNOWN; this.densityAnchor = null; this.positionsAnchor = null; this.switchState = 0; @@ -50,7 +46,6 @@ public abstract class Density { public Context( @Nonnull Vector3d position, - @Nonnull WorkerIndexer.Id workerId, @Nullable Vector3d densityAnchor, int switchState, double distanceFromCellWall, @@ -58,7 +53,6 @@ public abstract class Density { double distanceToBiomeEdge ) { this.position = position; - this.workerId = workerId; this.densityAnchor = densityAnchor; this.switchState = switchState; this.distanceFromCellWall = distanceFromCellWall; @@ -73,37 +67,60 @@ public abstract class Density { this.switchState = other.switchState; this.distanceFromCellWall = other.distanceFromCellWall; this.positionsAnchor = other.positionsAnchor; - this.workerId = other.workerId; this.terrainDensityProvider = other.terrainDensityProvider; this.distanceToBiomeEdge = other.distanceToBiomeEdge; } public Context(@Nonnull VectorProvider.Context context) { this.position = context.position; - this.workerId = context.workerId; this.terrainDensityProvider = context.terrainDensityProvider; } public Context(@Nonnull TintProvider.Context context) { this.position = context.position.toVector3d(); - this.workerId = context.workerId; } public Context(@Nonnull EnvironmentProvider.Context context) { this.position = context.position.toVector3d(); - this.workerId = context.workerId; } public Context(@Nonnull MaterialProvider.Context context) { this.position = context.position.toVector3d(); - this.workerId = context.workerId; this.terrainDensityProvider = context.terrainDensityProvider; this.distanceToBiomeEdge = context.distanceToBiomeEdge; } public Context(@Nonnull Pattern.Context context) { this.position = context.position.toVector3d(); - this.workerId = context.workerId; + } + + public void assign(@Nonnull Density.Context other) { + this.position = other.position; + this.densityAnchor = other.densityAnchor; + this.switchState = other.switchState; + this.distanceFromCellWall = other.distanceFromCellWall; + this.positionsAnchor = other.positionsAnchor; + this.terrainDensityProvider = other.terrainDensityProvider; + this.distanceToBiomeEdge = other.distanceToBiomeEdge; + } + + public void assign(@Nonnull VectorProvider.Context context) { + this.position = context.position; + this.terrainDensityProvider = context.terrainDensityProvider; + } + + public void assign(@Nonnull MaterialProvider.Context context) { + this.position.assign(context.position.x, context.position.y, context.position.z); + this.terrainDensityProvider = context.terrainDensityProvider; + this.distanceToBiomeEdge = context.distanceToBiomeEdge; + } + + public void assign(@Nonnull EnvironmentProvider.Context context) { + this.position.assign(context.position.x, context.position.y, context.position.z); + } + + public void assign(@Nonnull Pattern.Context context) { + this.position.assign(context.position.x, context.position.y, context.position.z); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AnchorDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AnchorDensity.java index b48dc56d..766170d5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AnchorDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AnchorDensity.java @@ -9,27 +9,32 @@ public class AnchorDensity extends Density { @Nullable private Density input; private final boolean isReversed; + private final Vector3d rChildPosition; + private final Density.Context rChildContext; public AnchorDensity(Density input, boolean isReversed) { this.input = input; this.isReversed = isReversed; + this.rChildPosition = new Vector3d(); + this.rChildContext = new Density.Context(); } @Override public double process(@Nonnull Density.Context context) { - Vector3d anchor = context.densityAnchor; - if (anchor == null) { + if (context.densityAnchor == null) { return this.input.process(context); - } else if (this.isReversed) { - Vector3d childPosition = new Vector3d(context.position.x + anchor.x, context.position.y + anchor.y, context.position.z + anchor.z); - Density.Context childContext = new Density.Context(context); - childContext.position = childPosition; - return this.input.process(childContext); } else { - Vector3d childPosition = new Vector3d(context.position.x - anchor.x, context.position.y - anchor.y, context.position.z - anchor.z); - Density.Context childContext = new Density.Context(context); - childContext.position = childPosition; - return this.input.process(childContext); + if (this.isReversed) { + this.rChildPosition + .assign(context.position.x + context.densityAnchor.x, context.position.y + context.densityAnchor.y, context.position.z + context.densityAnchor.z); + } else { + this.rChildPosition + .assign(context.position.x - context.densityAnchor.x, context.position.y - context.densityAnchor.y, context.position.z - context.densityAnchor.z); + } + + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + return this.input.process(this.rChildContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AngleDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AngleDensity.java index 1228f526..8d9863af 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AngleDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AngleDensity.java @@ -13,17 +13,22 @@ public class AngleDensity extends Density { @Nonnull private final Vector3d vector; private final boolean toAxis; + private final Vector3d rOtherVector; + private final VectorProvider.Context rVectorProviderContext; public AngleDensity(@Nonnull VectorProvider vectorProvider, @Nonnull Vector3d vector, boolean toAxis) { this.vector = vector.clone(); this.vectorProvider = vectorProvider; this.toAxis = toAxis; + this.rOtherVector = new Vector3d(); + this.rVectorProviderContext = new VectorProvider.Context(new Vector3d(), null); } @Override public double process(@Nonnull Density.Context context) { - Vector3d otherVector = this.vectorProvider.process(new VectorProvider.Context(context)); - double slopeAngle = VectorUtil.angle(this.vector, otherVector); + this.rVectorProviderContext.assign(context); + this.vectorProvider.process(this.rVectorProviderContext, this.rOtherVector); + double slopeAngle = VectorUtil.angle(this.vector, this.rOtherVector); if (this.toAxis && slopeAngle > Math.PI / 2) { slopeAngle = Math.PI - slopeAngle; } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AxisDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AxisDensity.java index a241a1b6..3a7157c4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AxisDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AxisDensity.java @@ -14,11 +14,23 @@ public class AxisDensity extends Density { @Nonnull private final Vector3d axis; private final boolean isAnchored; + private final Vector3d rPosition; + private final Vector3d r0; + private final Vector3d r1; + private final Vector3d r2; + private final Vector3d r3; + private final Vector3d r4; public AxisDensity(@Nonnull Double2DoubleFunction distanceCurve, @Nonnull Vector3d axis, boolean isAnchored) { this.distanceCurve = distanceCurve; this.axis = axis; this.isAnchored = isAnchored; + this.rPosition = new Vector3d(); + this.r0 = new Vector3d(); + this.r1 = new Vector3d(); + this.r2 = new Vector3d(); + this.r3 = new Vector3d(); + this.r4 = new Vector3d(); } @Override @@ -28,7 +40,7 @@ public class AxisDensity extends Density { } else if (this.isAnchored) { return this.processAnchored(context); } else { - double distance = VectorUtil.distanceToLine3d(context.position, ZERO_VECTOR, this.axis); + double distance = VectorUtil.distanceToLine3d(context.position, ZERO_VECTOR, this.axis, this.r0, this.r1, this.r2, this.r3, this.r4); return this.distanceCurve.get(distance); } } @@ -41,8 +53,8 @@ public class AxisDensity extends Density { if (anchor == null) { return 0.0; } else { - Vector3d position = context.position.clone().subtract(anchor); - double distance = VectorUtil.distanceToLine3d(position, ZERO_VECTOR, this.axis); + this.rPosition.assign(context.position).subtract(anchor); + double distance = VectorUtil.distanceToLine3d(this.rPosition, ZERO_VECTOR, this.axis, this.r0, this.r1, this.r2, this.r3, this.r4); return this.distanceCurve.get(distance); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/CacheDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/CacheDensity.java index 47a2e053..5dc66e39 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/CacheDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/CacheDensity.java @@ -1,33 +1,34 @@ package com.hypixel.hytale.builtin.hytalegenerator.density.nodes; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class CacheDensity extends Density { - private final WorkerIndexer.Data threadData; + private final CacheDensity.Cache cache; @Nonnull private Density input; - public CacheDensity(@Nonnull Density input, int threadCount) { + public CacheDensity(@Nonnull Density input) { this.input = input; - this.threadData = new WorkerIndexer.Data<>(threadCount, CacheDensity.Cache::new); + this.cache = new CacheDensity.Cache(); } @Override public double process(@Nonnull Density.Context context) { - CacheDensity.Cache cache = this.threadData.get(context.workerId); - if (cache.position != null && cache.position.x == context.position.x && cache.position.y == context.position.y && cache.position.z == context.position.z) { - return cache.value; + if (this.cache.position != null + && this.cache.position.x == context.position.x + && this.cache.position.y == context.position.y + && this.cache.position.z == context.position.z) { + return this.cache.value; } else { - if (cache.position == null) { - cache.position = new Vector3d(); + if (this.cache.position == null) { + this.cache.position = new Vector3d(); } - cache.position.assign(context.position); - cache.value = this.input.process(context); - return cache.value; + this.cache.position.assign(context.position); + this.cache.value = this.input.process(context); + return this.cache.value; } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/FastGradientWarpDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/FastGradientWarpDensity.java index 9ba1925d..4ec60db1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/FastGradientWarpDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/FastGradientWarpDensity.java @@ -13,6 +13,9 @@ public class FastGradientWarpDensity extends Density { private final double warpScale; @Nonnull private final FastNoiseLite warper; + private final FastNoiseLite.Vector3 rWarpedPosition; + private final Density.Context rChildContext; + private final Vector3d rPosition; public FastGradientWarpDensity( @Nonnull Density input, float warpLacunarity, float warpPersistence, int warpOctaves, float warpScale, float warpFactor, int seed @@ -30,6 +33,9 @@ public class FastGradientWarpDensity extends Density { this.warper.setFractalOctaves(warpOctaves); this.warper.setDomainWarpAmp(warpFactor); this.warper.setDomainWarpFreq(warpScale); + this.rWarpedPosition = new FastNoiseLite.Vector3(0.0, 0.0, 0.0); + this.rChildContext = new Density.Context(); + this.rPosition = new Vector3d(); } } @@ -38,11 +44,15 @@ public class FastGradientWarpDensity extends Density { if (this.input == null) { return 0.0; } else { - FastNoiseLite.Vector3 warpedPosition = new FastNoiseLite.Vector3(context.position.x, context.position.y, context.position.z); - this.warper.DomainWarpFractalProgressive(warpedPosition); - Density.Context childContext = new Density.Context(context); - childContext.position = new Vector3d(warpedPosition.x, warpedPosition.y, warpedPosition.z); - return this.input.process(childContext); + this.rWarpedPosition.x = context.position.x; + this.rWarpedPosition.y = context.position.y; + this.rWarpedPosition.z = context.position.z; + this.warper.DomainWarpFractalProgressive(this.rWarpedPosition); + this.rPosition.assign(context.position); + this.rChildContext.assign(context); + this.rChildContext.position = this.rPosition; + this.rChildContext.position.assign(this.rWarpedPosition.x, this.rWarpedPosition.y, this.rWarpedPosition.z); + return this.input.process(this.rChildContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/GradientDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/GradientDensity.java index 00423910..6660fc1f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/GradientDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/GradientDensity.java @@ -13,6 +13,9 @@ public class GradientDensity extends Density { private final double slopeRange; @Nonnull private final Vector3d axis; + private final Density.Context rChildContext; + private final Vector3d rSlopeDirection; + private final Vector3d rPosition; public GradientDensity(@Nonnull Density input, double slopeRange, @Nonnull Vector3d axis) { if (slopeRange <= 0.0) { @@ -21,6 +24,9 @@ public class GradientDensity extends Density { this.axis = axis.clone(); this.slopeRange = slopeRange; this.input = input; + this.rChildContext = new Density.Context(); + this.rSlopeDirection = new Vector3d(); + this.rPosition = new Vector3d(); } } @@ -29,19 +35,21 @@ public class GradientDensity extends Density { if (this.input == null) { return 0.0; } else { - double valueAtOrigin = this.input.process(context); + this.rPosition.assign(context.position); + this.rChildContext.assign(context); + this.rChildContext.position = this.rPosition; + double valueAtOrigin = this.input.process(this.rChildContext); double maxX = context.position.x + this.slopeRange; double maxY = context.position.y + this.slopeRange; double maxZ = context.position.z + this.slopeRange; - Density.Context childContext = new Density.Context(context); - childContext.position = new Vector3d(maxX, context.position.y, context.position.z); - double deltaX = Math.abs(this.input.process(childContext) - valueAtOrigin); - childContext.position = new Vector3d(context.position.x, maxY, context.position.z); - double deltaY = Math.abs(this.input.process(childContext) - valueAtOrigin); - childContext.position = new Vector3d(context.position.x, context.position.y, maxZ); - double deltaZ = Math.abs(this.input.process(childContext) - valueAtOrigin); - Vector3d slopeDirection = new Vector3d(deltaX, deltaY, deltaZ); - double slopeAngle = VectorUtil.angle(this.axis, slopeDirection); + this.rChildContext.position.assign(maxX, context.position.y, context.position.z); + double deltaX = Math.abs(this.input.process(this.rChildContext) - valueAtOrigin); + this.rChildContext.position.assign(context.position.x, maxY, context.position.z); + double deltaY = Math.abs(this.input.process(this.rChildContext) - valueAtOrigin); + this.rChildContext.position.assign(context.position.x, context.position.y, maxZ); + double deltaZ = Math.abs(this.input.process(this.rChildContext) - valueAtOrigin); + this.rSlopeDirection.assign(deltaX, deltaY, deltaZ); + double slopeAngle = VectorUtil.angle(this.axis, this.rSlopeDirection); if (slopeAngle > Math.PI / 2) { slopeAngle = Math.PI - slopeAngle; } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/GradientWarpDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/GradientWarpDensity.java index fd033fef..123f7a98 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/GradientWarpDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/GradientWarpDensity.java @@ -13,6 +13,9 @@ public class GradientWarpDensity extends Density { private Density warpInput; private final double slopeRange; private final double warpFactor; + private final Density.Context rChildContext; + private final Vector3d rGradient; + public final Vector3d rPosition; public GradientWarpDensity(@Nonnull Density input, @Nonnull Density warpInput, double slopeRange, double warpFactor) { if (slopeRange <= 0.0) { @@ -22,6 +25,9 @@ public class GradientWarpDensity extends Density { this.warpFactor = warpFactor; this.input = input; this.warpInput = warpInput; + this.rChildContext = new Density.Context(); + this.rGradient = new Vector3d(); + this.rPosition = new Vector3d(); } } @@ -36,19 +42,21 @@ public class GradientWarpDensity extends Density { double maxX = context.position.x + this.slopeRange; double maxY = context.position.y + this.slopeRange; double maxZ = context.position.z + this.slopeRange; - Density.Context childContext = new Density.Context(context); - childContext.position = new Vector3d(maxX, context.position.y, context.position.z); - double deltaX = this.warpInput.process(childContext) - valueAtOrigin; - childContext.position = new Vector3d(context.position.x, maxY, context.position.z); - double deltaY = this.warpInput.process(childContext) - valueAtOrigin; - childContext.position = new Vector3d(context.position.x, context.position.z, maxZ); - double deltaZ = this.warpInput.process(childContext) - valueAtOrigin; - Vector3d gradient = new Vector3d(deltaX, deltaY, deltaZ); - gradient.scale(1.0 / this.slopeRange); - gradient.scale(this.warpFactor); - gradient.add(context.position.x, context.position.y, context.position.z); - childContext.position = gradient; - return this.input.process(childContext); + this.rPosition.assign(context.position); + this.rChildContext.assign(context); + this.rChildContext.position = this.rPosition; + this.rChildContext.position.assign(maxX, context.position.y, context.position.z); + double deltaX = this.warpInput.process(this.rChildContext) - valueAtOrigin; + this.rChildContext.position.assign(context.position.x, maxY, context.position.z); + double deltaY = this.warpInput.process(this.rChildContext) - valueAtOrigin; + this.rChildContext.position.assign(context.position.x, context.position.z, maxZ); + double deltaZ = this.warpInput.process(this.rChildContext) - valueAtOrigin; + this.rGradient.assign(deltaX, deltaY, deltaZ); + this.rGradient.scale(1.0 / this.slopeRange); + this.rGradient.scale(this.warpFactor); + this.rGradient.add(context.position.x, context.position.y, context.position.z); + this.rChildContext.position = this.rGradient; + return this.input.process(this.rChildContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/MultiCacheDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/MultiCacheDensity.java index 7c5d8d88..057a0890 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/MultiCacheDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/MultiCacheDensity.java @@ -1,28 +1,28 @@ package com.hypixel.hytale.builtin.hytalegenerator.density.nodes; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MultiCacheDensity extends Density { @Nonnull - private final WorkerIndexer.Data threadData; + private final MultiCacheDensity.Cache cache; @Nonnull private Density input; - public MultiCacheDensity(@Nonnull Density input, int threadCount, int capacity) { + public MultiCacheDensity(@Nonnull Density input, int capacity) { + assert capacity >= 0; + this.input = input; - this.threadData = new WorkerIndexer.Data<>(threadCount, () -> new MultiCacheDensity.Cache(capacity)); + this.cache = new MultiCacheDensity.Cache(capacity); } @Override public double process(@Nonnull Density.Context context) { - MultiCacheDensity.Cache cache = this.threadData.get(context.workerId); - MultiCacheDensity.Entry matchingEntry = cache.find(context.position); + MultiCacheDensity.Entry matchingEntry = this.cache.find(context.position); if (matchingEntry == null) { - matchingEntry = cache.getNext(); + matchingEntry = this.cache.getNext(); if (matchingEntry.position == null) { matchingEntry.position = new Vector3d(); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PlaneDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PlaneDensity.java index 81ec1a15..421351ba 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PlaneDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PlaneDensity.java @@ -16,12 +16,26 @@ public class PlaneDensity extends Density { private final Vector3d planeNormal; private final boolean isPlaneHorizontal; private final boolean isAnchored; + private final Vector3d rNearestPoint; + private final Vector3d rPosition; + private final Vector3d rVectorFromPlane; + private final Vector3d r0; + private final Vector3d r1; + private final Vector3d r2; + private final Vector3d r3; public PlaneDensity(@Nonnull Double2DoubleFunction distanceCurve, @Nonnull Vector3d planeNormal, boolean isAnchored) { this.distanceCurve = distanceCurve; this.planeNormal = planeNormal; this.isPlaneHorizontal = planeNormal.x == 0.0 && planeNormal.z == 0.0; this.isAnchored = isAnchored; + this.rNearestPoint = new Vector3d(); + this.rPosition = new Vector3d(); + this.rVectorFromPlane = new Vector3d(); + this.r0 = new Vector3d(); + this.r1 = new Vector3d(); + this.r2 = new Vector3d(); + this.r3 = new Vector3d(); } @Override @@ -35,8 +49,8 @@ public class PlaneDensity extends Density { if (this.isPlaneHorizontal) { distance = context.position.y; } else { - Vector3d nearestPoint = VectorUtil.nearestPointOnLine3d(context.position, ZERO_VECTOR, this.planeNormal); - distance = nearestPoint.length(); + VectorUtil.nearestPointOnLine3d(context.position, ZERO_VECTOR, this.planeNormal, this.rNearestPoint, this.r0, this.r1, this.r2, this.r3); + distance = this.rNearestPoint.length(); } return this.distanceCurve.get(distance); @@ -47,19 +61,19 @@ public class PlaneDensity extends Density { if (context == null) { return 0.0; } else { - Vector3d position = new Vector3d(x, y, z); + this.rPosition.assign(x, y, z); Vector3d p0 = context.densityAnchor; if (p0 == null) { return 0.0; } else { double distance = 0.0; if (this.isPlaneHorizontal) { - distance = Math.abs(p0.y - position.y); + distance = Math.abs(p0.y - this.rPosition.y); } - Vector3d pos = position.clone().addScaled(p0, -1.0); - Vector3d vectorFromPlane = VectorUtil.nearestPointOnLine3d(pos, ZERO_VECTOR, this.planeNormal); - distance = vectorFromPlane.length(); + this.rPosition.subtract(p0); + VectorUtil.nearestPointOnLine3d(this.rPosition, ZERO_VECTOR, this.planeNormal, this.rVectorFromPlane, this.r0, this.r1, this.r2, this.r3); + distance = this.rVectorFromPlane.length(); return this.distanceCurve.get(distance); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsHorizontalPinchDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsHorizontalPinchDensity.java index f8386f3f..9a3329a1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsHorizontalPinchDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsHorizontalPinchDensity.java @@ -1,13 +1,11 @@ package com.hypixel.hytale.builtin.hytalegenerator.density.nodes; +import com.hypixel.hytale.builtin.hytalegenerator.ReusableList; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.framework.math.Calculator; import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3d; import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; -import java.util.ArrayList; -import java.util.function.Consumer; import javax.annotation.Nonnull; public class PositionsHorizontalPinchDensity extends Density { @@ -18,11 +16,22 @@ public class PositionsHorizontalPinchDensity extends Density { @Nonnull private final Double2DoubleFunction pinchCurve; @Nonnull - private final WorkerIndexer.Data threadData; + private final PositionsHorizontalPinchDensity.Cache cache; private final double maxDistance; private final boolean distanceNormalized; private final double positionsMinY; private final double positionsMaxY; + private final Vector3d rWarpVector; + private final Vector3d rSamplePoint; + private final Vector3d rMin; + private final Vector3d rMax; + private final Vector3d rPosition; + private final Vector3d rConsumerResult; + private final ReusableList rWarpVectors; + private final ReusableList rWarpDistances; + private final ReusableList rWeights; + private final PositionProvider.Context rPositionsContext; + private final Density.Context rChildContext; public PositionsHorizontalPinchDensity( @Nonnull Density input, @@ -31,8 +40,7 @@ public class PositionsHorizontalPinchDensity extends Density { double maxDistance, boolean distanceNormalized, double positionsMinY, - double positionsMaxY, - int threadCount + double positionsMaxY ) { if (maxDistance < 0.0) { throw new IllegalArgumentException(); @@ -48,7 +56,18 @@ public class PositionsHorizontalPinchDensity extends Density { this.distanceNormalized = distanceNormalized; this.positionsMinY = positionsMinY; this.positionsMaxY = positionsMaxY; - this.threadData = new WorkerIndexer.Data<>(threadCount, PositionsHorizontalPinchDensity.Cache::new); + this.cache = new PositionsHorizontalPinchDensity.Cache(); + this.rWarpVector = new Vector3d(); + this.rSamplePoint = new Vector3d(); + this.rMin = new Vector3d(); + this.rMax = new Vector3d(); + this.rPosition = new Vector3d(); + this.rConsumerResult = new Vector3d(); + this.rWarpVectors = new ReusableList<>(); + this.rWarpDistances = new ReusableList<>(); + this.rWeights = new ReusableList<>(); + this.rPositionsContext = new PositionProvider.Context(); + this.rChildContext = new Density.Context(); } } @@ -59,19 +78,17 @@ public class PositionsHorizontalPinchDensity extends Density { } else if (this.positions == null) { return this.input.process(context); } else { - PositionsHorizontalPinchDensity.Cache cache = this.threadData.get(context.workerId); - Vector3d warpVector; - if (cache.x == context.position.x && cache.z == context.position.z && !cache.hasValue) { - warpVector = cache.warpVector; + if (this.cache.x == context.position.x && this.cache.z == context.position.z && !this.cache.hasValue) { + this.rWarpVector.assign(this.cache.warpVector); } else { - warpVector = this.calculateWarpVector(context); - cache.warpVector = warpVector; + this.calculateWarpVector(context, this.rWarpVector); + this.cache.warpVector = this.rWarpVector; } - Vector3d position = new Vector3d(warpVector.x + context.position.x, warpVector.y + context.position.y, warpVector.z + context.position.z); - Density.Context childContext = new Density.Context(context); - childContext.position = position; - return this.input.process(childContext); + this.rPosition.assign(this.rWarpVector.x + context.position.x, this.rWarpVector.y + context.position.y, this.rWarpVector.z + context.position.z); + this.rChildContext.assign(context); + this.rChildContext.position = this.rPosition; + return this.input.process(this.rChildContext); } } @@ -84,66 +101,66 @@ public class PositionsHorizontalPinchDensity extends Density { this.input = inputs[0]; } - public Vector3d calculateWarpVector(@Nonnull Density.Context context) { - Vector3d position = context.position; - Vector3d min = new Vector3d(position.x - this.maxDistance, this.positionsMinY, position.z - this.maxDistance); - Vector3d max = new Vector3d(position.x + this.maxDistance, this.positionsMaxY, position.z + this.maxDistance); - Vector3d samplePoint = position.clone(); - ArrayList warpVectors = new ArrayList<>(10); - ArrayList warpDistances = new ArrayList<>(10); - Consumer consumer = iteratedPosition -> { - double distance = Calculator.distance(iteratedPosition.x, iteratedPosition.z, samplePoint.x, samplePoint.z); - if (!(distance > this.maxDistance)) { - double normalizedDistance = distance / this.maxDistance; - Vector3d warpVectorx = iteratedPosition.clone().addScaled(samplePoint, -1.0); - warpVectorx.setY(0.0); - double radialDistance; - if (this.distanceNormalized) { - radialDistance = this.pinchCurve.applyAsDouble(normalizedDistance); - radialDistance *= this.maxDistance; - } else { - radialDistance = this.pinchCurve.applyAsDouble(distance); - } - - if (!(Math.abs(warpVectorx.length()) < 1.0E-9)) { - warpVectorx.setLength(radialDistance); - } - - warpVectors.add(warpVectorx); - warpDistances.add(normalizedDistance); + private void consumer(@Nonnull Vector3d iteratedPosition) { + double distance = Calculator.distance(iteratedPosition.x, iteratedPosition.z, this.rSamplePoint.x, this.rSamplePoint.z); + if (!(distance > this.maxDistance)) { + double normalizedDistance = distance / this.maxDistance; + this.rConsumerResult.assign(iteratedPosition).subtract(this.rSamplePoint); + this.rConsumerResult.setY(0.0); + double radialDistance; + if (this.distanceNormalized) { + radialDistance = this.pinchCurve.applyAsDouble(normalizedDistance); + radialDistance *= this.maxDistance; + } else { + radialDistance = this.pinchCurve.applyAsDouble(distance); } - }; - PositionProvider.Context positionsContext = new PositionProvider.Context(); - positionsContext.minInclusive = min; - positionsContext.maxExclusive = max; - positionsContext.consumer = consumer; - this.positions.positionsIn(positionsContext); - if (warpVectors.isEmpty()) { - return new Vector3d(0.0, 0.0, 0.0); - } else if (warpVectors.size() == 1) { - return warpVectors.getFirst(); + + if (!(Math.abs(this.rConsumerResult.length()) < 1.0E-9)) { + this.rConsumerResult.setLength(radialDistance); + } + + if (this.rWarpVectors.isAtHardCapacity()) { + this.rWarpVectors.expandAndSet(this.rConsumerResult.clone()); + } else { + this.rWarpVectors.expandAndGet().assign(this.rConsumerResult); + } + + this.rWarpDistances.expandAndSet(normalizedDistance); + } + } + + public void calculateWarpVector(@Nonnull Density.Context context, @Nonnull Vector3d vector_out) { + this.rMin.assign(context.position.x - this.maxDistance, this.positionsMinY, context.position.z - this.maxDistance); + this.rMax.assign(context.position.x + this.maxDistance, this.positionsMaxY, context.position.z + this.maxDistance); + this.rSamplePoint.assign(context.position); + this.rWarpVectors.clear(); + this.rWarpDistances.clear(); + this.rPositionsContext.minInclusive = this.rMin; + this.rPositionsContext.maxExclusive = this.rMax; + this.rPositionsContext.consumer = this::consumer; + this.positions.positionsIn(this.rPositionsContext); + if (this.rWarpVectors.getSoftSize() == 0) { + vector_out.assign(0.0, 0.0, 0.0); + } else if (this.rWarpVectors.getSoftSize() == 1) { + vector_out.assign(this.rWarpVectors.get(0)); } else { - int possiblePointsSize = warpVectors.size(); - ArrayList weights = new ArrayList<>(warpDistances.size()); + int possiblePointsSize = this.rWarpVectors.getSoftSize(); + this.rWeights.clear(); double totalWeight = 0.0; for (int i = 0; i < possiblePointsSize; i++) { - double distance = warpDistances.get(i); + double distance = this.rWarpDistances.get(i); double weight = 1.0 - distance; - weights.add(weight); + this.rWeights.expandAndSet(weight); totalWeight += weight; } - Vector3d totalWarpVector = new Vector3d(); - for (int i = 0; i < possiblePointsSize; i++) { - double weight = weights.get(i) / totalWeight; - Vector3d warpVector = warpVectors.get(i); + double weight = this.rWeights.get(i) / totalWeight; + Vector3d warpVector = this.rWarpVectors.get(i); warpVector.scale(weight); - totalWarpVector.add(warpVector); + vector_out.add(warpVector); } - - return totalWarpVector; } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsPinchDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsPinchDensity.java index 5d70cc5f..13f3f7b5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsPinchDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsPinchDensity.java @@ -1,11 +1,10 @@ package com.hypixel.hytale.builtin.hytalegenerator.density.nodes; +import com.hypixel.hytale.builtin.hytalegenerator.ReusableList; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; import com.hypixel.hytale.math.vector.Vector3d; import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; -import java.util.ArrayList; -import java.util.function.Consumer; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -17,6 +16,14 @@ public class PositionsPinchDensity extends Density { private Double2DoubleFunction pinchCurve; private double maxDistance; private boolean distanceNormalized; + private final Vector3d rMin; + private final Vector3d rMax; + private final Vector3d rSamplePoint; + private final Vector3d rWarpVector; + private final ReusableList rWarpVectors; + private final ReusableList rWarpDistances; + private final ReusableList rWeights; + private final Density.Context rChildContext; public PositionsPinchDensity( @Nullable Density input, @Nullable PositionProvider positions, @Nonnull Double2DoubleFunction pinchCurve, double maxDistance, boolean distanceNormalized @@ -29,6 +36,41 @@ public class PositionsPinchDensity extends Density { this.pinchCurve = pinchCurve; this.maxDistance = maxDistance; this.distanceNormalized = distanceNormalized; + this.rMin = new Vector3d(); + this.rMax = new Vector3d(); + this.rSamplePoint = new Vector3d(); + this.rWarpVector = new Vector3d(); + this.rWarpVectors = new ReusableList<>(); + this.rWarpDistances = new ReusableList<>(); + this.rWeights = new ReusableList<>(); + this.rChildContext = new Density.Context(); + } + } + + private void consumer(@Nonnull Vector3d p) { + double distance = p.distanceTo(this.rSamplePoint); + if (!(distance > this.maxDistance)) { + double normalizedDistance = distance / this.maxDistance; + this.rWarpVector.assign(p).subtract(this.rSamplePoint); + double radialDistance; + if (this.distanceNormalized) { + radialDistance = this.pinchCurve.applyAsDouble(normalizedDistance); + radialDistance *= this.maxDistance; + } else { + radialDistance = this.pinchCurve.applyAsDouble(distance); + } + + if (!(Math.abs(this.rWarpVector.length()) < 1.0E-9)) { + this.rWarpVector.setLength(radialDistance); + } + + if (this.rWarpVectors.isAtHardCapacity()) { + this.rWarpVectors.expandAndSet(this.rWarpVector.clone()); + } else { + this.rWarpVectors.expandAndGet().assign(this.rWarpVector); + } + + this.rWarpDistances.expandAndSet(normalizedDistance); } } @@ -39,63 +81,41 @@ public class PositionsPinchDensity extends Density { } else if (this.positions == null) { return this.input.process(context); } else { - Vector3d min = new Vector3d(context.position.x - this.maxDistance, context.position.y - this.maxDistance, context.position.z - this.maxDistance); - Vector3d max = new Vector3d(context.position.x + this.maxDistance, context.position.y + this.maxDistance, context.position.z + this.maxDistance); - Vector3d samplePoint = context.position.clone(); - ArrayList warpVectors = new ArrayList<>(10); - ArrayList warpDistances = new ArrayList<>(10); - Consumer consumer = p -> { - double distance = p.distanceTo(samplePoint); - if (!(distance > this.maxDistance)) { - double normalizedDistance = distance / this.maxDistance; - Vector3d warpVectorx = p.clone().addScaled(samplePoint, -1.0); - double radialDistance; - if (this.distanceNormalized) { - radialDistance = this.pinchCurve.applyAsDouble(normalizedDistance); - radialDistance *= this.maxDistance; - } else { - radialDistance = this.pinchCurve.applyAsDouble(distance); - } - - if (!(Math.abs(warpVectorx.length()) < 1.0E-9)) { - warpVectorx.setLength(radialDistance); - } - - warpVectors.add(warpVectorx); - warpDistances.add(normalizedDistance); - } - }; + this.rMin.assign(context.position.x - this.maxDistance, context.position.y - this.maxDistance, context.position.z - this.maxDistance); + this.rMax.assign(context.position.x + this.maxDistance, context.position.y + this.maxDistance, context.position.z + this.maxDistance); + this.rSamplePoint.assign(context.position); + this.rWarpVectors.clear(); + this.rWarpDistances.clear(); PositionProvider.Context positionsContext = new PositionProvider.Context(); - positionsContext.minInclusive = min; - positionsContext.maxExclusive = max; - positionsContext.consumer = consumer; - positionsContext.workerId = context.workerId; + positionsContext.minInclusive = this.rMin; + positionsContext.maxExclusive = this.rMax; + positionsContext.consumer = this::consumer; this.positions.positionsIn(positionsContext); - if (warpVectors.isEmpty()) { + if (this.rWarpVectors.getSoftSize() == 0) { return this.input.process(context); - } else if (warpVectors.size() == 1) { - Vector3d warpVector = warpVectors.getFirst(); - samplePoint.add(warpVector); - Density.Context childContext = new Density.Context(context); - context.position = samplePoint; - return this.input.process(childContext); + } else if (this.rWarpVectors.getSoftSize() == 1) { + Vector3d warpVector = this.rWarpVectors.get(0); + this.rSamplePoint.add(warpVector); + this.rChildContext.assign(context); + this.rChildContext.position = this.rSamplePoint; + return this.input.process(this.rChildContext); } else { - int possiblePointsSize = warpVectors.size(); - ArrayList weights = new ArrayList<>(warpDistances.size()); + int possiblePointsSize = this.rWarpVectors.getSoftSize(); + this.rWeights.clear(); double totalWeight = 0.0; for (int i = 0; i < possiblePointsSize; i++) { - double distance = warpDistances.get(i); + double distance = this.rWarpDistances.get(i); double weight = 1.0 - distance; - weights.add(weight); + this.rWeights.expandAndSet(weight); totalWeight += weight; } for (int i = 0; i < possiblePointsSize; i++) { - double weight = weights.get(i) / totalWeight; - Vector3d warpVector = warpVectors.get(i); + double weight = this.rWeights.get(i) / totalWeight; + Vector3d warpVector = this.rWarpVectors.get(i); warpVector.scale(weight); - samplePoint.add(warpVector); + this.rSamplePoint.add(warpVector); } return this.input.process(context); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsTwistDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsTwistDensity.java index 7df4e003..986aae05 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsTwistDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PositionsTwistDensity.java @@ -1,12 +1,11 @@ package com.hypixel.hytale.builtin.hytalegenerator.density.nodes; +import com.hypixel.hytale.builtin.hytalegenerator.ReusableList; import com.hypixel.hytale.builtin.hytalegenerator.VectorUtil; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; import com.hypixel.hytale.math.vector.Vector3d; import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; -import java.util.ArrayList; -import java.util.function.Consumer; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -20,6 +19,16 @@ public class PositionsTwistDensity extends Density { private double maxDistance; private boolean distanceNormalized; private boolean zeroPositionsY; + private final Vector3d rMin; + private final Vector3d rMax; + private final Vector3d rSamplePoint; + private final Vector3d rQueryPosition; + private final Vector3d rWarpVector; + private final ReusableList rWarpVectors; + private final ReusableList rWarpDistances; + private final ReusableList rWeights; + private final PositionProvider.Context rPositionsContext; + private final Density.Context rChildContext; public PositionsTwistDensity( @Nullable Density input, @@ -44,6 +53,48 @@ public class PositionsTwistDensity extends Density { this.maxDistance = maxDistance; this.distanceNormalized = distanceNormalized; this.zeroPositionsY = zeroPositionsY; + this.rMin = new Vector3d(); + this.rMax = new Vector3d(); + this.rSamplePoint = new Vector3d(); + this.rQueryPosition = new Vector3d(); + this.rWarpVector = new Vector3d(); + this.rWarpVectors = new ReusableList<>(); + this.rWarpDistances = new ReusableList<>(); + this.rWeights = new ReusableList<>(); + this.rPositionsContext = new PositionProvider.Context(); + this.rChildContext = new Density.Context(); + } + } + + public void consumer(@Nonnull Vector3d p) { + double distance = p.distanceTo(this.rQueryPosition); + if (!(distance > this.maxDistance)) { + double normalizedDistance = distance / this.maxDistance; + this.rWarpVector.assign(this.rSamplePoint); + double twistAngle; + if (this.distanceNormalized) { + twistAngle = this.twistCurve.applyAsDouble(normalizedDistance); + } else { + twistAngle = this.twistCurve.applyAsDouble(distance); + } + + twistAngle /= 180.0; + twistAngle *= Math.PI; + this.rWarpVector.subtract(p); + VectorUtil.rotateAroundAxis(this.rWarpVector, this.twistAxis, twistAngle); + this.rWarpVector.add(p); + this.rWarpVector.subtract(this.rSamplePoint); + if (this.rWarpVectors.isAtHardCapacity()) { + this.rWarpVectors.expandAndSet(this.rWarpVector.clone()); + } else { + this.rWarpVectors.expandAndGet().assign(this.rWarpVector); + } + + if (this.distanceNormalized) { + this.rWarpDistances.expandAndSet(normalizedDistance); + } else { + this.rWarpDistances.expandAndSet(distance); + } } } @@ -54,76 +105,52 @@ public class PositionsTwistDensity extends Density { } else if (this.positions == null) { return this.input.process(context); } else { - Vector3d min = new Vector3d(context.position.x - this.maxDistance, context.position.y - this.maxDistance, context.position.z - this.maxDistance); - Vector3d max = new Vector3d(context.position.x + this.maxDistance, context.position.y + this.maxDistance, context.position.z + this.maxDistance); - Vector3d samplePoint = context.position.clone(); - Vector3d queryPosition = context.position.clone(); + this.rMin.assign(context.position.x - this.maxDistance, context.position.y - this.maxDistance, context.position.z - this.maxDistance); + this.rMax.assign(context.position.x + this.maxDistance, context.position.y + this.maxDistance, context.position.z + this.maxDistance); + this.rSamplePoint.assign(context.position); + this.rQueryPosition.assign(context.position); if (this.zeroPositionsY) { - queryPosition.y = 0.0; - min.y = -1.0; - max.y = 1.0; + this.rQueryPosition.y = 0.0; + this.rMin.y = -1.0; + this.rMax.y = 1.0; } - ArrayList warpVectors = new ArrayList<>(10); - ArrayList warpDistances = new ArrayList<>(10); - Consumer consumer = p -> { - double distance = p.distanceTo(queryPosition); - if (!(distance > this.maxDistance)) { - double normalizedDistance = distance / this.maxDistance; - Vector3d warpVectorx = samplePoint.clone(); - double twistAngle; - if (this.distanceNormalized) { - twistAngle = this.twistCurve.applyAsDouble(normalizedDistance); - } else { - twistAngle = this.twistCurve.applyAsDouble(distance); - } - - twistAngle /= 180.0; - twistAngle *= Math.PI; - warpVectorx.subtract(p); - VectorUtil.rotateAroundAxis(warpVectorx, this.twistAxis, twistAngle); - warpVectorx.add(p); - warpVectorx.subtract(samplePoint); - warpVectors.add(warpVectorx); - if (this.distanceNormalized) { - warpDistances.add(normalizedDistance); - } else { - warpDistances.add(distance); - } - } - }; - PositionProvider.Context positionsContext = new PositionProvider.Context(min, max, consumer, null, context.workerId); - this.positions.positionsIn(positionsContext); - if (warpVectors.isEmpty()) { + this.rWarpVectors.clear(); + this.rWarpDistances.clear(); + this.rPositionsContext.minInclusive = this.rMin; + this.rPositionsContext.maxExclusive = this.rMax; + this.rPositionsContext.consumer = this::consumer; + this.positions.positionsIn(this.rPositionsContext); + if (this.rWarpVectors.getSoftSize() == 0) { return this.input.process(context); - } else if (warpVectors.size() == 1) { - Vector3d warpVector = warpVectors.getFirst(); - samplePoint.add(warpVector); + } else if (this.rWarpVectors.getSoftSize() == 1) { + Vector3d warpVector = this.rWarpVectors.get(0); + this.rSamplePoint.add(warpVector); Density.Context childContext = new Density.Context(context); - childContext.position = samplePoint; + childContext.position = this.rSamplePoint; return this.input.process(childContext); } else { - int possiblePointsSize = warpVectors.size(); - ArrayList weights = new ArrayList<>(warpDistances.size()); + int possiblePointsSize = this.rWarpVectors.getSoftSize(); + this.rWeights.clear(); double totalWeight = 0.0; for (int i = 0; i < possiblePointsSize; i++) { - double distance = warpDistances.get(i); + double distance = this.rWarpDistances.get(i); double weight = 1.0 - distance; - weights.add(weight); + this.rWeights.expandAndSet(weight); totalWeight += weight; } for (int i = 0; i < possiblePointsSize; i++) { - double weight = weights.get(i) / totalWeight; - Vector3d warpVector = warpVectors.get(i); + double weight = this.rWeights.get(i) / totalWeight; + Vector3d warpVector = this.rWarpVectors.get(i); warpVector.scale(weight); - samplePoint.add(warpVector); + this.rSamplePoint.add(warpVector); } - Density.Context childContext = new Density.Context(context); - childContext.position = samplePoint; - return this.input.process(childContext); + this.rChildContext.assign(context); + this.rChildContext.position = this.rSamplePoint; + return this.input.process(this.rChildContext); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/RotatorDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/RotatorDensity.java index 01aaba5a..51a2d8c5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/RotatorDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/RotatorDensity.java @@ -16,6 +16,8 @@ public class RotatorDensity extends Density { private final double spinAngle; @Nonnull private final RotatorDensity.SpecialCase axisSpecialCase; + private final Vector3d rChildPosition; + private final Density.Context rChildContext; public RotatorDensity(@Nonnull Density input, @Nonnull Vector3d newYAxis, double spinAngle) { this.input = input; @@ -41,6 +43,8 @@ public class RotatorDensity extends Density { this.tiltAxis = yAxis.cross(newYAxis); this.tiltAngle = Math.acos(newYAxis.dot(yAxis) / (newYAxis.length() * yAxis.length())); + this.rChildPosition = new Vector3d(); + this.rChildContext = new Density.Context(); } @Override @@ -48,18 +52,18 @@ public class RotatorDensity extends Density { if (this.input == null) { return 0.0; } else { - Vector3d childPosition = context.position.clone(); + this.rChildPosition.assign(context.position); switch (this.axisSpecialCase) { case INVERTED_Y_AXIS: - childPosition.scale(-1.0); + this.rChildPosition.scale(-1.0); case NONE: - VectorUtil.rotateAroundAxis(childPosition, this.tiltAxis, this.tiltAngle); + VectorUtil.rotateAroundAxis(this.rChildPosition, this.tiltAxis, this.tiltAngle); case Y_AXIS: default: - VectorUtil.rotateAroundAxis(childPosition, Y_AXIS, this.spinAngle); - Density.Context childContext = new Density.Context(context); - childContext.position = childPosition; - return this.input.process(childContext); + VectorUtil.rotateAroundAxis(this.rChildPosition, Y_AXIS, this.spinAngle); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + return this.input.process(this.rChildContext); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ScaleDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ScaleDensity.java index 9d5392b1..9caf6dd8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ScaleDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ScaleDensity.java @@ -11,11 +11,15 @@ public class ScaleDensity extends Density { private final boolean isInvalid; @Nullable private Density input; + private final Vector3d rChildPosition; + private final Density.Context rChildContext; public ScaleDensity(double scaleX, double scaleY, double scaleZ, Density input) { this.scale = new Vector3d(1.0 / scaleX, 1.0 / scaleY, 1.0 / scaleZ); this.isInvalid = scaleX == 0.0 || scaleY == 0.0 || scaleZ == 0.0; this.input = input; + this.rChildPosition = new Vector3d(); + this.rChildContext = new Density.Context(); } @Override @@ -25,11 +29,11 @@ public class ScaleDensity extends Density { } else if (this.isInvalid) { return 0.0; } else { - Vector3d scaledPosition = context.position.clone(); - scaledPosition.scale(this.scale); - Density.Context childContext = new Density.Context(context); - childContext.position = scaledPosition; - return this.input.process(childContext); + this.rChildPosition.assign(context.position); + this.rChildPosition.scale(this.scale); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + return this.input.process(this.rChildContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ShellDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ShellDensity.java index 95877745..04fa797a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ShellDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ShellDensity.java @@ -16,12 +16,14 @@ public class ShellDensity extends Density { @Nonnull private final Vector3d axis; private final boolean isMirrored; + private final Vector3d rRadialVector; public ShellDensity(@Nonnull Double2DoubleFunction angleCurve, @Nonnull Double2DoubleFunction distanceCurve, @Nonnull Vector3d axis, boolean isMirrored) { this.angleCurve = angleCurve; this.distanceCurve = distanceCurve; this.axis = axis; this.isMirrored = isMirrored; + this.rRadialVector = new Vector3d(); } @Override @@ -30,14 +32,14 @@ public class ShellDensity extends Density { if (this.axis.length() == 0.0) { return 0.0; } else { - Vector3d radialVector = context.position.clone(); + this.rRadialVector.assign(context.position); double amplitude = this.distanceCurve.applyAsDouble(distance); if (amplitude == 0.0) { return 0.0; - } else if (radialVector.length() <= 1.0E-9) { + } else if (this.rRadialVector.length() <= 1.0E-9) { return amplitude; } else { - double angle = VectorUtil.angle(radialVector, this.axis); + double angle = VectorUtil.angle(this.rRadialVector, this.axis); angle /= Math.PI; angle *= 180.0; if (this.isMirrored && angle > 90.0) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/SliderDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/SliderDensity.java index 97beb3fb..47dcf41d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/SliderDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/SliderDensity.java @@ -11,12 +11,16 @@ public class SliderDensity extends Density { private final double slideZ; @Nullable private Density input; + private final Vector3d rChildPosition; + private final Density.Context rChildContext; public SliderDensity(double slideX, double slideY, double slideZ, Density input) { this.slideX = slideX; this.slideY = slideY; this.slideZ = slideZ; this.input = input; + this.rChildPosition = new Vector3d(); + this.rChildContext = new Density.Context(); } @Override @@ -24,10 +28,10 @@ public class SliderDensity extends Density { if (this.input == null) { return 0.0; } else { - Vector3d childPosition = new Vector3d(context.position.x - this.slideX, context.position.y - this.slideY, context.position.z - this.slideZ); - Density.Context childContext = new Density.Context(context); - childContext.position = childPosition; - return this.input.process(childContext); + this.rChildPosition.assign(context.position.x - this.slideX, context.position.y - this.slideY, context.position.z - this.slideZ); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + return this.input.process(this.rChildContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/SwitchStateDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/SwitchStateDensity.java index fe939c97..576829c8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/SwitchStateDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/SwitchStateDensity.java @@ -9,10 +9,12 @@ public class SwitchStateDensity extends Density { @Nullable private Density input; private final int switchState; + private final Density.Context rChildContext; public SwitchStateDensity(Density input, int switchState) { this.input = input; this.switchState = switchState; + this.rChildContext = new Density.Context(); } @Override @@ -20,8 +22,8 @@ public class SwitchStateDensity extends Density { if (this.input == null) { return 0.0; } else { - Density.Context childContext = new Density.Context(context); - childContext.switchState = this.switchState; + this.rChildContext.assign(context); + this.rChildContext.switchState = this.switchState; return this.input.process(context); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/TerrainDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/TerrainDensity.java index 3c24de6e..df0eb8e7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/TerrainDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/TerrainDensity.java @@ -6,6 +6,6 @@ import javax.annotation.Nonnull; public class TerrainDensity extends Density { @Override public double process(@Nonnull Density.Context context) { - return context.terrainDensityProvider == null ? 0.0 : context.terrainDensityProvider.get(context.position.toVector3i(), context.workerId); + return context.terrainDensityProvider == null ? 0.0 : context.terrainDensityProvider.get(context.position.toVector3i()); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/VectorWarpDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/VectorWarpDensity.java index 3f23e304..2b64a082 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/VectorWarpDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/VectorWarpDensity.java @@ -13,12 +13,16 @@ public class VectorWarpDensity extends Density { private final double warpFactor; @Nonnull private final Vector3d warpVector; + private final Vector3d rSamplePoint; + private final Density.Context rChildContext; public VectorWarpDensity(@Nonnull Density input, @Nonnull Density warpInput, double warpFactor, @Nonnull Vector3d warpVector) { this.input = input; this.warpInput = warpInput; this.warpFactor = warpFactor; this.warpVector = warpVector; + this.rSamplePoint = new Vector3d(); + this.rChildContext = new Density.Context(); } @Override @@ -30,13 +34,13 @@ public class VectorWarpDensity extends Density { } else { double warp = this.warpInput.process(context); warp *= this.warpFactor; - Vector3d samplePoint = this.warpVector.clone(); - samplePoint.setLength(1.0); - samplePoint.scale(warp); - samplePoint.add(context.position); - Density.Context childContext = new Density.Context(context); - childContext.position = samplePoint; - return this.input.process(childContext); + this.rSamplePoint.assign(this.warpVector); + this.rSamplePoint.setLength(1.0); + this.rSamplePoint.scale(warp); + this.rSamplePoint.add(context.position); + this.rChildContext.assign(context); + this.rChildContext.position = this.rSamplePoint; + return this.input.process(this.rChildContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/XOverrideDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/XOverrideDensity.java index 99c952ad..3eb1df41 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/XOverrideDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/XOverrideDensity.java @@ -8,18 +8,22 @@ public class XOverrideDensity extends Density { @Nonnull private Density input; private final double value; + private final Density.Context rChildContext; + private final Vector3d rChildPosition; public XOverrideDensity(@Nonnull Density input, double value) { this.input = input; this.value = value; + this.rChildContext = new Density.Context(); + this.rChildPosition = new Vector3d(); } @Override public double process(@Nonnull Density.Context context) { - Vector3d childPosition = new Vector3d(this.value, context.position.y, context.position.z); - Density.Context childContext = new Density.Context(context); - childContext.position = childPosition; - return this.input.process(childContext); + this.rChildPosition.assign(this.value, context.position.y, context.position.z); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + return this.input.process(this.rChildContext); } @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/YOverrideDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/YOverrideDensity.java index 09536790..7091cf4c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/YOverrideDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/YOverrideDensity.java @@ -8,18 +8,22 @@ public class YOverrideDensity extends Density { @Nonnull private Density input; private final double value; + private final Density.Context rChildContext; + private final Vector3d rChildPosition; public YOverrideDensity(@Nonnull Density input, double value) { this.input = input; this.value = value; + this.rChildContext = new Density.Context(); + this.rChildPosition = new Vector3d(); } @Override public double process(@Nonnull Density.Context context) { - Vector3d childPosition = new Vector3d(context.position.x, this.value, context.position.z); - Density.Context childContext = new Density.Context(context); - childContext.position = childPosition; - return this.input.process(childContext); + this.rChildPosition.assign(context.position.x, this.value, context.position.z); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + return this.input.process(this.rChildContext); } @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ZOverrideDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ZOverrideDensity.java index 37b54d38..14374818 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ZOverrideDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/ZOverrideDensity.java @@ -8,18 +8,22 @@ public class ZOverrideDensity extends Density { @Nonnull private Density input; private final double value; + private final Density.Context rChildContext; + private final Vector3d rChildPosition; public ZOverrideDensity(@Nonnull Density input, double value) { this.input = input; this.value = value; + this.rChildContext = new Density.Context(); + this.rChildPosition = new Vector3d(); } @Override public double process(@Nonnull Density.Context context) { - Vector3d childPosition = new Vector3d(context.position.x, context.position.y, this.value); - Density.Context childContext = new Density.Context(context); - childContext.position = childPosition; - return this.input.process(childContext); + this.rChildPosition.assign(context.position.x, context.position.y, this.value); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + return this.input.process(this.rChildContext); } @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/PositionsDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/PositionsDensity.java index ba6c4843..8789e62f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/PositionsDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/PositionsDensity.java @@ -18,6 +18,13 @@ public class PositionsDensity extends Density { private final ReturnType returnType; @Nonnull private final DistanceFunction distanceFunction; + private final Vector3d rMin; + private final Vector3d rMax; + private final Vector3d rClosestPoint; + private final Vector3d rPreviousClosestPoint; + private final Vector3d rLocalPoint; + private final double[] rDistance; + private final boolean[] rHasClosestPoint; public PositionsDensity( @Nonnull PositionProvider positionsField, @Nonnull ReturnType returnType, @Nonnull DistanceFunction distanceFunction, double maxDistance @@ -30,6 +37,13 @@ public class PositionsDensity extends Density { this.maxDistanceRaw = maxDistance * maxDistance; this.returnType = returnType; this.distanceFunction = distanceFunction; + this.rMin = new Vector3d(); + this.rMax = new Vector3d(); + this.rClosestPoint = new Vector3d(); + this.rPreviousClosestPoint = new Vector3d(); + this.rLocalPoint = new Vector3d(); + this.rDistance = new double[2]; + this.rHasClosestPoint = new boolean[2]; } } @@ -40,44 +54,45 @@ public class PositionsDensity extends Density { @Override public double process(@Nonnull Density.Context context) { - Vector3d min = context.position.clone().subtract(this.maxDistance); - Vector3d max = context.position.clone().add(this.maxDistance); - double[] distance = new double[]{Double.MAX_VALUE, Double.MAX_VALUE}; - boolean[] hasClosestPoint = new boolean[2]; - Vector3d closestPoint = new Vector3d(); - Vector3d previousClosestPoint = new Vector3d(); - Vector3d localPoint = new Vector3d(); + this.rMin.assign(context.position).subtract(this.maxDistance); + this.rMax.assign(context.position).add(this.maxDistance); + this.rDistance[0] = Double.MAX_VALUE; + this.rDistance[1] = Double.MAX_VALUE; + this.rHasClosestPoint[0] = false; + this.rHasClosestPoint[1] = false; + this.rClosestPoint.assign(0.0, 0.0, 0.0); + this.rPreviousClosestPoint.assign(0.0, 0.0, 0.0); + this.rLocalPoint.assign(0.0, 0.0, 0.0); Consumer positionsConsumer = providedPoint -> { - localPoint.x = providedPoint.x - context.position.x; - localPoint.y = providedPoint.y - context.position.y; - localPoint.z = providedPoint.z - context.position.z; - double newDistance = this.distanceFunction.getDistance(localPoint); + this.rLocalPoint.x = providedPoint.x - context.position.x; + this.rLocalPoint.y = providedPoint.y - context.position.y; + this.rLocalPoint.z = providedPoint.z - context.position.z; + double newDistance = this.distanceFunction.getDistance(this.rLocalPoint); if (!(this.maxDistanceRaw < newDistance)) { - distance[1] = Math.max(Math.min(distance[1], newDistance), distance[0]); - if (newDistance < distance[0]) { - distance[0] = newDistance; - previousClosestPoint.assign(closestPoint); - closestPoint.assign(providedPoint); - hasClosestPoint[1] = hasClosestPoint[0]; - hasClosestPoint[0] = true; + this.rDistance[1] = Math.max(Math.min(this.rDistance[1], newDistance), this.rDistance[0]); + if (newDistance < this.rDistance[0]) { + this.rDistance[0] = newDistance; + this.rPreviousClosestPoint.assign(this.rClosestPoint); + this.rClosestPoint.assign(providedPoint); + this.rHasClosestPoint[1] = this.rHasClosestPoint[0]; + this.rHasClosestPoint[0] = true; } } }; PositionProvider.Context positionsContext = new PositionProvider.Context(); - positionsContext.minInclusive = min; - positionsContext.maxExclusive = max; + positionsContext.minInclusive = this.rMin; + positionsContext.maxExclusive = this.rMax; positionsContext.consumer = positionsConsumer; - positionsContext.workerId = context.workerId; this.positionProvider.positionsIn(positionsContext); - distance[0] = Math.sqrt(distance[0]); - distance[1] = Math.sqrt(distance[1]); + this.rDistance[0] = Math.sqrt(this.rDistance[0]); + this.rDistance[1] = Math.sqrt(this.rDistance[1]); return this.returnType .get( - distance[0], - distance[1], + this.rDistance[0], + this.rDistance[1], context.position.clone(), - hasClosestPoint[0] ? closestPoint : null, - hasClosestPoint[1] ? previousClosestPoint : null, + this.rHasClosestPoint[0] ? this.rClosestPoint : null, + this.rHasClosestPoint[1] ? this.rPreviousClosestPoint : null, context ); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/returntypes/CellValueReturnType.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/returntypes/CellValueReturnType.java index 15d45610..68dd802a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/returntypes/CellValueReturnType.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/returntypes/CellValueReturnType.java @@ -9,10 +9,12 @@ public class CellValueReturnType extends ReturnType { @Nonnull private final Density sampleField; private final double defaultValue; + private final Density.Context rChildContext; - public CellValueReturnType(@Nonnull Density sampleField, double defaultValue, int threadCount) { + public CellValueReturnType(@Nonnull Density sampleField, double defaultValue) { this.sampleField = sampleField; this.defaultValue = defaultValue; + this.rChildContext = new Density.Context(); } @Override @@ -27,9 +29,9 @@ public class CellValueReturnType extends ReturnType { if (closestPoint0 == null) { return this.defaultValue; } else { - Density.Context childContext = new Density.Context(context); - childContext.position = closestPoint0; - return this.sampleField.process(childContext); + this.rChildContext.assign(context); + this.rChildContext.position = closestPoint0; + return this.sampleField.process(this.rChildContext); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/returntypes/DensityReturnType.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/returntypes/DensityReturnType.java index bdbb82f5..dfd0538f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/returntypes/DensityReturnType.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/positions/returntypes/DensityReturnType.java @@ -20,9 +20,11 @@ public class DensityReturnType extends ReturnType { @Nonnull private final Density[] sampleDensities; private final boolean calculateDistanceFromWall; + private final Vector3d rScaledSamplePointClone; + private final Density.Context rChildContext; public DensityReturnType( - @Nonnull Density choiceDensity, @Nonnull Map densityDelimiters, boolean calculateDistanceFromWall, double defaultValue, int threadCount + @Nonnull Density choiceDensity, @Nonnull Map densityDelimiters, boolean calculateDistanceFromWall, double defaultValue ) { this.choiceDensity = choiceDensity; this.defaultValue = defaultValue; @@ -37,6 +39,9 @@ public class DensityReturnType extends ReturnType { this.sampleDensities[i] = entry.getValue(); i++; } + + this.rScaledSamplePointClone = new Vector3d(); + this.rChildContext = new Density.Context(); } @Override @@ -50,19 +55,18 @@ public class DensityReturnType extends ReturnType { ) { double distanceFromWall = Double.MAX_VALUE; if (closestPoint0 != null && this.calculateDistanceFromWall) { - distance0 = samplePoint.clone().addScaled(closestPoint0, -1.0).length(); + distance0 = this.rScaledSamplePointClone.assign(samplePoint).subtract(closestPoint0).length(); double fromMaxDistance = Math.abs(super.maxDistance - distance0); if (closestPoint1 == null) { distanceFromWall = fromMaxDistance; } else { - distance1 = samplePoint.clone().addScaled(closestPoint1, -1.0).length(); + distance1 = this.rScaledSamplePointClone.assign(samplePoint).subtract(closestPoint1).length(); double l = distance1 / this.maxDistance; double fromOtherCell = Math.abs(distance1 - distance0) / 2.0; distanceFromWall = fromOtherCell; } } - Density.Context childContext = null; double choiceValue = this.defaultValue; if (closestPoint0 == null) { return this.defaultValue; @@ -72,10 +76,10 @@ public class DensityReturnType extends ReturnType { for (double[] delimiter : this.delimiters) { if (choiceValue >= delimiter[0] && choiceValue < delimiter[1]) { - childContext = new Density.Context(context); - childContext.densityAnchor = closestPoint0.clone(); - childContext.distanceFromCellWall = distanceFromWall; - return this.sampleDensities[i].process(childContext); + this.rChildContext.assign(context); + this.rChildContext.densityAnchor = closestPoint0; + this.rChildContext.distanceFromCellWall = distanceFromWall; + return this.sampleDensities[i].process(this.rChildContext); } i++; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/DensityDelimitedEnvironmentProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/DensityDelimitedEnvironmentProvider.java index 9023a9a4..751b4ae0 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/DensityDelimitedEnvironmentProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/DensityDelimitedEnvironmentProvider.java @@ -12,6 +12,7 @@ public class DensityDelimitedEnvironmentProvider extends EnvironmentProvider { private final List> delimiters = new ArrayList<>(); @Nonnull private final Density density; + private final Density.Context rDensityContext; public DensityDelimitedEnvironmentProvider(@Nonnull List> delimiters, @Nonnull Density density) { for (DelimiterDouble delimiter : delimiters) { @@ -22,11 +23,13 @@ public class DensityDelimitedEnvironmentProvider extends EnvironmentProvider { } this.density = density; + this.rDensityContext = new Density.Context(); } @Override public int getValue(@Nonnull EnvironmentProvider.Context context) { - double densityValue = this.density.process(new Density.Context(context)); + this.rDensityContext.assign(context); + double densityValue = this.density.process(this.rDensityContext); for (DelimiterDouble delimiter : this.delimiters) { if (delimiter.getRange().contains(densityValue)) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/AllStoneMaterialProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/AllStoneMaterialProvider.java deleted file mode 100644 index 44eaf2d8..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/AllStoneMaterialProvider.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.materialproviders; - -import com.hypixel.hytale.builtin.hytalegenerator.material.MaterialCache; -import com.hypixel.hytale.builtin.hytalegenerator.material.SolidMaterial; -import javax.annotation.Nonnull; - -public class AllStoneMaterialProvider extends MaterialProvider { - private final MaterialCache materialCache; - - public AllStoneMaterialProvider(@Nonnull MaterialCache materialCache) { - this.materialCache = materialCache; - } - - public SolidMaterial getVoxelTypeAt(@Nonnull MaterialProvider.Context context) { - return context.depthIntoFloor > 0 ? this.materialCache.ROCK_STONE : this.materialCache.EMPTY_AIR; - } -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/FieldFunctionMaterialProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/FieldFunctionMaterialProvider.java index 234b4704..aa4ba091 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/FieldFunctionMaterialProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/FieldFunctionMaterialProvider.java @@ -10,6 +10,7 @@ public class FieldFunctionMaterialProvider extends MaterialProvider { private final Density density; @Nonnull private final FieldFunctionMaterialProvider.FieldDelimiter[] fieldDelimiters; + private final Density.Context rDensityContext; public FieldFunctionMaterialProvider(@Nonnull Density density, @Nonnull List> delimiters) { this.density = density; @@ -24,13 +25,15 @@ public class FieldFunctionMaterialProvider extends MaterialProvider { for (int i = 0; i < delimiters.size(); i++) { this.fieldDelimiters[i] = delimiters.get(i); } + + this.rDensityContext = new Density.Context(); } @Nullable @Override public V getVoxelTypeAt(@Nonnull MaterialProvider.Context context) { - Density.Context childContext = new Density.Context(context); - double densityValue = this.density.process(childContext); + this.rDensityContext.assign(context); + double densityValue = this.density.process(this.rDensityContext); for (FieldFunctionMaterialProvider.FieldDelimiter delimiter : this.fieldDelimiters) { if (delimiter.isInside(densityValue)) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/GrassTopMaterialProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/GrassTopMaterialProvider.java deleted file mode 100644 index 315f9c7a..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/GrassTopMaterialProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.materialproviders; - -import com.hypixel.hytale.builtin.hytalegenerator.material.SolidMaterial; -import javax.annotation.Nonnull; - -public class GrassTopMaterialProvider extends MaterialProvider { - private final SolidMaterial grass; - private final SolidMaterial dirt; - private final SolidMaterial stone; - private final SolidMaterial empty; - - public GrassTopMaterialProvider(@Nonnull SolidMaterial grass, @Nonnull SolidMaterial dirt, @Nonnull SolidMaterial stone, @Nonnull SolidMaterial empty) { - this.grass = grass; - this.dirt = dirt; - this.stone = stone; - this.empty = empty; - } - - public SolidMaterial getVoxelTypeAt(@Nonnull MaterialProvider.Context context) { - if (context.depthIntoFloor == 1) { - return this.grass; - } else if (context.depthIntoFloor > 1 && context.depthIntoFloor <= 3) { - return this.dirt; - } else { - return context.depthIntoFloor > 3 ? this.stone : this.empty; - } - } -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/MaterialProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/MaterialProvider.java index f1b0fe82..2be21f1b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/MaterialProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/MaterialProvider.java @@ -1,7 +1,6 @@ package com.hypixel.hytale.builtin.hytalegenerator.materialproviders; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.TerrainDensityProvider; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -23,8 +22,6 @@ public abstract class MaterialProvider { public int depthIntoCeiling; public int spaceAboveFloor; public int spaceBelowCeiling; - @Nonnull - public WorkerIndexer.Id workerId; @Nullable public TerrainDensityProvider terrainDensityProvider; public double distanceToBiomeEdge; @@ -36,7 +33,6 @@ public abstract class MaterialProvider { int depthIntoCeiling, int spaceAboveFloor, int spaceBelowCeiling, - @Nonnull WorkerIndexer.Id workerId, @Nullable TerrainDensityProvider terrainDensityProvider, double distanceToBiomeEdge ) { @@ -46,7 +42,6 @@ public abstract class MaterialProvider { this.depthIntoCeiling = depthIntoCeiling; this.spaceAboveFloor = spaceAboveFloor; this.spaceBelowCeiling = spaceBelowCeiling; - this.workerId = workerId; this.terrainDensityProvider = terrainDensityProvider; this.distanceToBiomeEdge = distanceToBiomeEdge; } @@ -58,7 +53,6 @@ public abstract class MaterialProvider { this.depthIntoCeiling = other.depthIntoCeiling; this.spaceAboveFloor = other.spaceAboveFloor; this.spaceBelowCeiling = other.spaceBelowCeiling; - this.workerId = other.workerId; this.terrainDensityProvider = other.terrainDensityProvider; this.distanceToBiomeEdge = other.distanceToBiomeEdge; } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/layers/NoiseThickness.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/layers/NoiseThickness.java index c0e1ce98..93982e87 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/layers/NoiseThickness.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/layers/NoiseThickness.java @@ -3,7 +3,6 @@ package com.hypixel.hytale.builtin.hytalegenerator.materialproviders.spaceanddep import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.MaterialProvider; import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.spaceanddepth.SpaceAndDepthMaterialProvider; -import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -12,20 +11,21 @@ public class NoiseThickness extends SpaceAndDepthMaterialProvider.Layer { private final Density density; @Nullable private final MaterialProvider materialProvider; + private final Density.Context rDensityContext; public NoiseThickness(@Nonnull Density density, @Nullable MaterialProvider materialProvider) { this.density = density; this.materialProvider = materialProvider; + this.rDensityContext = new Density.Context(); } @Override public int getThicknessAt( int x, int y, int z, int depthIntoFloor, int depthIntoCeiling, int spaceAboveFloor, int spaceBelowCeiling, double distanceToBiomeEdge ) { - Density.Context childContext = new Density.Context(); - childContext.position = new Vector3d(x, y, z); - childContext.distanceToBiomeEdge = distanceToBiomeEdge; - return (int)this.density.process(childContext); + this.rDensityContext.position.assign(x, y, z); + this.rDensityContext.distanceToBiomeEdge = distanceToBiomeEdge; + return (int)this.density.process(this.rDensityContext); } @Nullable diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/NStagedChunkGenerator.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/NStagedChunkGenerator.java index 8b677502..f2b109c7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/NStagedChunkGenerator.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/NStagedChunkGenerator.java @@ -28,6 +28,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.blocktype.component.BlockPhysics; +import com.hypixel.hytale.server.core.universe.world.chunk.environment.EnvironmentChunk; 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.worldgen.GeneratedBlockChunk; @@ -40,7 +41,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; @@ -330,6 +330,7 @@ public class NStagedChunkGenerator implements ChunkGenerator { section_timeProbe.start(); Holder section = sections[sectionIndexFinal]; FluidSection fluidSection = fluidSections[sectionIndexFinal]; + Vector3i world_voxelGrid = new Vector3i(); for (int x_voxelGrid = 0; x_voxelGrid < 32; x_voxelGrid++) { for (int z_voxelGrid = 0; z_voxelGrid < 32; z_voxelGrid++) { @@ -338,10 +339,10 @@ public class NStagedChunkGenerator implements ChunkGenerator { for (int y_voxelGrid = minY_voxelGrid; y_voxelGrid < maxY_voxelGrid; y_voxelGrid++) { int sectionY = y_voxelGrid - minY_voxelGrid; - int worldX_voxelGrid = x_voxelGrid + chunkBounds_voxelGrid.min.x; - int worldY_voxelGrid = y_voxelGrid + chunkBounds_voxelGrid.min.y; - int worldZ_voxelGrid = z_voxelGrid + chunkBounds_voxelGrid.min.z; - Material material = materialVoxelSpace.getContent(worldX_voxelGrid, worldY_voxelGrid, worldZ_voxelGrid); + world_voxelGrid.x = x_voxelGrid + chunkBounds_voxelGrid.min.x; + world_voxelGrid.y = y_voxelGrid + chunkBounds_voxelGrid.min.y; + world_voxelGrid.z = z_voxelGrid + chunkBounds_voxelGrid.min.z; + Material material = materialVoxelSpace.getContent(world_voxelGrid); if (material == null) { blockChunk.setBlock(x_voxelGrid, y_voxelGrid, z_voxelGrid, 0, 0, 0); fluidSection.setFluid( @@ -385,16 +386,17 @@ public class NStagedChunkGenerator implements ChunkGenerator { NBufferBundle.Access tintBufferAccess = this.bufferBundle.createBufferAccess(this.tintOutput_bufferType, chunkBounds_bufferGrid); VoxelSpace tintVoxelSpace = new NPixelBufferView<>(tintBufferAccess.createView(), Integer.class); GeneratedBlockChunk blockChunk = generatedChunk.getBlockChunk(); - int worldY_voxelGrid = 0; TimeInstrument.Probe tintsTransfer_timeProbe = transfer_timeProbe.createProbe("Tints"); return CompletableFuture.runAsync(() -> { tintsTransfer_timeProbe.start(); + Vector3i worldPosition_voxelGrid = new Vector3i(); + worldPosition_voxelGrid.y = 0; for (int x_voxelGrid = 0; x_voxelGrid < 32; x_voxelGrid++) { for (int z_voxelGrid = 0; z_voxelGrid < 32; z_voxelGrid++) { - int worldX_voxelGrid = x_voxelGrid + chunkBounds_voxelGrid.min.x; - int worldZ_voxelGrid = z_voxelGrid + chunkBounds_voxelGrid.min.z; - Integer tint = tintVoxelSpace.getContent(worldX_voxelGrid, 0, worldZ_voxelGrid); + worldPosition_voxelGrid.x = x_voxelGrid + chunkBounds_voxelGrid.min.x; + worldPosition_voxelGrid.z = z_voxelGrid + chunkBounds_voxelGrid.min.z; + Integer tint = tintVoxelSpace.getContent(worldPosition_voxelGrid); if (tint == null) { blockChunk.setTint(x_voxelGrid, z_voxelGrid, 0); } else { @@ -422,28 +424,48 @@ public class NStagedChunkGenerator implements ChunkGenerator { Bounds3i chunkBounds_bufferGrid = GridUtils.createChunkBounds_bufferGrid(arguments.x(), arguments.z()); NBufferBundle.Access environmentBufferAccess = this.bufferBundle.createBufferAccess(this.environmentOutput_bufferType, chunkBounds_bufferGrid); VoxelSpace environmentVoxelSpace = new NVoxelBufferView<>(environmentBufferAccess.createView(), Integer.class); - GeneratedBlockChunk blockChunk = generatedChunk.getBlockChunk(); - TimeInstrument.Probe timeProbe = transfer_timeProbe.createProbe("Environment"); - return CompletableFuture.runAsync(() -> { - timeProbe.start(); + EnvironmentChunk.BulkWriter bulkWriter = new EnvironmentChunk.BulkWriter(); + int sectionCounter = 0; + Vector3i taskSize = new Vector3i(8, 0, 8); + Vector3i taskCount = new Vector3i(32 / taskSize.x, 0, 32 / taskSize.z); + List> futures = new ArrayList<>(); - for (int x_voxelGrid = 0; x_voxelGrid < 32; x_voxelGrid++) { - for (int z_voxelGrid = 0; z_voxelGrid < 32; z_voxelGrid++) { - int minY_voxelGrid = 0; - int maxY_voxelGrid = 320; + for (int taskX = 0; taskX < taskCount.x; taskX++) { + for (int taskZ = 0; taskZ < taskCount.z; taskZ++) { + TimeInstrument.Probe timeProbe = transfer_timeProbe.createProbe("Environment Section " + sectionCounter++); + int minX_voxelGrid = taskX * taskSize.x; + int minZ_voxelGrid = taskZ * taskSize.z; + int maxX_voxelGrid = minX_voxelGrid + taskSize.x; + int maxZ_voxelGrid = minZ_voxelGrid + taskSize.z; + CompletableFuture future = CompletableFuture.runAsync(() -> { + timeProbe.start(); + Vector3i world_voxelGrid = new Vector3i(); - for (int y_voxelGrid = 0; y_voxelGrid < 320; y_voxelGrid++) { - int worldX_voxelGrid = x_voxelGrid + chunkBounds_voxelGrid.min.x; - int worldY_voxelGrid = y_voxelGrid + chunkBounds_voxelGrid.min.y; - int worldZ_voxelGrid = z_voxelGrid + chunkBounds_voxelGrid.min.z; - Integer environment = environmentVoxelSpace.getContent(worldX_voxelGrid, worldY_voxelGrid, worldZ_voxelGrid); - blockChunk.setEnvironment(x_voxelGrid, y_voxelGrid, z_voxelGrid, Objects.requireNonNullElse(environment, 0)); + for (int x_voxelGrid = minX_voxelGrid; x_voxelGrid < maxX_voxelGrid; x_voxelGrid++) { + for (int z_voxelGrid = minZ_voxelGrid; z_voxelGrid < maxZ_voxelGrid; z_voxelGrid++) { + EnvironmentChunk.BulkWriter.ColumnWriter columnWriter = bulkWriter.getColumnWriter(x_voxelGrid, z_voxelGrid); + int x_voxelGrid_final = x_voxelGrid; + int z_voxelGrid_final = z_voxelGrid; + columnWriter.intake(y_voxelGrid -> { + world_voxelGrid.x = x_voxelGrid_final + chunkBounds_voxelGrid.min.x; + world_voxelGrid.y = y_voxelGrid + chunkBounds_voxelGrid.min.y; + world_voxelGrid.z = z_voxelGrid_final + chunkBounds_voxelGrid.min.z; + Integer environment = environmentVoxelSpace.getContent(world_voxelGrid); + + assert environment != null; + + return environment; + }); + } } - } - } - timeProbe.stop(); - }, this.concurrentExecutor).handle((r, e) -> { + timeProbe.stop(); + }, this.concurrentExecutor); + futures.add(future); + } + } + + return FutureUtils.allOf(futures).thenRun(() -> bulkWriter.write(generatedChunk.getBlockChunk().getEnvironmentChunk())).handle((r, e) -> { if (e == null) { return (Void)r; } else { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/TerrainDensityProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/TerrainDensityProvider.java index 73c65211..a74cce29 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/TerrainDensityProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/TerrainDensityProvider.java @@ -1,10 +1,9 @@ package com.hypixel.hytale.builtin.hytalegenerator.newsystem; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; @FunctionalInterface public interface TerrainDensityProvider { - double get(@Nonnull Vector3i var1, @Nonnull WorkerIndexer.Id var2); + double get(@Nonnull Vector3i var1); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NBiomeDistanceStage.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NBiomeDistanceStage.java index a2c2da96..40bc787b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NBiomeDistanceStage.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NBiomeDistanceStage.java @@ -1,6 +1,5 @@ package com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i; import com.hypixel.hytale.builtin.hytalegenerator.framework.math.Calculator; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.GridUtils; @@ -23,7 +22,7 @@ public class NBiomeDistanceStage implements NStage { private static final double BUFFER_DIAGONAL_VOXEL_GRID = Math.sqrt(NPixelBuffer.SIZE.x * NPixelBuffer.SIZE.x + NPixelBuffer.SIZE.z * NPixelBuffer.SIZE.z); public static final double DEFAULT_DISTANCE_TO_BIOME_EDGE = Double.MAX_VALUE; public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + public static final Class biomeClass = Integer.class; public static final Class biomeDistanceBufferClass = NSimplePixelBuffer.class; public static final Class biomeDistanceClass = NBiomeDistanceStage.BiomeDistanceEntries.class; private final NParametrizedBufferType biomeInputBufferType; @@ -56,7 +55,7 @@ public class NBiomeDistanceStage implements NStage { @Override public void run(@Nonnull NStage.Context context) { NBufferBundle.Access.View biomeAccess = context.bufferAccess.get(this.biomeInputBufferType); - NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeTypeClass); + NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeClass); NBufferBundle.Access.View biomeDistanceAccess = context.bufferAccess.get(this.biomeDistanceOutputBufferType); NPixelBufferView biomeDistanceSpace = new NPixelBufferView<>(biomeDistanceAccess, biomeDistanceClass); Vector3i position_voxelGrid = new Vector3i(); @@ -71,7 +70,7 @@ public class NBiomeDistanceStage implements NStage { @Nonnull private NBiomeDistanceStage.BiomeDistanceEntries createDistanceTracker( - @Nonnull NBufferBundle.Access.View biomeAccess, @Nonnull NPixelBufferView biomeSpace, @Nonnull Vector3i targetPosition_voxelGrid + @Nonnull NBufferBundle.Access.View biomeAccess, @Nonnull NPixelBufferView biomeSpace, @Nonnull Vector3i targetPosition_voxelGrid ) { NBiomeDistanceStage.BiomeDistanceCounter counter = new NBiomeDistanceStage.BiomeDistanceCounter(); Vector3i position_bufferGrid = new Vector3i(); @@ -84,15 +83,15 @@ public class NBiomeDistanceStage implements NStage { double distanceToBuffer_voxelGrid = distanceToBuffer_voxelGrid(targetPosition_voxelGrid, position_bufferGrid); distanceToBuffer_voxelGrid = Math.max(distanceToBuffer_voxelGrid - 1.0, 0.0); if (!(distanceToBuffer_voxelGrid > this.maxDistance_voxelGrid)) { - NCountedPixelBuffer biomeBuffer = (NCountedPixelBuffer)biomeAccess.getBuffer(position_bufferGrid).buffer(); - List uniqueBiomeTypes = biomeBuffer.getUniqueEntries(); + NCountedPixelBuffer biomeBuffer = (NCountedPixelBuffer)biomeAccess.getBuffer(position_bufferGrid).buffer(); + List uniqueBiomeIds = biomeBuffer.getUniqueEntries(); - assert !uniqueBiomeTypes.isEmpty(); + assert !uniqueBiomeIds.isEmpty(); - if (!allBiomesAreCountedAndFarther(counter, uniqueBiomeTypes, distanceToBuffer_voxelGrid)) { - if (uniqueBiomeTypes.size() == 1) { + if (!allBiomesAreCountedAndFarther(counter, uniqueBiomeIds, distanceToBuffer_voxelGrid)) { + if (uniqueBiomeIds.size() == 1) { if (!(distanceToBuffer_voxelGrid > this.maxDistance_voxelGrid)) { - counter.accountFor(uniqueBiomeTypes.getFirst(), distanceToBuffer_voxelGrid); + counter.accountFor(uniqueBiomeIds.getFirst(), distanceToBuffer_voxelGrid); } } else { Bounds3i bufferBounds_voxelGrid = GridUtils.createColumnBounds_voxelGrid(position_bufferGrid, 0, 1); @@ -111,11 +110,11 @@ public class NBiomeDistanceStage implements NStage { ); distanceToColumn_voxelGrid = Math.max(distanceToColumn_voxelGrid - 1.0, 0.0); if (!(distanceToColumn_voxelGrid > this.maxDistance_voxelGrid)) { - BiomeType biomeType = biomeSpace.getContent(columnPosition_voxelGrid); + Integer biomeId = biomeSpace.getContent(columnPosition_voxelGrid); - assert biomeType != null; + assert biomeId != null; - counter.accountFor(biomeType, distanceToColumn_voxelGrid); + counter.accountFor(biomeId, distanceToColumn_voxelGrid); } } } @@ -183,10 +182,10 @@ public class NBiomeDistanceStage implements NStage { } private static boolean allBiomesAreCountedAndFarther( - @Nonnull NBiomeDistanceStage.BiomeDistanceCounter counter, @Nonnull List uniqueBiomes, double distanceToBuffer_voxelGrid + @Nonnull NBiomeDistanceStage.BiomeDistanceCounter counter, @Nonnull List uniqueBiomes, double distanceToBuffer_voxelGrid ) { - for (BiomeType biomeType : uniqueBiomes) { - if (counter.isCloserThanCounted(biomeType, distanceToBuffer_voxelGrid)) { + for (Integer biomeId : uniqueBiomes) { + if (counter.isCloserThanCounted(biomeId, distanceToBuffer_voxelGrid)) { return false; } } @@ -203,9 +202,9 @@ public class NBiomeDistanceStage implements NStage { BiomeDistanceCounter() { } - boolean isCloserThanCounted(@Nonnull BiomeType biomeType, double distance_voxelGrid) { + boolean isCloserThanCounted(int biomeId, double distance_voxelGrid) { for (NBiomeDistanceStage.BiomeDistanceEntry entry : this.entries) { - if (entry.biomeType == biomeType) { + if (entry.biomeId == biomeId) { return distance_voxelGrid < entry.distance_voxelGrid; } } @@ -213,14 +212,14 @@ public class NBiomeDistanceStage implements NStage { return true; } - void accountFor(@Nonnull BiomeType biomeType, double distance_voxelGrid) { - if (this.cachedEntry != null && this.cachedEntry.biomeType == biomeType) { + void accountFor(int biomeId, double distance_voxelGrid) { + if (this.cachedEntry != null && this.cachedEntry.biomeId == biomeId) { if (!(this.cachedEntry.distance_voxelGrid <= distance_voxelGrid)) { this.cachedEntry.distance_voxelGrid = distance_voxelGrid; } } else { for (NBiomeDistanceStage.BiomeDistanceEntry entry : this.entries) { - if (entry.biomeType == biomeType) { + if (entry.biomeId == biomeId) { this.cachedEntry = entry; if (entry.distance_voxelGrid <= distance_voxelGrid) { return; @@ -232,7 +231,7 @@ public class NBiomeDistanceStage implements NStage { } NBiomeDistanceStage.BiomeDistanceEntry entryx = new NBiomeDistanceStage.BiomeDistanceEntry(); - entryx.biomeType = biomeType; + entryx.biomeId = biomeId; entryx.distance_voxelGrid = distance_voxelGrid; this.entries.add(entryx); this.cachedEntry = entryx; @@ -247,11 +246,11 @@ public class NBiomeDistanceStage implements NStage { this.entries = entries; } - public double distanceToClosestOtherBiome(@Nonnull BiomeType thisBiome) { + public double distanceToClosestOtherBiome(int thisBiomeId) { double smallestDistance = Double.MAX_VALUE; for (NBiomeDistanceStage.BiomeDistanceEntry entry : this.entries) { - if (entry.biomeType != thisBiome) { + if (entry.biomeId != thisBiomeId) { smallestDistance = Math.min(smallestDistance, entry.distance_voxelGrid); } } @@ -261,7 +260,7 @@ public class NBiomeDistanceStage implements NStage { } public static class BiomeDistanceEntry { - public BiomeType biomeType; + public int biomeId; public double distance_voxelGrid; } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NBiomeStage.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NBiomeStage.java index 42610041..24ae1564 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NBiomeStage.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NBiomeStage.java @@ -1,6 +1,5 @@ package com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i; import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiCarta; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.NBufferBundle; @@ -8,32 +7,37 @@ import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers.type.NBufferType; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers.type.NParametrizedBufferType; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NPixelBufferView; +import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; +import com.hypixel.hytale.builtin.hytalegenerator.worldstructure.WorldStructure; import java.util.List; import java.util.Map; import javax.annotation.Nonnull; public class NBiomeStage implements NStage { public static final Class bufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + public static final Class biomeClass = Integer.class; private final NParametrizedBufferType biomeOutputBufferType; private final String stageName; - private BiCarta biomeCarta; + private final WorkerIndexer.Data worldStructure_workerData; - public NBiomeStage(@Nonnull String stageName, @Nonnull NParametrizedBufferType biomeOutputBufferType, @Nonnull BiCarta biomeCarta) { + public NBiomeStage( + @Nonnull String stageName, @Nonnull NParametrizedBufferType biomeOutputBufferType, @Nonnull WorkerIndexer.Data worldStructure_workerData + ) { this.stageName = stageName; this.biomeOutputBufferType = biomeOutputBufferType; - this.biomeCarta = biomeCarta; + this.worldStructure_workerData = worldStructure_workerData; } @Override public void run(@Nonnull NStage.Context context) { NBufferBundle.Access.View biomeAccess = context.bufferAccess.get(this.biomeOutputBufferType); - NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeTypeClass); + NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeClass); + BiCarta biomeMap = this.worldStructure_workerData.get(context.workerId).getBiomeMap(); for (int x = biomeSpace.minX(); x < biomeSpace.maxX(); x++) { for (int z = biomeSpace.minZ(); z < biomeSpace.maxZ(); z++) { - BiomeType biome = this.biomeCarta.apply(x, z, context.workerId); - biomeSpace.set(biome, x, 0, z); + Integer biomeId = biomeMap.apply(x, z, WorkerIndexer.Id.TEMP_0); + biomeSpace.set(biomeId, x, 0, z); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NEnvironmentStage.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NEnvironmentStage.java index 203c9bba..a356c726 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NEnvironmentStage.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NEnvironmentStage.java @@ -1,6 +1,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; +import com.hypixel.hytale.builtin.hytalegenerator.Registry; +import com.hypixel.hytale.builtin.hytalegenerator.biome.Biome; import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i; import com.hypixel.hytale.builtin.hytalegenerator.environmentproviders.EnvironmentProvider; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.GridUtils; @@ -11,6 +12,8 @@ import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers.type.NParametrizedBufferType; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NPixelBufferView; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NVoxelBufferView; +import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; +import com.hypixel.hytale.builtin.hytalegenerator.worldstructure.WorldStructure; import com.hypixel.hytale.math.vector.Vector3i; import java.util.List; import java.util.Map; @@ -18,16 +21,20 @@ import javax.annotation.Nonnull; public class NEnvironmentStage implements NStage { public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + public static final Class biomeTypeClass = Integer.class; public static final Class environmentBufferClass = NVoxelBuffer.class; public static final Class environmentClass = Integer.class; private final NParametrizedBufferType biomeInputBufferType; private final NParametrizedBufferType environmentOutputBufferType; private final Bounds3i inputBounds_bufferGrid; private final String stageName; + private final WorkerIndexer.Data worldStructure_workerData; public NEnvironmentStage( - @Nonnull String stageName, @Nonnull NParametrizedBufferType biomeInputBufferType, @Nonnull NParametrizedBufferType environmentOutputBufferType + @Nonnull String stageName, + @Nonnull NParametrizedBufferType biomeInputBufferType, + @Nonnull NParametrizedBufferType environmentOutputBufferType, + @Nonnull WorkerIndexer.Data worldStructure_workerData ) { assert biomeInputBufferType.isValidType(biomeBufferClass, biomeTypeClass); @@ -36,22 +43,28 @@ public class NEnvironmentStage implements NStage { this.biomeInputBufferType = biomeInputBufferType; this.environmentOutputBufferType = environmentOutputBufferType; this.stageName = stageName; + this.worldStructure_workerData = worldStructure_workerData; this.inputBounds_bufferGrid = GridUtils.createUnitBounds3i(Vector3i.ZERO); } @Override public void run(@Nonnull NStage.Context context) { NBufferBundle.Access.View biomeAccess = context.bufferAccess.get(this.biomeInputBufferType); - NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeTypeClass); + NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeTypeClass); NBufferBundle.Access.View environmentAccess = context.bufferAccess.get(this.environmentOutputBufferType); NVoxelBufferView environmentSpace = new NVoxelBufferView<>(environmentAccess, environmentClass); Bounds3i outputBounds_voxelGrid = environmentSpace.getBounds(); Vector3i position_voxelGrid = new Vector3i(outputBounds_voxelGrid.min); - EnvironmentProvider.Context tintContext = new EnvironmentProvider.Context(position_voxelGrid, context.workerId); + EnvironmentProvider.Context tintContext = new EnvironmentProvider.Context(position_voxelGrid, WorkerIndexer.Id.TEMP_0); + Registry biomeRegistry = this.worldStructure_workerData.get(context.workerId).getBiomeRegistry(); for (position_voxelGrid.x = outputBounds_voxelGrid.min.x; position_voxelGrid.x < outputBounds_voxelGrid.max.x; position_voxelGrid.x++) { for (position_voxelGrid.z = outputBounds_voxelGrid.min.z; position_voxelGrid.z < outputBounds_voxelGrid.max.z; position_voxelGrid.z++) { - BiomeType biome = biomeSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); + Integer biomeId = biomeSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); + + assert biomeId != null; + + Biome biome = biomeRegistry.getObject(biomeId); assert biome != null; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NPropStage.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NPropStage.java index 683f4951..ed409e67 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NPropStage.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NPropStage.java @@ -1,7 +1,8 @@ package com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages; import com.hypixel.hytale.builtin.hytalegenerator.PropField; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; +import com.hypixel.hytale.builtin.hytalegenerator.Registry; +import com.hypixel.hytale.builtin.hytalegenerator.biome.Biome; import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3d; import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i; import com.hypixel.hytale.builtin.hytalegenerator.material.Material; @@ -20,8 +21,11 @@ import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NVoxelBufferVi import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; import com.hypixel.hytale.builtin.hytalegenerator.props.Prop; import com.hypixel.hytale.builtin.hytalegenerator.props.ScanResult; +import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; +import com.hypixel.hytale.builtin.hytalegenerator.worldstructure.WorldStructure; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3i; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -34,7 +38,7 @@ import javax.annotation.Nullable; public class NPropStage implements NStage { public static final double DEFAULT_BACKGROUND_DENSITY = 0.0; public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + public static final Class biomeClass = Integer.class; public static final Class biomeDistanceBufferClass = NSimplePixelBuffer.class; public static final Class biomeDistanceClass = NBiomeDistanceStage.BiomeDistanceEntries.class; public static final Class materialBufferClass = NVoxelBuffer.class; @@ -50,6 +54,7 @@ public class NPropStage implements NStage { private final Bounds3i inputBounds_voxelGrid; private final String stageName; private final MaterialCache materialCache; + private final WorkerIndexer.Data worldStructure_workerData; private final int runtimeIndex; public NPropStage( @@ -61,10 +66,10 @@ public class NPropStage implements NStage { @Nonnull NParametrizedBufferType materialOutputBufferType, @Nonnull NBufferType entityOutputBufferType, @Nonnull MaterialCache materialCache, - @Nonnull List expectedBiomes, + @Nonnull WorkerIndexer.Data worldStructure_workerData, int runtimeIndex ) { - assert biomeInputBufferType.isValidType(biomeBufferClass, biomeTypeClass); + assert biomeInputBufferType.isValidType(biomeBufferClass, biomeClass); assert biomeDistanceInputBufferType.isValidType(biomeDistanceBufferClass, biomeDistanceClass); @@ -82,13 +87,17 @@ public class NPropStage implements NStage { this.entityInputBufferType = entityInputBufferType; this.materialOutputBufferType = materialOutputBufferType; this.entityOutputBufferType = entityOutputBufferType; + this.worldStructure_workerData = worldStructure_workerData; this.stageName = stageName; this.materialCache = materialCache; this.runtimeIndex = runtimeIndex; + List allBiomes = new ArrayList<>(); + this.worldStructure_workerData + .forEach((workerId, worldStructure) -> worldStructure.getBiomeRegistry().forEach((biomeId, biomex) -> allBiomes.add(biomex))); this.inputBounds_voxelGrid = new Bounds3i(); Vector3i range = new Vector3i(); - for (BiomeType biome : expectedBiomes) { + for (Biome biome : allBiomes) { for (PropField propField : biome.getPropFields()) { if (propField.getRuntime() == this.runtimeIndex) { for (Prop prop : propField.getPropDistribution().getAllPossibleProps()) { @@ -114,7 +123,7 @@ public class NPropStage implements NStage { @Override public void run(@Nonnull NStage.Context context) { NBufferBundle.Access.View biomeAccess = context.bufferAccess.get(this.biomeInputBufferType); - NPixelBufferView biomeInputSpace = new NPixelBufferView<>(biomeAccess, biomeTypeClass); + NPixelBufferView biomeInputSpace = new NPixelBufferView<>(biomeAccess, biomeClass); NBufferBundle.Access.View biomeDistanceAccess = context.bufferAccess.get(this.biomeDistanceInputBufferType); NPixelBufferView biomeDistanceSpace = new NPixelBufferView<>(biomeDistanceAccess, biomeDistanceClass); NBufferBundle.Access.View materialInputAccess = context.bufferAccess.get(this.materialInputBufferType); @@ -139,17 +148,20 @@ public class NPropStage implements NStage { entityOutputSpace.copyFrom(entityInputSpace); } - HashSet biomesInBuffer = new HashSet<>(); + Registry biomeRegistry = this.worldStructure_workerData.get(context.workerId).getBiomeRegistry(); + HashSet biomesInBuffer = new HashSet<>(); for (int x = localInputBounds_voxelGrid.min.x; x < localInputBounds_voxelGrid.max.x; x++) { for (int z = localInputBounds_voxelGrid.min.z; z < localInputBounds_voxelGrid.max.z; z++) { - biomesInBuffer.add(biomeInputSpace.getContent(x, 0, z)); + Integer biomeId = biomeInputSpace.getContent(x, 0, z); + Biome biome = biomeRegistry.getObject(biomeId); + biomesInBuffer.add(biome); } } - Map propFieldBiomeMap = new HashMap<>(); + Map propFieldBiomeMap = new HashMap<>(); - for (BiomeType biome : biomesInBuffer) { + for (Biome biome : biomesInBuffer) { for (PropField propField : biome.getPropFields()) { if (propField.getRuntime() == this.runtimeIndex) { propFieldBiomeMap.put(propField, biome); @@ -157,31 +169,34 @@ public class NPropStage implements NStage { } } - for (Entry entry : propFieldBiomeMap.entrySet()) { + for (Entry entry : propFieldBiomeMap.entrySet()) { PropField propFieldx = entry.getKey(); - BiomeType biome = entry.getValue(); + Biome biome = entry.getValue(); PositionProvider positionProvider = propFieldx.getPositionProvider(); Consumer positionsConsumer = position -> { if (localInputBoundsDouble_voxelGrid.contains(position)) { Vector3i positionInt_voxelGrid = position.toVector3i(); - BiomeType biomeAtPosition = biomeInputSpace.getContent(positionInt_voxelGrid.x, 0, positionInt_voxelGrid.z); + Integer biomeIdAtPosition = biomeInputSpace.getContent(positionInt_voxelGrid.x, 0, positionInt_voxelGrid.z); + Biome biomeAtPosition = biomeRegistry.getObject(biomeIdAtPosition); if (biomeAtPosition == biome) { Vector3i position2d_voxelGrid = positionInt_voxelGrid.clone(); position2d_voxelGrid.setY(0); - double distanceToBiomeEdge = biomeDistanceSpace.getContent(position2d_voxelGrid).distanceToClosestOtherBiome(biomeAtPosition); - Prop prop = propField.getPropDistribution().propAt(position, context.workerId, distanceToBiomeEdge); + double distanceToBiomeEdge = biomeDistanceSpace.getContent(position2d_voxelGrid).distanceToClosestOtherBiome(biomeIdAtPosition); + Prop prop = propField.getPropDistribution().propAt(position, WorkerIndexer.Id.TEMP_0, distanceToBiomeEdge); Bounds3i propWriteBounds = prop.getWriteBounds_voxelGrid().clone(); propWriteBounds.offset(positionInt_voxelGrid); if (propWriteBounds.intersects(localOutputBounds_voxelGrid)) { - ScanResult scanResult = prop.scan(positionInt_voxelGrid, materialInputSpace, context.workerId); - Prop.Context propContext = new Prop.Context(scanResult, materialOutputSpace, entityOutputSpace, context.workerId, distanceToBiomeEdge); + ScanResult scanResult = prop.scan(positionInt_voxelGrid, materialInputSpace, WorkerIndexer.Id.TEMP_0); + Prop.Context propContext = new Prop.Context( + scanResult, materialOutputSpace, entityOutputSpace, WorkerIndexer.Id.TEMP_0, distanceToBiomeEdge + ); prop.place(propContext); } } } }; PositionProvider.Context positionsContext = new PositionProvider.Context( - localInputBoundsDouble_voxelGrid.min, localInputBoundsDouble_voxelGrid.max, positionsConsumer, null, context.workerId + localInputBoundsDouble_voxelGrid.min, localInputBoundsDouble_voxelGrid.max, positionsConsumer, null ); positionProvider.positionsIn(positionsContext); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTerrainStage.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTerrainStage.java index 79ddff7e..5f57ac4c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTerrainStage.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTerrainStage.java @@ -1,6 +1,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; +import com.hypixel.hytale.builtin.hytalegenerator.Registry; +import com.hypixel.hytale.builtin.hytalegenerator.biome.Biome; import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.material.Material; @@ -18,6 +19,7 @@ import com.hypixel.hytale.builtin.hytalegenerator.newsystem.containers.FloatCont import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NPixelBufferView; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NVoxelBufferView; import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; +import com.hypixel.hytale.builtin.hytalegenerator.worldstructure.WorldStructure; import com.hypixel.hytale.math.vector.Vector3i; import java.util.ArrayList; import java.util.HashMap; @@ -31,7 +33,7 @@ public class NTerrainStage implements NStage { public static final double ORIGIN_REACH_HALF = 0.5; public static final double QUARTER_PI = Math.PI / 4; public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeClass = BiomeType.class; + public static final Class biomeClass = Integer.class; public static final Class biomeDistanceBufferClass = NSimplePixelBuffer.class; public static final Class biomeDistanceClass = NBiomeDistanceStage.BiomeDistanceEntries.class; public static final Class materialBufferClass = NVoxelBuffer.class; @@ -44,6 +46,7 @@ public class NTerrainStage implements NStage { private final int maxInterpolationRadius_voxelGrid; private final MaterialCache materialCache; private final WorkerIndexer.Data densityContainers; + private final WorkerIndexer.Data worldStructure_workerdata; public NTerrainStage( @Nonnull String stageName, @@ -52,7 +55,8 @@ public class NTerrainStage implements NStage { @Nonnull NParametrizedBufferType materialOutputBufferType, int maxInterpolationRadius_voxelGrid, @Nonnull MaterialCache materialCache, - @Nonnull WorkerIndexer workerIndexer + @Nonnull WorkerIndexer workerIndexer, + @Nonnull WorkerIndexer.Data worldStructure_workerdata ) { assert biomeInputBufferType.isValidType(biomeBufferClass, biomeClass); @@ -62,6 +66,7 @@ public class NTerrainStage implements NStage { assert maxInterpolationRadius_voxelGrid >= 0; + this.worldStructure_workerdata = worldStructure_workerdata; this.biomeInputBufferType = biomeInputBufferType; this.biomeDistanceInputBufferType = biomeDistanceInputBufferType; this.materialOutputBufferType = materialOutputBufferType; @@ -80,7 +85,7 @@ public class NTerrainStage implements NStage { @Override public void run(@Nonnull NStage.Context context) { NBufferBundle.Access.View biomeAccess = context.bufferAccess.get(this.biomeInputBufferType); - NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeClass); + NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeClass); NBufferBundle.Access.View biomeDistanceAccess = context.bufferAccess.get(this.biomeDistanceInputBufferType); NPixelBufferView biomeDistanceSpace = new NPixelBufferView<>(biomeDistanceAccess, biomeDistanceClass); NBufferBundle.Access.View materialAccess = context.bufferAccess.get(this.materialOutputBufferType); @@ -88,8 +93,9 @@ public class NTerrainStage implements NStage { Bounds3i outputBounds_voxelGrid = materialSpace.getBounds(); FloatContainer3d densityContainer = this.densityContainers.get(context.workerId); densityContainer.moveMinTo(outputBounds_voxelGrid.min); - this.generateDensity(densityContainer, biomeSpace, biomeDistanceSpace, context.workerId); - this.generateMaterials(biomeSpace, biomeDistanceSpace, densityContainer, materialSpace, context.workerId); + Registry biomeRegistry = this.worldStructure_workerdata.get(context.workerId).getBiomeRegistry(); + this.generateDensity(densityContainer, biomeSpace, biomeDistanceSpace, biomeRegistry); + this.generateMaterials(biomeSpace, biomeDistanceSpace, densityContainer, materialSpace, biomeRegistry); } @Nonnull @@ -115,15 +121,14 @@ public class NTerrainStage implements NStage { private void generateDensity( @Nonnull FloatContainer3d densityBuffer, - @Nonnull NPixelBufferView biomeSpace, + @Nonnull NPixelBufferView biomeSpace, @Nonnull NPixelBufferView distanceSpace, - @Nonnull WorkerIndexer.Id workerId + @Nonnull Registry biomeRegistry ) { Bounds3i bounds_voxelGrid = densityBuffer.getBounds_voxelGrid(); Vector3i position_voxelGrid = new Vector3i(bounds_voxelGrid.min); Density.Context densityContext = new Density.Context(); densityContext.position = position_voxelGrid.toVector3d(); - densityContext.workerId = workerId; for (position_voxelGrid.x = bounds_voxelGrid.min.x; position_voxelGrid.x < bounds_voxelGrid.max.x; position_voxelGrid.x++) { densityContext.position.x = position_voxelGrid.x; @@ -132,14 +137,22 @@ public class NTerrainStage implements NStage { densityContext.position.z = position_voxelGrid.z; position_voxelGrid.y = 0; position_voxelGrid.dropHash(); - BiomeType biomeAtOrigin = biomeSpace.getContent(position_voxelGrid); + Integer biomeIdAtOrigin = biomeSpace.getContent(position_voxelGrid); + + assert biomeIdAtOrigin != null; + + Biome biomeAtOrigin = biomeRegistry.getObject(biomeIdAtOrigin); + + assert biomeAtOrigin != null; + NBiomeDistanceStage.BiomeDistanceEntries biomeDistances = distanceSpace.getContent(position_voxelGrid); - NTerrainStage.BiomeWeights biomeWeights = createWeights(biomeDistances, biomeAtOrigin, this.maxInterpolationRadius_voxelGrid); - densityContext.distanceToBiomeEdge = biomeDistances.distanceToClosestOtherBiome(biomeAtOrigin); + NTerrainStage.BiomeWeights biomeWeights = createWeights(biomeDistances, biomeIdAtOrigin, this.maxInterpolationRadius_voxelGrid); + densityContext.distanceToBiomeEdge = biomeDistances.distanceToClosestOtherBiome(biomeIdAtOrigin); boolean isFirstBiome = true; for (NTerrainStage.BiomeWeights.Entry biomeWeight : biomeWeights.entries) { - Density density = biomeWeight.biomeType.getTerrainDensity(); + Biome biome = biomeRegistry.getObject(biomeWeight.biomeId); + Density density = biome.getTerrainDensity(); if (isFirstBiome) { for (position_voxelGrid.y = bounds_voxelGrid.min.y; position_voxelGrid.y < bounds_voxelGrid.max.y; position_voxelGrid.y++) { position_voxelGrid.dropHash(); @@ -170,34 +183,37 @@ public class NTerrainStage implements NStage { private float getOrGenerateDensity( @Nonnull Vector3i position_voxelGrid, @Nonnull FloatContainer3d densityBuffer, - @Nonnull NPixelBufferView biomeSpace, + @Nonnull NPixelBufferView biomeSpace, @Nonnull NPixelBufferView distanceSpace, - @Nonnull WorkerIndexer.Id workerId + @Nonnull Registry biomeRegistry ) { return densityBuffer.getBounds_voxelGrid().contains(position_voxelGrid) ? densityBuffer.get(position_voxelGrid) - : this.generateDensity(position_voxelGrid, biomeSpace, distanceSpace, workerId); + : this.generateDensity(position_voxelGrid, biomeSpace, distanceSpace, biomeRegistry); } private float generateDensity( @Nonnull Vector3i position_voxelGrid, - @Nonnull NPixelBufferView biomeSpace, + @Nonnull NPixelBufferView biomeSpace, @Nonnull NPixelBufferView distanceSpace, - @Nonnull WorkerIndexer.Id workerId + @Nonnull Registry biomeRegistry ) { if (!distanceSpace.isInsideSpace(position_voxelGrid.x, 0, position_voxelGrid.z)) { return 0.0F; } else { Density.Context densityContext = new Density.Context(); densityContext.position = position_voxelGrid.toVector3d(); - densityContext.workerId = workerId; - BiomeType biomeAtOrigin = biomeSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); + Integer biomeIdAtOrigin = biomeSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); + + assert biomeIdAtOrigin != null; + NBiomeDistanceStage.BiomeDistanceEntries biomeDistances = distanceSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); - NTerrainStage.BiomeWeights biomeWeights = createWeights(biomeDistances, biomeAtOrigin, this.maxInterpolationRadius_voxelGrid); + NTerrainStage.BiomeWeights biomeWeights = createWeights(biomeDistances, biomeIdAtOrigin, this.maxInterpolationRadius_voxelGrid); float densityResult = 0.0F; for (NTerrainStage.BiomeWeights.Entry biomeWeight : biomeWeights.entries) { - Density density = biomeWeight.biomeType.getTerrainDensity(); + Biome biome = biomeRegistry.getObject(biomeWeight.biomeId); + Density density = biome.getTerrainDensity(); float densityValue = (float)density.process(densityContext); float scaledDensityValue = densityValue * biomeWeight.weight; densityResult += scaledDensityValue; @@ -208,43 +224,42 @@ public class NTerrainStage implements NStage { } private void generateMaterials( - @Nonnull NPixelBufferView biomeSpace, + @Nonnull NPixelBufferView biomeSpace, @Nonnull NPixelBufferView distanceSpace, @Nonnull FloatContainer3d densityBuffer, @Nonnull NVoxelBufferView materialSpace, - @Nonnull WorkerIndexer.Id workerId + @Nonnull Registry biomeRegistry ) { Bounds3i bounds_voxelGrid = materialSpace.getBounds(); + MaterialProvider.Context context = new MaterialProvider.Context( + new Vector3i(), 0.0, 0, 0, 0, 0, position -> this.getOrGenerateDensity(position, densityBuffer, biomeSpace, distanceSpace, biomeRegistry), 0.0 + ); + NTerrainStage.ColumnData columnData = new NTerrainStage.ColumnData(bounds_voxelGrid.min.y, bounds_voxelGrid.max.y, densityBuffer); Vector3i position_voxelGrid = new Vector3i(); for (position_voxelGrid.x = bounds_voxelGrid.min.x; position_voxelGrid.x < bounds_voxelGrid.max.x; position_voxelGrid.x++) { for (position_voxelGrid.z = bounds_voxelGrid.min.z; position_voxelGrid.z < bounds_voxelGrid.max.z; position_voxelGrid.z++) { position_voxelGrid.y = bounds_voxelGrid.min.y; - BiomeType biome = biomeSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); + Integer biomeId = biomeSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); + Biome biome = biomeRegistry.getObject(biomeId); MaterialProvider materialProvider = biome.getMaterialProvider(); - NTerrainStage.ColumnData columnData = new NTerrainStage.ColumnData( - bounds_voxelGrid.min.y, bounds_voxelGrid.max.y, position_voxelGrid.x, position_voxelGrid.z, densityBuffer, materialProvider - ); - double distanceToOtherBiome_voxelGrid = distanceSpace.getContent(position_voxelGrid).distanceToClosestOtherBiome(biome); + columnData.resolve(position_voxelGrid.x, position_voxelGrid.z, materialProvider); + double distanceToOtherBiome_voxelGrid = distanceSpace.getContent(position_voxelGrid).distanceToClosestOtherBiome(biomeId); for (position_voxelGrid.y = bounds_voxelGrid.min.y; position_voxelGrid.y < bounds_voxelGrid.max.y; position_voxelGrid.y++) { int i = position_voxelGrid.y - bounds_voxelGrid.min.y; - MaterialProvider.Context context = new MaterialProvider.Context( - position_voxelGrid, - 0.0, - columnData.depthIntoFloor[i], - columnData.depthIntoCeiling[i], - columnData.spaceAboveFloor[i], - columnData.spaceBelowCeiling[i], - workerId, - (position, id) -> this.getOrGenerateDensity(position, densityBuffer, biomeSpace, distanceSpace, workerId), - distanceToOtherBiome_voxelGrid - ); + context.position.assign(position_voxelGrid); + context.density = densityBuffer.get(position_voxelGrid); + context.depthIntoFloor = columnData.depthIntoFloor[i]; + context.depthIntoCeiling = columnData.depthIntoCeiling[i]; + context.spaceAboveFloor = columnData.spaceAboveFloor[i]; + context.spaceBelowCeiling = columnData.spaceBelowCeiling[i]; + context.distanceToBiomeEdge = distanceToOtherBiome_voxelGrid; Material material = columnData.materialProvider.getVoxelTypeAt(context); if (material != null) { - materialSpace.set(material, position_voxelGrid.x, position_voxelGrid.y, position_voxelGrid.z); + materialSpace.set(material, position_voxelGrid); } else { - materialSpace.set(this.materialCache.EMPTY, position_voxelGrid.x, position_voxelGrid.y, position_voxelGrid.z); + materialSpace.set(this.materialCache.EMPTY, position_voxelGrid); } } } @@ -253,7 +268,7 @@ public class NTerrainStage implements NStage { @Nonnull private static NTerrainStage.BiomeWeights createWeights( - @Nonnull NBiomeDistanceStage.BiomeDistanceEntries distances, @Nonnull BiomeType biomeAtOrigin, double interpolationRange + @Nonnull NBiomeDistanceStage.BiomeDistanceEntries distances, int biomeIdAtOrigin, double interpolationRange ) { double circleRadius = interpolationRange + 0.5; NTerrainStage.BiomeWeights biomeWeights = new NTerrainStage.BiomeWeights(); @@ -265,13 +280,13 @@ public class NTerrainStage implements NStage { NBiomeDistanceStage.BiomeDistanceEntry distanceEntry = distances.entries.get(i); NTerrainStage.BiomeWeights.Entry weightEntry = new NTerrainStage.BiomeWeights.Entry(); if (!(distanceEntry.distance_voxelGrid >= interpolationRange)) { - if (distanceEntry.biomeType == biomeAtOrigin) { + if (distanceEntry.biomeId == biomeIdAtOrigin) { originIndex = biomeWeights.entries.size(); } else if (distanceEntry.distance_voxelGrid < smallestNonOriginDistance) { smallestNonOriginDistance = distanceEntry.distance_voxelGrid; } - weightEntry.biomeType = distanceEntry.biomeType; + weightEntry.biomeId = distanceEntry.biomeId; weightEntry.weight = (float)areaUnderCircleCurve(distanceEntry.distance_voxelGrid, circleRadius, circleRadius); biomeWeights.entries.add(weightEntry); total += weightEntry.weight; @@ -318,7 +333,7 @@ public class NTerrainStage implements NStage { } static class Entry { - BiomeType biomeType; + int biomeId; float weight; } } @@ -337,31 +352,32 @@ public class NTerrainStage implements NStage { int top; FloatContainer3d densityBuffer; - private ColumnData( - int bottom, int topExclusive, int worldX, int worldZ, @Nonnull FloatContainer3d densityBuffer, @Nonnull MaterialProvider materialProvider - ) { + ColumnData(int bottom, int topExclusive, @Nonnull FloatContainer3d densityBuffer) { this.topExclusive = topExclusive; this.bottom = bottom; + this.densityBuffer = densityBuffer; + } + + void resolve(int worldX, int worldZ, @Nonnull MaterialProvider materialProvider) { this.worldX = worldX; this.worldZ = worldZ; - this.arrayLength = topExclusive - bottom; + this.arrayLength = this.topExclusive - this.bottom; this.depthIntoFloor = new int[this.arrayLength]; this.spaceBelowCeiling = new int[this.arrayLength]; this.depthIntoCeiling = new int[this.arrayLength]; this.spaceAboveFloor = new int[this.arrayLength]; - this.top = topExclusive - 1; - this.densityBuffer = densityBuffer; + this.top = this.topExclusive - 1; this.materialProvider = materialProvider; Vector3i position = new Vector3i(worldX, 0, worldZ); Vector3i positionAbove = new Vector3i(worldX, 0, worldZ); Vector3i positionBelow = new Vector3i(worldX, 0, worldZ); - for (int y = this.top; y >= bottom; y--) { + for (int y = this.top; y >= this.bottom; y--) { position.y = y; positionAbove.y = y + 1; positionBelow.y = y - 1; - int i = y - bottom; - float density = densityBuffer.get(position); + int i = y - this.bottom; + float density = this.densityBuffer.get(position); boolean solidity = density > 0.0; if (y == this.top) { if (solidity) { @@ -376,7 +392,7 @@ public class NTerrainStage implements NStage { this.spaceAboveFloor[i] = this.spaceAboveFloor[i + 1]; } else { this.depthIntoFloor[i] = 0; - if (densityBuffer.get(positionAbove) > 0.0) { + if (this.densityBuffer.get(positionAbove) > 0.0) { this.spaceAboveFloor[i] = 0; } else { this.spaceAboveFloor[i] = this.spaceAboveFloor[i + 1] + 1; @@ -384,11 +400,11 @@ public class NTerrainStage implements NStage { } } - for (int yx = bottom; yx <= this.top; yx++) { - int i = yx - bottom; - double density = densityBuffer.get(position); + for (int yx = this.bottom; yx <= this.top; yx++) { + int i = yx - this.bottom; + double density = this.densityBuffer.get(position); boolean solidity = density > 0.0; - if (yx == bottom) { + if (yx == this.bottom) { if (solidity) { this.depthIntoCeiling[i] = 1; } else { @@ -401,7 +417,7 @@ public class NTerrainStage implements NStage { this.spaceBelowCeiling[i] = this.spaceBelowCeiling[i - 1]; } else { this.depthIntoCeiling[i] = 0; - if (densityBuffer.get(positionBelow) > 0.0) { + if (this.densityBuffer.get(positionBelow) > 0.0) { this.spaceBelowCeiling[i] = 0; } else { this.spaceBelowCeiling[i] = this.spaceBelowCeiling[i - 1] + 1; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTintStage.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTintStage.java index 57688de6..c0f39593 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTintStage.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTintStage.java @@ -1,6 +1,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; +import com.hypixel.hytale.builtin.hytalegenerator.Registry; +import com.hypixel.hytale.builtin.hytalegenerator.biome.Biome; import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.GridUtils; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.NBufferBundle; @@ -9,7 +10,9 @@ import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers.type.NBufferType; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers.type.NParametrizedBufferType; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NPixelBufferView; +import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.builtin.hytalegenerator.tintproviders.TintProvider; +import com.hypixel.hytale.builtin.hytalegenerator.worldstructure.WorldStructure; import com.hypixel.hytale.math.vector.Vector3i; import java.util.List; import java.util.Map; @@ -17,39 +20,51 @@ import javax.annotation.Nonnull; public class NTintStage implements NStage { public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + public static final Class biomeClass = Integer.class; public static final Class tintBufferClass = NSimplePixelBuffer.class; public static final Class tintClass = Integer.class; private final NParametrizedBufferType biomeInputBufferType; private final NParametrizedBufferType tintOutputBufferType; private final Bounds3i inputBounds_bufferGrid; private final String stageName; + private final WorkerIndexer.Data worldStructure_workerData; - public NTintStage(@Nonnull String stageName, @Nonnull NParametrizedBufferType biomeInputBufferType, @Nonnull NParametrizedBufferType tintOutputBufferType) { - assert biomeInputBufferType.isValidType(biomeBufferClass, biomeTypeClass); + public NTintStage( + @Nonnull String stageName, + @Nonnull NParametrizedBufferType biomeInputBufferType, + @Nonnull NParametrizedBufferType tintOutputBufferType, + @Nonnull WorkerIndexer.Data worldStructure_workerData + ) { + assert biomeInputBufferType.isValidType(biomeBufferClass, biomeClass); assert tintOutputBufferType.isValidType(tintBufferClass, tintClass); this.biomeInputBufferType = biomeInputBufferType; this.tintOutputBufferType = tintOutputBufferType; this.stageName = stageName; + this.worldStructure_workerData = worldStructure_workerData; this.inputBounds_bufferGrid = GridUtils.createUnitBounds3i(Vector3i.ZERO); } @Override public void run(@Nonnull NStage.Context context) { NBufferBundle.Access.View biomeAccess = context.bufferAccess.get(this.biomeInputBufferType); - NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeTypeClass); + NPixelBufferView biomeSpace = new NPixelBufferView<>(biomeAccess, biomeClass); NBufferBundle.Access.View tintAccess = context.bufferAccess.get(this.tintOutputBufferType); NPixelBufferView tintSpace = new NPixelBufferView<>(tintAccess, tintClass); Bounds3i outputBounds_voxelGrid = tintSpace.getBounds(); + Registry biomeRegistry = this.worldStructure_workerData.get(context.workerId).getBiomeRegistry(); Vector3i position_voxelGrid = new Vector3i(outputBounds_voxelGrid.min); position_voxelGrid.setY(0); - TintProvider.Context tintContext = new TintProvider.Context(position_voxelGrid, context.workerId); + TintProvider.Context tintContext = new TintProvider.Context(position_voxelGrid, WorkerIndexer.Id.TEMP_0); for (position_voxelGrid.x = outputBounds_voxelGrid.min.x; position_voxelGrid.x < outputBounds_voxelGrid.max.x; position_voxelGrid.x++) { for (position_voxelGrid.z = outputBounds_voxelGrid.min.z; position_voxelGrid.z < outputBounds_voxelGrid.max.z; position_voxelGrid.z++) { - BiomeType biome = biomeSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); + Integer biomeId = biomeSpace.getContent(position_voxelGrid.x, 0, position_voxelGrid.z); + + assert biomeId != null; + + Biome biome = biomeRegistry.getObject(biomeId); assert biome != null; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NVoxelBufferView.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NVoxelBufferView.java index b76cb16a..8b0f984d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NVoxelBufferView.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NVoxelBufferView.java @@ -61,10 +61,13 @@ public class NVoxelBufferView implements VoxelSpace { public boolean set(T content, @Nonnull Vector3i position_voxelGrid) { assert this.bounds_voxelGrid.contains(position_voxelGrid); + int initialX = position_voxelGrid.x; + int initialY = position_voxelGrid.y; + int initialZ = position_voxelGrid.z; NVoxelBuffer buffer = this.getBuffer_fromVoxelGrid(position_voxelGrid); - Vector3i positionInBuffer_voxelGrid = position_voxelGrid.clone(); - GridUtils.toVoxelGridInsideBuffer_fromWorldGrid(positionInBuffer_voxelGrid); - buffer.setVoxelContent(positionInBuffer_voxelGrid, content); + GridUtils.toVoxelGridInsideBuffer_fromWorldGrid(position_voxelGrid); + buffer.setVoxelContent(position_voxelGrid, content); + position_voxelGrid.assign(initialX, initialY, initialZ); return true; } @@ -89,10 +92,14 @@ public class NVoxelBufferView implements VoxelSpace { public T getContent(@Nonnull Vector3i position_voxelGrid) { assert this.bounds_voxelGrid.contains(position_voxelGrid); + int initialX = position_voxelGrid.x; + int initialY = position_voxelGrid.y; + int initialZ = position_voxelGrid.z; NVoxelBuffer buffer = this.getBuffer_fromVoxelGrid(position_voxelGrid); - Vector3i positionInBuffer_voxelGrid = position_voxelGrid.clone(); - GridUtils.toVoxelGridInsideBuffer_fromWorldGrid(positionInBuffer_voxelGrid); - return buffer.getVoxelContent(positionInBuffer_voxelGrid); + GridUtils.toVoxelGridInsideBuffer_fromWorldGrid(position_voxelGrid); + T content = buffer.getVoxelContent(position_voxelGrid); + position_voxelGrid.assign(initialX, initialY, initialZ); + return content; } @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CeilingPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CeilingPattern.java index 7d36b581..fa99ba1c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CeilingPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CeilingPattern.java @@ -11,6 +11,8 @@ public class CeilingPattern extends Pattern { private final Pattern airPattern; @Nonnull private final SpaceSize readSpaceSize; + private final Vector3i rCeilingPosition; + private final Pattern.Context rCeilingContext; public CeilingPattern(@Nonnull Pattern ceilingPattern, @Nonnull Pattern airPattern) { this.ceilingPattern = ceilingPattern; @@ -18,15 +20,17 @@ public class CeilingPattern extends Pattern { SpaceSize ceilingSpace = ceilingPattern.readSpace(); ceilingSpace.moveBy(new Vector3i(0, 1, 0)); this.readSpaceSize = SpaceSize.merge(ceilingSpace, airPattern.readSpace()); + this.rCeilingPosition = new Vector3i(); + this.rCeilingContext = new Pattern.Context(); } @Override public boolean matches(@Nonnull Pattern.Context context) { - Vector3i ceilingPosition = new Vector3i(context.position.x, context.position.y + 1, context.position.z); - if (context.materialSpace.isInsideSpace(context.position) && context.materialSpace.isInsideSpace(ceilingPosition)) { - Pattern.Context ceilingContext = new Pattern.Context(context); - ceilingContext.position = ceilingPosition; - return this.airPattern.matches(context) && this.ceilingPattern.matches(ceilingContext); + this.rCeilingPosition.assign(context.position); + if (context.materialSpace.isInsideSpace(context.position) && context.materialSpace.isInsideSpace(this.rCeilingPosition)) { + this.rCeilingContext.assign(context); + this.rCeilingContext.position = this.rCeilingPosition; + return this.airPattern.matches(context) && this.ceilingPattern.matches(this.rCeilingContext); } else { return false; } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CuboidPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CuboidPattern.java index f6cc81ff..0b59e5f7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CuboidPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CuboidPattern.java @@ -13,30 +13,38 @@ public class CuboidPattern extends Pattern { private final Vector3i max; @Nonnull private final SpaceSize readSpaceSize; + private final Vector3i rScanMin; + private final Vector3i rScanMax; + private final Vector3i rChildPosition; + private final Pattern.Context rChildContext; public CuboidPattern(@Nonnull Pattern subPattern, @Nonnull Vector3i min, @Nonnull Vector3i max) { this.subPattern = subPattern; this.min = min; this.max = max; this.readSpaceSize = new SpaceSize(min, max.clone().add(1, 1, 1)); + this.rScanMin = new Vector3i(); + this.rScanMax = new Vector3i(); + this.rChildPosition = new Vector3i(); + this.rChildContext = new Pattern.Context(); } @Override public boolean matches(@Nonnull Pattern.Context context) { - Vector3i scanMin = this.min.clone().add(context.position); - Vector3i scanMax = this.max.clone().add(context.position); - Vector3i childPosition = context.position.clone(); - Pattern.Context childContext = new Pattern.Context(context); - childContext.position = childPosition; + this.rScanMin.assign(this.min).add(context.position); + this.rScanMax.assign(this.max).add(context.position); + this.rChildPosition.assign(context.position); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; - for (childPosition.x = scanMin.x; childPosition.x <= scanMax.x; childPosition.x++) { - for (childPosition.z = scanMin.z; childPosition.z <= scanMax.z; childPosition.z++) { - for (childPosition.y = scanMin.y; childPosition.y <= scanMax.y; childPosition.y++) { - if (!context.materialSpace.isInsideSpace(childPosition)) { + for (this.rChildPosition.x = this.rScanMin.x; this.rChildPosition.x <= this.rScanMax.x; this.rChildPosition.x++) { + for (this.rChildPosition.z = this.rScanMin.z; this.rChildPosition.z <= this.rScanMax.z; this.rChildPosition.z++) { + for (this.rChildPosition.y = this.rScanMin.y; this.rChildPosition.y <= this.rScanMax.y; this.rChildPosition.y++) { + if (!context.materialSpace.isInsideSpace(this.rChildPosition)) { return false; } - if (!this.subPattern.matches(childContext)) { + if (!this.subPattern.matches(this.rChildContext)) { return false; } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/FieldFunctionPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/FieldFunctionPattern.java index 52af77ee..02052556 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/FieldFunctionPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/FieldFunctionPattern.java @@ -13,17 +13,19 @@ public class FieldFunctionPattern extends Pattern { private final SpaceSize readSpaceSize; @Nonnull private final List delimiters; + private final Density.Context rDensityContext; public FieldFunctionPattern(@Nonnull Density field) { this.field = field; this.readSpaceSize = SpaceSize.empty(); this.delimiters = new ArrayList<>(1); + this.rDensityContext = new Density.Context(); } @Override public boolean matches(@Nonnull Pattern.Context context) { - Density.Context densityContext = new Density.Context(context); - double density = this.field.process(densityContext); + this.rDensityContext.assign(context); + double density = this.field.process(this.rDensityContext); for (FieldFunctionPattern.Delimiter d : this.delimiters) { if (d.isInside(density)) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/GapPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/GapPattern.java index 62262651..ca57bc31 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/GapPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/GapPattern.java @@ -19,6 +19,8 @@ public class GapPattern extends Pattern { private Pattern gapPattern; private Pattern anchorPattern; private SpaceSize readSpaceSize; + private final Vector3i rChildPosition; + private final Pattern.Context rChildContext; public GapPattern( @Nonnull List angles, @@ -38,6 +40,8 @@ public class GapPattern extends Pattern { this.anchorRoughness = anchorRoughness; this.depthDown = depthDown; this.depthUp = depthUp; + this.rChildPosition = new Vector3i(); + this.rChildContext = new Pattern.Context(); this.depthPositionedPatterns = this.renderDepths(); this.axisPositionedPatterns = new ArrayList<>(angles.size()); @@ -72,6 +76,44 @@ public class GapPattern extends Pattern { } } + @Override + public boolean matches(@Nonnull Pattern.Context context) { + this.rChildPosition.assign(0, 0, 0); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + + for (GapPattern.PositionedPattern entry : this.depthPositionedPatterns) { + this.rChildPosition.assign(entry.position).add(context.position); + if (!entry.pattern.matches(this.rChildContext)) { + return false; + } + } + + for (List patternsInDirection : this.axisPositionedPatterns) { + boolean matchesDirection = true; + + for (GapPattern.PositionedPattern entryx : patternsInDirection) { + this.rChildPosition.assign(entryx.position).add(context.position); + if (!entryx.pattern.matches(context)) { + matchesDirection = false; + break; + } + } + + if (matchesDirection) { + return true; + } + } + + return false; + } + + @Nonnull + @Override + public SpaceSize readSpace() { + return this.readSpaceSize.clone(); + } + @Nonnull private List renderDepths() { ArrayList positions = new ArrayList<>(); @@ -161,44 +203,6 @@ public class GapPattern extends Pattern { return positions; } - @Override - public boolean matches(@Nonnull Pattern.Context context) { - Vector3i childPosition = new Vector3i(); - Pattern.Context childContext = new Pattern.Context(context); - childContext.position = childPosition; - - for (GapPattern.PositionedPattern entry : this.depthPositionedPatterns) { - childPosition.assign(entry.position).add(context.position); - if (!entry.pattern.matches(childContext)) { - return false; - } - } - - for (List patternsInDirection : this.axisPositionedPatterns) { - boolean matchesDirection = true; - - for (GapPattern.PositionedPattern entryx : patternsInDirection) { - childPosition.assign(entryx.position).add(context.position); - if (!entryx.pattern.matches(context)) { - matchesDirection = false; - break; - } - } - - if (matchesDirection) { - return true; - } - } - - return false; - } - - @Nonnull - @Override - public SpaceSize readSpace() { - return this.readSpaceSize.clone(); - } - public static class PositionedPattern { private Vector3i position; private Pattern pattern; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/OffsetPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/OffsetPattern.java index 752edae5..1198bdb1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/OffsetPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/OffsetPattern.java @@ -11,18 +11,23 @@ public class OffsetPattern extends Pattern { private final Vector3i offset; @Nonnull private final SpaceSize readSpaceSize; + private final Vector3i rChildPosition; + private final Pattern.Context rChildContext; public OffsetPattern(@Nonnull Pattern pattern, @Nonnull Vector3i offset) { this.pattern = pattern; this.offset = offset; this.readSpaceSize = pattern.readSpace().moveBy(offset); + this.rChildPosition = new Vector3i(); + this.rChildContext = new Pattern.Context(); } @Override public boolean matches(@Nonnull Pattern.Context context) { - Pattern.Context childContext = new Pattern.Context(context); - childContext.position = context.position.clone().add(this.offset); - return this.pattern.matches(childContext); + this.rChildPosition.assign(context.position).add(this.offset); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + return this.pattern.matches(this.rChildContext); } @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/Pattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/Pattern.java index 0fd7bf9a..e539c508 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/Pattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/Pattern.java @@ -3,9 +3,9 @@ package com.hypixel.hytale.builtin.hytalegenerator.patterns; import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize; import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.VoxelSpace; import com.hypixel.hytale.builtin.hytalegenerator.material.Material; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public abstract class Pattern { public abstract boolean matches(@Nonnull Pattern.Context var1); @@ -47,20 +47,29 @@ public abstract class Pattern { } public static class Context { + @Nonnull public Vector3i position; + @Nullable public VoxelSpace materialSpace; - public WorkerIndexer.Id workerId; - public Context(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, WorkerIndexer.Id workerId) { + public Context() { + this.position = new Vector3i(); + this.materialSpace = null; + } + + public Context(@Nonnull Vector3i position, @Nullable VoxelSpace materialSpace) { this.position = position; this.materialSpace = materialSpace; - this.workerId = workerId; } public Context(@Nonnull Pattern.Context other) { this.position = other.position; this.materialSpace = other.materialSpace; - this.workerId = other.workerId; + } + + public void assign(@Nonnull Pattern.Context other) { + this.position = other.position; + this.materialSpace = other.materialSpace; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/SurfacePattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/SurfacePattern.java index 4037cc6a..7ee1a21b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/SurfacePattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/SurfacePattern.java @@ -20,6 +20,8 @@ public class SurfacePattern extends Pattern { private final List surfacePositions; @Nonnull private final List originPositions; + private final Vector3i rChildPosition; + private final Pattern.Context rChildContext; public SurfacePattern( @Nonnull Pattern surfacePattern, @@ -32,6 +34,8 @@ public class SurfacePattern extends Pattern { ) { this.wallPattern = surfacePattern; this.originPattern = originPattern; + this.rChildPosition = new Vector3i(); + this.rChildContext = new Pattern.Context(); int surfaceY = -1 - surfaceGap; this.surfacePositions = new ArrayList<>(1); @@ -81,6 +85,29 @@ public class SurfacePattern extends Pattern { this.readSpaceSize = SpaceSize.merge(floorSpace, originSpace); } + @Override + public boolean matches(@Nonnull Pattern.Context context) { + this.rChildPosition.assign(context.position); + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + + for (Vector3i pos : this.originPositions) { + this.rChildPosition.assign(pos).add(context.position); + if (!this.originPattern.matches(this.rChildContext)) { + return false; + } + } + + for (Vector3i posx : this.surfacePositions) { + this.rChildPosition.assign(posx).add(context.position); + if (!this.wallPattern.matches(this.rChildContext)) { + return false; + } + } + + return true; + } + private void applyFacing(@Nonnull Vector3i pos, @Nonnull SurfacePattern.Facing facing) { switch (facing) { case D: @@ -126,29 +153,6 @@ public class SurfacePattern extends Pattern { pos.x = -pos.x; } - @Override - public boolean matches(@Nonnull Pattern.Context context) { - Vector3i childPosition = context.position.clone(); - Pattern.Context childContext = new Pattern.Context(context); - childContext.position = childPosition; - - for (Vector3i pos : this.originPositions) { - childPosition.assign(pos).add(context.position); - if (!this.originPattern.matches(childContext)) { - return false; - } - } - - for (Vector3i posx : this.surfacePositions) { - childPosition.assign(posx).add(context.position); - if (!this.wallPattern.matches(childContext)) { - return false; - } - } - - return true; - } - @Nonnull @Override public SpaceSize readSpace() { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/WallPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/WallPattern.java index cc6a0928..39ff6716 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/WallPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/WallPattern.java @@ -17,12 +17,16 @@ public class WallPattern extends Pattern { private final List directions; private final boolean matchAll; private final SpaceSize readSpaceSize; + private final Vector3i rWallPosition; + private final Pattern.Context rWallContext; public WallPattern(@Nonnull Pattern wallPattern, @Nonnull Pattern originPattern, @Nonnull List wallDirections, boolean matchAll) { this.wallPattern = wallPattern; this.originPattern = originPattern; this.directions = new ArrayList<>(wallDirections); this.matchAll = matchAll; + this.rWallPosition = new Vector3i(); + this.rWallContext = new Pattern.Context(); SpaceSize originSpace = originPattern.readSpace(); SpaceSize wallSpace = wallPattern.readSpace(); SpaceSize totalSpace = originSpace; @@ -57,24 +61,24 @@ public class WallPattern extends Pattern { } private boolean matches(@Nonnull Pattern.Context context, @Nonnull WallPattern.WallDirection direction) { - Vector3i wallPosition = context.position.clone(); + this.rWallPosition.assign(context.position); switch (direction) { case N: - wallPosition.z--; + this.rWallPosition.z--; break; case S: - wallPosition.z++; + this.rWallPosition.z++; break; case E: - wallPosition.x++; + this.rWallPosition.x++; break; case W: - wallPosition.x--; + this.rWallPosition.x--; } - Pattern.Context wallContext = new Pattern.Context(context); - wallContext.position = wallPosition; - return this.originPattern.matches(context) && this.wallPattern.matches(wallContext); + this.rWallContext.assign(context); + this.rWallContext.position = this.rWallPosition; + return this.originPattern.matches(context) && this.wallPattern.matches(this.rWallContext); } @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/Handle.java b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/Handle.java index ef7ea733..130783dc 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/Handle.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/Handle.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.server.core.universe.world.spawn.ISpawnProvider; import com.hypixel.hytale.server.core.universe.world.worldgen.GeneratedChunk; import com.hypixel.hytale.server.core.universe.world.worldgen.IWorldGen; import com.hypixel.hytale.server.core.universe.world.worldgen.WorldGenTimingsCollector; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.LongPredicate; import javax.annotation.Nonnull; @@ -16,15 +17,22 @@ public class Handle implements IWorldGen { private final HytaleGenerator plugin; @Nonnull private final ChunkRequest.GeneratorProfile profile; + @Nullable + private final String seedOverride; - public Handle(@Nonnull HytaleGenerator plugin, @Nonnull ChunkRequest.GeneratorProfile profile) { + public Handle(@Nonnull HytaleGenerator plugin, @Nonnull ChunkRequest.GeneratorProfile profile, @Nullable String seedOverride) { this.plugin = plugin; this.profile = profile; + this.seedOverride = seedOverride; } @Override public CompletableFuture generate(int seed, long index, int x, int z, LongPredicate stillNeeded) { ChunkRequest.Arguments arguments = new ChunkRequest.Arguments(seed, index, x, z, stillNeeded); + if (this.seedOverride != null) { + seed = Objects.hash(this.seedOverride); + } + this.profile.setSeed(seed); ChunkRequest request = new ChunkRequest(this.profile, arguments); return this.plugin.submitChunkRequest(request); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HandleProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HandleProvider.java index 9983db0a..92995875 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HandleProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HandleProvider.java @@ -14,22 +14,35 @@ public class HandleProvider implements IWorldGenProvider { private final HytaleGenerator plugin; @Nonnull private String worldStructureName = "Default"; + @Nullable + private String seedOverride; + private int worldCounter; - public HandleProvider(@Nonnull HytaleGenerator plugin) { + public HandleProvider(@Nonnull HytaleGenerator plugin, int worldCounter) { this.plugin = plugin; + this.worldCounter = worldCounter; } public void setWorldStructureName(@Nullable String worldStructureName) { this.worldStructureName = worldStructureName; } + public void setSeedOverride(@Nullable String seedOverride) { + this.seedOverride = seedOverride; + } + @Nonnull public String getWorldStructureName() { return this.worldStructureName; } + @Nullable + public String getSeedOverride() { + return this.seedOverride; + } + @Override public IWorldGen getGenerator() throws WorldGenLoadException { - return new Handle(this.plugin, new ChunkRequest.GeneratorProfile(this.worldStructureName, 0)); + return new Handle(this.plugin, new ChunkRequest.GeneratorProfile(this.worldStructureName, 0, this.worldCounter), this.seedOverride); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HytaleGenerator.java b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HytaleGenerator.java index 1ac19e09..e547c5cf 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HytaleGenerator.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HytaleGenerator.java @@ -1,18 +1,17 @@ package com.hypixel.hytale.builtin.hytalegenerator.plugin; +import com.hypixel.hytale.builtin.hytalegenerator.FutureUtils; import com.hypixel.hytale.builtin.hytalegenerator.LoggerUtil; import com.hypixel.hytale.builtin.hytalegenerator.PropField; import com.hypixel.hytale.builtin.hytalegenerator.assets.AssetManager; import com.hypixel.hytale.builtin.hytalegenerator.assets.SettingsAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.WorldStructureAsset; -import com.hypixel.hytale.builtin.hytalegenerator.biome.BiomeType; -import com.hypixel.hytale.builtin.hytalegenerator.biomemap.BiomeMap; +import com.hypixel.hytale.builtin.hytalegenerator.biome.Biome; import com.hypixel.hytale.builtin.hytalegenerator.chunkgenerator.ChunkGenerator; import com.hypixel.hytale.builtin.hytalegenerator.chunkgenerator.ChunkRequest; import com.hypixel.hytale.builtin.hytalegenerator.chunkgenerator.FallbackGenerator; import com.hypixel.hytale.builtin.hytalegenerator.commands.ViewportCommand; import com.hypixel.hytale.builtin.hytalegenerator.material.MaterialCache; -import com.hypixel.hytale.builtin.hytalegenerator.material.SolidMaterial; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.NStagedChunkGenerator; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers.NCountedPixelBuffer; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers.NEntityBuffer; @@ -29,6 +28,7 @@ import com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages.NTerrainStage import com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages.NTintStage; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; +import com.hypixel.hytale.builtin.hytalegenerator.worldstructure.WorldStructure; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; @@ -61,6 +61,7 @@ public class HytaleGenerator extends JavaPlugin { private int concurrency; private ExecutorService mainExecutor; private ThreadPoolExecutor concurrentExecutor; + private int worldCounter; @Override protected void start() { @@ -101,11 +102,14 @@ public class HytaleGenerator extends JavaPlugin { @Override protected void setup() { this.assetManager = new AssetManager(this.getEventRegistry(), this.getLogger()); - BuilderCodec generatorProvider = BuilderCodec.builder(HandleProvider.class, () -> new HandleProvider(this)) + BuilderCodec generatorProvider = BuilderCodec.builder(HandleProvider.class, () -> new HandleProvider(this, this.worldCounter++)) .documentation("The standard generator for Hytale.") - .append(new KeyedCodec<>("WorldStructure", Codec.STRING), HandleProvider::setWorldStructureName, HandleProvider::getWorldStructureName) + .append(new KeyedCodec<>("WorldStructure", Codec.STRING, true), HandleProvider::setWorldStructureName, HandleProvider::getWorldStructureName) .documentation("The world structure to be used for this world.") .add() + .append(new KeyedCodec<>("SeedOverride", Codec.STRING, false), HandleProvider::setSeedOverride, HandleProvider::getSeedOverride) + .documentation("If set, this will override the world's seed to ensure consistency.") + .add() .build(); IWorldGenProvider.CODEC.register("HytaleGenerator", HandleProvider.class, generatorProvider); this.getCommandRegistry().registerCommand(new ViewportCommand(this.assetManager)); @@ -123,17 +127,38 @@ public class HytaleGenerator extends JavaPlugin { WorkerIndexer workerIndexer = new WorkerIndexer(this.concurrency); SeedBox seed = new SeedBox(generatorProfile.seed()); MaterialCache materialCache = new MaterialCache(); - BiomeMap biomeMap = worldStructureAsset.buildBiomeMap(new WorldStructureAsset.Argument(materialCache, seed, workerIndexer)); + WorkerIndexer.Session workerSession = workerIndexer.createSession(); + WorkerIndexer.Data worldStructure_workerData = new WorkerIndexer.Data<>(workerIndexer.getWorkerCount(), () -> null); + List> futures = new ArrayList<>(); + + while (workerSession.hasNext()) { + WorkerIndexer.Id workerId = workerSession.next(); + CompletableFuture future = CompletableFuture.runAsync(() -> { + WorldStructure worldStructure = worldStructureAsset.build(new WorldStructureAsset.Argument(materialCache, seed)); + worldStructure_workerData.set(workerId, worldStructure); + }, this.concurrentExecutor).handle((r, e) -> { + if (e == null) { + return (Void)r; + } else { + LoggerUtil.logException("during async initialization of world-gen logic from assets", e); + return null; + } + }); + futures.add(future); + } + + FutureUtils.allOf(futures).join(); worldStructureAsset.cleanUp(); NStagedChunkGenerator.Builder generatorBuilder = new NStagedChunkGenerator.Builder(); - List allBiomes = biomeMap.allPossibleValues(); + WorldStructure worldStructure_worker0 = worldStructure_workerData.get(workerIndexer.createSession().next()); + List allBiomes = worldStructure_worker0.getBiomeRegistry().getAllValues(); List allRuntimes = new ArrayList<>(getAllPossibleRuntimeIndices(allBiomes)); allRuntimes.sort(Comparator.naturalOrder()); int bufferTypeIndexCounter = 0; NParametrizedBufferType biome_bufferType = new NParametrizedBufferType( - "Biome", bufferTypeIndexCounter++, NBiomeStage.bufferClass, NBiomeStage.biomeTypeClass, () -> new NCountedPixelBuffer<>(NBiomeStage.biomeTypeClass) + "Biome", bufferTypeIndexCounter++, NBiomeStage.bufferClass, NBiomeStage.biomeClass, () -> new NCountedPixelBuffer<>(NBiomeStage.biomeClass) ); - NStage biomeStage = new NBiomeStage("BiomeStage", biome_bufferType, biomeMap); + NStage biomeStage = new NBiomeStage("BiomeStage", biome_bufferType, worldStructure_workerData); generatorBuilder.appendStage(biomeStage); NParametrizedBufferType biomeDistance_bufferType = new NParametrizedBufferType( "BiomeDistance", @@ -143,8 +168,8 @@ public class HytaleGenerator extends JavaPlugin { () -> new NSimplePixelBuffer<>(NBiomeDistanceStage.biomeDistanceClass) ); int MAX_BIOME_DISTANCE_RADIUS = 512; - int interpolationRadius = Math.clamp((long)(worldStructureAsset.getBiomeTransitionDistance() / 2), 0, 512); - int biomeEdgeRadius = Math.clamp((long)worldStructureAsset.getMaxBiomeEdgeDistance(), 0, 512); + int interpolationRadius = Math.clamp((long)(worldStructure_worker0.getBiomeTransitionDistance() / 2), 0, 512); + int biomeEdgeRadius = Math.clamp((long)worldStructure_worker0.getMaxBiomeEdgeDistance(), 0, 512); int maxDistance = Math.max(interpolationRadius, biomeEdgeRadius); NStage biomeDistanceStage = new NBiomeDistanceStage("BiomeDistanceStage", biome_bufferType, biomeDistance_bufferType, maxDistance); generatorBuilder.appendStage(biomeDistanceStage); @@ -162,7 +187,14 @@ public class HytaleGenerator extends JavaPlugin { } NStage terrainStage = new NTerrainStage( - "TerrainStage", biome_bufferType, biomeDistance_bufferType, material0_bufferType, interpolationRadius, materialCache, workerIndexer + "TerrainStage", + biome_bufferType, + biomeDistance_bufferType, + material0_bufferType, + interpolationRadius, + materialCache, + workerIndexer, + worldStructure_workerData ); generatorBuilder.appendStage(terrainStage); NParametrizedBufferType materialInput_bufferType = material0_bufferType; @@ -190,7 +222,7 @@ public class HytaleGenerator extends JavaPlugin { materialOutput_bufferType, entityOutput_bufferType, materialCache, - allBiomes, + worldStructure_workerData, runtime ); generatorBuilder.appendStage(propStage); @@ -211,15 +243,17 @@ public class HytaleGenerator extends JavaPlugin { generatorBuilder.MATERIAL_OUTPUT_BUFFER_TYPE, generatorBuilder.ENTITY_OUTPUT_BUFFER_TYPE, materialCache, - allBiomes, + worldStructure_workerData, runtime ); generatorBuilder.appendStage(propStage); } - NStage tintStage = new NTintStage("TintStage", biome_bufferType, generatorBuilder.TINT_OUTPUT_BUFFER_TYPE); + NStage tintStage = new NTintStage("TintStage", biome_bufferType, generatorBuilder.TINT_OUTPUT_BUFFER_TYPE, worldStructure_workerData); generatorBuilder.appendStage(tintStage); - NStage environmentStage = new NEnvironmentStage("EnvironmentStage", biome_bufferType, generatorBuilder.ENVIRONMENT_OUTPUT_BUFFER_TYPE); + NStage environmentStage = new NEnvironmentStage( + "EnvironmentStage", biome_bufferType, generatorBuilder.ENVIRONMENT_OUTPUT_BUFFER_TYPE, worldStructure_workerData + ); generatorBuilder.appendStage(environmentStage); double bufferCapacityFactor = Math.max(0.0, settingsAsset.getBufferCapacityFactor()); double targetViewDistance = Math.max(0.0, settingsAsset.getTargetViewDistance()); @@ -233,10 +267,10 @@ public class HytaleGenerator extends JavaPlugin { } @Nonnull - private static Set getAllPossibleRuntimeIndices(@Nonnull List biomes) { + private static Set getAllPossibleRuntimeIndices(@Nonnull List biomes) { Set allRuntimes = new HashSet<>(); - for (BiomeType biome : biomes) { + for (Biome biome : biomes) { for (PropField propField : biome.getPropFields()) { allRuntimes.add(propField.getRuntime()); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/AnchorPositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/AnchorPositionProvider.java index 5fd2ce98..456ce259 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/AnchorPositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/AnchorPositionProvider.java @@ -32,7 +32,7 @@ public class AnchorPositionProvider extends PositionProvider { if (VectorUtil.isInside(newPoint, context.minInclusive, context.maxExclusive)) { context.consumer.accept(newPoint); } - }, context.anchor, context.workerId); + }, context.anchor); this.positionProvider.positionsIn(childContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionOccurrencePositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionOccurrencePositionProvider.java index 387de4fa..b3325011 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionOccurrencePositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionOccurrencePositionProvider.java @@ -27,7 +27,6 @@ public class FieldFunctionOccurrencePositionProvider extends PositionProvider { Density.Context densityContext = new Density.Context(); densityContext.position = position; densityContext.positionsAnchor = context.anchor; - densityContext.workerId = context.workerId; double discardChance = 1.0 - this.field.process(densityContext); FastRandom random = new FastRandom(this.seedGenerator.seedAt(position.x, position.y, position.z, 100.0)); if (!(discardChance > random.nextDouble())) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionPositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionPositionProvider.java index 59851dbb..8a84a02c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionPositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionPositionProvider.java @@ -33,7 +33,6 @@ public class FieldFunctionPositionProvider extends PositionProvider { Density.Context densityContext = new Density.Context(); densityContext.position = p; densityContext.positionsAnchor = context.anchor; - densityContext.workerId = context.workerId; double value = this.field.process(densityContext); for (FieldFunctionPositionProvider.Delimiter d : this.delimiters) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/OffsetPositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/OffsetPositionProvider.java index d93743ce..4509923e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/OffsetPositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/OffsetPositionProvider.java @@ -38,7 +38,6 @@ public class OffsetPositionProvider extends PositionProvider { offsetP.add(this.offset3d); context.consumer.accept(offsetP); }; - childContext.workerId = context.workerId; this.positionProvider.positionsIn(childContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/PositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/PositionProvider.java index dc859ab5..7f6a8eae 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/PositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/PositionProvider.java @@ -1,6 +1,5 @@ package com.hypixel.hytale.builtin.hytalegenerator.positionproviders; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3d; import java.util.function.Consumer; import javax.annotation.Nonnull; @@ -25,28 +24,19 @@ public abstract class PositionProvider { public Consumer consumer; @Nullable public Vector3d anchor; - public WorkerIndexer.Id workerId; public Context() { this.minInclusive = Vector3d.ZERO; this.maxExclusive = Vector3d.ZERO; this.consumer = EMPTY_CONSUMER; this.anchor = null; - this.workerId = WorkerIndexer.Id.UNKNOWN; } - public Context( - @Nonnull Vector3d minInclusive, - @Nonnull Vector3d maxExclusive, - @Nonnull Consumer consumer, - @Nullable Vector3d anchor, - WorkerIndexer.Id workerId - ) { + public Context(@Nonnull Vector3d minInclusive, @Nonnull Vector3d maxExclusive, @Nonnull Consumer consumer, @Nullable Vector3d anchor) { this.minInclusive = minInclusive; this.maxExclusive = maxExclusive; this.consumer = consumer; this.anchor = anchor; - this.workerId = workerId; } public Context(@Nonnull PositionProvider.Context other) { @@ -54,7 +44,13 @@ public abstract class PositionProvider { this.maxExclusive = other.maxExclusive; this.consumer = other.consumer; this.anchor = other.anchor; - this.workerId = other.workerId; + } + + public void assign(@Nonnull PositionProvider.Context other) { + this.minInclusive = other.minInclusive; + this.maxExclusive = other.maxExclusive; + this.consumer = other.consumer; + this.anchor = other.anchor; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/cached/CachedPositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/cached/CachedPositionProvider.java index ffd25446..c0b35ed5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/cached/CachedPositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/cached/CachedPositionProvider.java @@ -2,7 +2,6 @@ package com.hypixel.hytale.builtin.hytalegenerator.positionproviders.cached; import com.hypixel.hytale.builtin.hytalegenerator.VectorUtil; import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.util.HashUtil; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3i; @@ -13,13 +12,13 @@ public class CachedPositionProvider extends PositionProvider { @Nonnull private final PositionProvider positionProvider; private final int sectionSize; - private WorkerIndexer.Data threadData; + private CacheThreadMemory cache; - public CachedPositionProvider(@Nonnull PositionProvider positionProvider, int sectionSize, int cacheSize, boolean useInternalThreadData, int threadCount) { - if (sectionSize > 0 && cacheSize >= 0 && threadCount > 0) { + public CachedPositionProvider(@Nonnull PositionProvider positionProvider, int sectionSize, int cacheSize, boolean useInternalThreadData) { + if (sectionSize > 0 && cacheSize >= 0) { this.positionProvider = positionProvider; this.sectionSize = sectionSize; - this.threadData = new WorkerIndexer.Data<>(threadCount, () -> new CacheThreadMemory(cacheSize)); + this.cache = new CacheThreadMemory(cacheSize); } else { throw new IllegalArgumentException(); } @@ -31,7 +30,6 @@ public class CachedPositionProvider extends PositionProvider { } public void get(@Nonnull PositionProvider.Context context) { - CacheThreadMemory cachedData = this.threadData.get(context.workerId); Vector3i minSection = this.sectionAddress(context.minInclusive); Vector3i maxSection = this.sectionAddress(context.maxExclusive); Vector3i sectionAddress = minSection.clone(); @@ -40,20 +38,20 @@ public class CachedPositionProvider extends PositionProvider { for (sectionAddress.z = minSection.z; sectionAddress.z <= maxSection.z; sectionAddress.z++) { for (sectionAddress.y = minSection.y; sectionAddress.y <= maxSection.y; sectionAddress.y++) { long key = HashUtil.hash(sectionAddress.x, sectionAddress.y, sectionAddress.z); - Vector3d[] section = cachedData.sections.get(key); + Vector3d[] section = this.cache.sections.get(key); if (section == null) { Vector3d sectionMin = this.sectionMin(sectionAddress); Vector3d sectionMax = sectionMin.clone().add(this.sectionSize, this.sectionSize, this.sectionSize); ArrayList generatedPositions = new ArrayList<>(); - PositionProvider.Context childContext = new PositionProvider.Context(sectionMin, sectionMax, generatedPositions::add, null, context.workerId); + PositionProvider.Context childContext = new PositionProvider.Context(sectionMin, sectionMax, generatedPositions::add, null); this.positionProvider.positionsIn(childContext); section = new Vector3d[generatedPositions.size()]; generatedPositions.toArray(section); - cachedData.sections.put(key, section); - cachedData.expirationList.addFirst(key); - if (cachedData.expirationList.size() > cachedData.size) { - long removedKey = cachedData.expirationList.removeLast(); - cachedData.sections.remove(removedKey); + this.cache.sections.put(key, section); + this.cache.expirationList.addFirst(key); + if (this.cache.expirationList.size() > this.cache.size) { + long removedKey = this.cache.expirationList.removeLast(); + this.cache.sections.remove(removedKey); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/propdistributions/FieldFunctionAssignments.java b/src/com/hypixel/hytale/builtin/hytalegenerator/propdistributions/FieldFunctionAssignments.java index f4743e05..0b85a8d6 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/propdistributions/FieldFunctionAssignments.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/propdistributions/FieldFunctionAssignments.java @@ -28,7 +28,6 @@ public class FieldFunctionAssignments extends Assignments { } else { Density.Context context = new Density.Context(); context.position = position; - context.workerId = id; context.distanceToBiomeEdge = distanceTOBiomeEdge; double fieldValue = this.density.process(context); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/ColumnProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/ColumnProp.java index 67422642..48b61bff 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/ColumnProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/ColumnProp.java @@ -79,7 +79,7 @@ public class ColumnProp extends Prop { Scanner.Context scannerContext = new Scanner.Context(position, this.directionality.getGeneralPattern(), materialSpace, id); List validPositions = this.scanner.scan(scannerContext); Vector3i patternPosition = new Vector3i(); - Pattern.Context patternContext = new Pattern.Context(patternPosition, materialSpace, id); + Pattern.Context patternContext = new Pattern.Context(patternPosition, materialSpace); RotatedPositionsScanResult scanResult = new RotatedPositionsScanResult(new ArrayList<>()); for (Vector3i validPosition : validPositions) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/DensityProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/DensityProp.java index fee96095..7cee9f06 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/DensityProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/DensityProp.java @@ -82,7 +82,6 @@ public class DensityProp extends Prop { densitySpace.setOrigin(-min.x, -min.y, -min.z); Density.Context childContext = new Density.Context(); childContext.densityAnchor = position.toVector3d(); - childContext.workerId = id; Vector3i itPosition = new Vector3i(position); for (itPosition.x = min.x; itPosition.x <= max.x; itPosition.x++) { @@ -163,7 +162,7 @@ public class DensityProp extends Prop { && itPosition.z < writeMax.z) { int i = itPosition.y - bottom; MaterialProvider.Context materialContext = new MaterialProvider.Context( - position, 0.0, depthIntoFloor[i], depthIntoCeiling[i], spaceAboveFloor[i], spaceBelowCeiling[i], id, (functionPosition, workerId) -> { + position, 0.0, depthIntoFloor[i], depthIntoCeiling[i], spaceAboveFloor[i], spaceBelowCeiling[i], functionPosition -> { childContext.position = functionPosition.toVector3d(); return this.density.process(childContext); }, childContext.distanceToBiomeEdge diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/filler/PondFillerProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/filler/PondFillerProp.java index a3521b64..a4de2e39 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/filler/PondFillerProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/filler/PondFillerProp.java @@ -207,9 +207,7 @@ public class PondFillerProp extends Prop { if (fluidBlocks != null) { for (Vector3i position : fluidBlocks) { if (context.materialSpace.isInsideSpace(position.x, position.y, position.z)) { - MaterialProvider.Context materialsContext = new MaterialProvider.Context( - position, 0.0, 0, 0, 0, 0, context.workerId, null, context.distanceFromBiomeEdge - ); + MaterialProvider.Context materialsContext = new MaterialProvider.Context(position, 0.0, 0, 0, 0, 0, null, context.distanceFromBiomeEdge); Material material = this.filledMaterialProvider.getVoxelTypeAt(materialsContext); if (material != null) { context.materialSpace.set(material, position.x, position.y, position.z); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/PrefabProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/PrefabProp.java index 6b25e486..9fdd2af1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/PrefabProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/PrefabProp.java @@ -176,7 +176,7 @@ public class PrefabProp extends Prop { Scanner.Context scannerContext = new Scanner.Context(position, this.directionality.getGeneralPattern(), materialSpace, id); List validPositions = this.scanner.scan(scannerContext); Vector3i patternPosition = new Vector3i(); - Pattern.Context patternContext = new Pattern.Context(patternPosition, materialSpace, id); + Pattern.Context patternContext = new Pattern.Context(patternPosition, materialSpace); RotatedPositionsScanResult scanResult = new RotatedPositionsScanResult(new ArrayList<>()); for (Vector3i validPosition : validPositions) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnLinearScanner.java b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnLinearScanner.java index b3037a5c..e0fc87ff 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnLinearScanner.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnLinearScanner.java @@ -55,7 +55,7 @@ public class ColumnLinearScanner extends Scanner { } Vector3i patternPosition = context.position.clone(); - Pattern.Context patternContext = new Pattern.Context(patternPosition, context.materialSpace, context.workerId); + Pattern.Context patternContext = new Pattern.Context(patternPosition, context.materialSpace); if (this.topDownOrder) { for (patternPosition.y = scanMaxY - 1; patternPosition.y >= scanMinY; patternPosition.y--) { if (context.pattern.matches(patternContext)) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnRandomScanner.java b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnRandomScanner.java index 2ac092df..feb16c0c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnRandomScanner.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnRandomScanner.java @@ -80,7 +80,7 @@ public class ColumnRandomScanner extends Scanner { int numberOfPossiblePositions = Math.max(0, scanMaxY - scanMinY); ArrayList validPositions = new ArrayList<>(numberOfPossiblePositions); Vector3i patternPosition = context.position.clone(); - Pattern.Context patternContext = new Pattern.Context(patternPosition, context.materialSpace, context.workerId); + Pattern.Context patternContext = new Pattern.Context(patternPosition, context.materialSpace); for (int y = scanMinY; y < scanMaxY; y++) { patternPosition.y = y; @@ -134,7 +134,7 @@ public class ColumnRandomScanner extends Scanner { FastRandom random = new FastRandom(this.seedGenerator.seedAt((long)context.position.x, (long)context.position.y, (long)context.position.z)); ArrayList usedYs = new ArrayList<>(this.resultsCap); Vector3i patternPosition = context.position.clone(); - Pattern.Context patternContext = new Pattern.Context(patternPosition, context.materialSpace, context.workerId); + Pattern.Context patternContext = new Pattern.Context(patternPosition, context.materialSpace); for (int i = 0; i < numberOfTries; i++) { patternPosition.y = random.nextInt(range) + scanMinY; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/OriginScanner.java b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/OriginScanner.java index 330d0330..dbf087be 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/OriginScanner.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/OriginScanner.java @@ -17,7 +17,7 @@ public class OriginScanner extends Scanner { @Nonnull @Override public List scan(@Nonnull Scanner.Context context) { - Pattern.Context patternContext = new Pattern.Context(context.position, context.materialSpace, context.workerId); + Pattern.Context patternContext = new Pattern.Context(context.position, context.materialSpace); return context.pattern.matches(patternContext) ? Collections.singletonList(context.position.clone()) : Collections.emptyList(); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/threadindexer/WorkerIndexer.java b/src/com/hypixel/hytale/builtin/hytalegenerator/threadindexer/WorkerIndexer.java index e817fb29..f7059f20 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/threadindexer/WorkerIndexer.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/threadindexer/WorkerIndexer.java @@ -3,6 +3,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.threadindexer; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.BiConsumer; import java.util.function.Supplier; import javax.annotation.Nonnull; @@ -44,9 +45,17 @@ public class WorkerIndexer { private T[] data; private Supplier initialize; - public Data(int size, @Nonnull Supplier initialize) { + public Data(int size, @Nonnull Supplier initializer) { this.data = (T[])(new Object[size]); - this.initialize = initialize; + this.initialize = initializer; + } + + public Data(@Nonnull WorkerIndexer.Data other, @Nonnull Supplier initializer) { + this(other.data.length, initializer); + } + + public Data(@Nonnull WorkerIndexer workerIndexer, @Nonnull Supplier initializer) { + this(workerIndexer.getWorkerCount(), initializer); } public boolean isValid(@Nonnull WorkerIndexer.Id id) { @@ -67,11 +76,27 @@ public class WorkerIndexer { return this.data[id.id]; } } + + public void set(@Nonnull WorkerIndexer.Id id, T value) { + if (!this.isValid(id)) { + throw new IllegalArgumentException("Invalid thread id " + id); + } else { + this.data[id.id] = value; + } + } + + public void forEach(@Nonnull BiConsumer consumer) { + for (int i = 0; i < this.data.length; i++) { + WorkerIndexer.Id id = new WorkerIndexer.Id(i); + consumer.accept(id, this.data[i]); + } + } } public static class Id { public static final int UNKNOWN_THREAD_ID = -1; public static final WorkerIndexer.Id UNKNOWN = new WorkerIndexer.Id(-1); + public static final WorkerIndexer.Id TEMP_0 = new WorkerIndexer.Id(0); public final int id; private Id(int id) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/CacheVectorProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/CacheVectorProvider.java index 2cfd8709..887a30d7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/CacheVectorProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/CacheVectorProvider.java @@ -1,6 +1,5 @@ package com.hypixel.hytale.builtin.hytalegenerator.vectorproviders; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; @@ -8,32 +7,27 @@ public class CacheVectorProvider extends VectorProvider { @Nonnull private final VectorProvider vectorProvider; @Nonnull - private final WorkerIndexer.Data threadData; + private final CacheVectorProvider.Cache cache; - public CacheVectorProvider(@Nonnull VectorProvider vectorProvider, int threadCount) { - if (threadCount <= 0) { - throw new IllegalArgumentException("threadCount must be greater than 0"); - } else { - this.vectorProvider = vectorProvider; - this.threadData = new WorkerIndexer.Data<>(threadCount, CacheVectorProvider.Cache::new); - } + public CacheVectorProvider(@Nonnull VectorProvider vectorProvider) { + this.vectorProvider = vectorProvider; + this.cache = new CacheVectorProvider.Cache(); } - @Nonnull @Override - public Vector3d process(@Nonnull VectorProvider.Context context) { - CacheVectorProvider.Cache cache = this.threadData.get(context.workerId); - if (cache.position != null && cache.position.equals(context.position)) { - return cache.value; - } else { - if (cache.position == null) { - cache.position = new Vector3d(); - } - - cache.position.assign(context.position); - cache.value = this.vectorProvider.process(context); - return cache.value; + public void process(@Nonnull VectorProvider.Context context, @Nonnull Vector3d vector_out) { + if (this.cache.position != null && this.cache.position.equals(context.position)) { + vector_out.assign(this.cache.value); } + + if (this.cache.position == null) { + this.cache.position = new Vector3d(); + this.cache.value = new Vector3d(); + } + + this.cache.position.assign(context.position); + this.vectorProvider.process(context, this.cache.value); + vector_out.assign(this.cache.value); } public static class Cache { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/ConstantVectorProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/ConstantVectorProvider.java index 5d18230f..edd70b71 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/ConstantVectorProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/ConstantVectorProvider.java @@ -11,9 +11,8 @@ public class ConstantVectorProvider extends VectorProvider { this.value = value.clone(); } - @Nonnull @Override - public Vector3d process(@Nonnull VectorProvider.Context context) { - return this.value.clone(); + public void process(@Nonnull VectorProvider.Context context, @Nonnull Vector3d vector_out) { + vector_out.assign(this.value); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/DensityGradientVectorProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/DensityGradientVectorProvider.java index f37a4813..8dae8019 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/DensityGradientVectorProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/DensityGradientVectorProvider.java @@ -8,28 +8,33 @@ public class DensityGradientVectorProvider extends VectorProvider { @Nonnull private final Density density; private final double sampleDistance; + private final Density.Context rChildContext; + private final Vector3d rPosition; public DensityGradientVectorProvider(@Nonnull Density density, double sampleDistance) { assert sampleDistance >= 0.0; this.density = density; this.sampleDistance = Math.max(0.0, sampleDistance); + this.rChildContext = new Density.Context(); + this.rPosition = new Vector3d(); } - @Nonnull @Override - public Vector3d process(@Nonnull VectorProvider.Context context) { - double valueAtOrigin = this.density.process(new Density.Context(context)); + public void process(@Nonnull VectorProvider.Context context, @Nonnull Vector3d vector_out) { + this.rPosition.assign(context.position); + this.rChildContext.assign(context); + this.rChildContext.position = this.rPosition; + double valueAtOrigin = this.density.process(this.rChildContext); double maxX = context.position.x + this.sampleDistance; double maxY = context.position.y + this.sampleDistance; double maxZ = context.position.z + this.sampleDistance; - Density.Context childContext = new Density.Context(context); - childContext.position = new Vector3d(maxX, context.position.y, context.position.z); - double deltaX = this.density.process(childContext) - valueAtOrigin; - childContext.position = new Vector3d(context.position.x, maxY, context.position.z); - double deltaY = this.density.process(childContext) - valueAtOrigin; - childContext.position = new Vector3d(context.position.x, context.position.y, maxZ); - double deltaZ = this.density.process(childContext) - valueAtOrigin; - return new Vector3d(deltaX, deltaY, deltaZ); + this.rChildContext.position.assign(maxX, context.position.y, context.position.z); + double deltaX = this.density.process(this.rChildContext) - valueAtOrigin; + this.rChildContext.position.assign(context.position.x, maxY, context.position.z); + double deltaY = this.density.process(this.rChildContext) - valueAtOrigin; + this.rChildContext.position.assign(context.position.x, context.position.y, maxZ); + double deltaZ = this.density.process(this.rChildContext) - valueAtOrigin; + vector_out.assign(deltaX, deltaY, deltaZ); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/VectorProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/VectorProvider.java index 0b6c6c39..5c7f20f2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/VectorProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/VectorProvider.java @@ -2,38 +2,36 @@ package com.hypixel.hytale.builtin.hytalegenerator.vectorproviders; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.TerrainDensityProvider; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class VectorProvider { - @Nonnull - public abstract Vector3d process(@Nonnull VectorProvider.Context var1); + public abstract void process(@Nonnull VectorProvider.Context var1, @Nonnull Vector3d var2); public static class Context { @Nonnull public Vector3d position; - @Nonnull - public WorkerIndexer.Id workerId; @Nullable public TerrainDensityProvider terrainDensityProvider; - public Context(@Nonnull Vector3d position, @Nonnull WorkerIndexer.Id workerId, @Nullable TerrainDensityProvider terrainDensityProvider) { + public Context(@Nonnull Vector3d position, @Nullable TerrainDensityProvider terrainDensityProvider) { this.position = position; - this.workerId = workerId; this.terrainDensityProvider = terrainDensityProvider; } public Context(@Nonnull VectorProvider.Context other) { this.position = other.position; - this.workerId = other.workerId; this.terrainDensityProvider = other.terrainDensityProvider; } public Context(@Nonnull Density.Context other) { this.position = other.position; - this.workerId = other.workerId; + this.terrainDensityProvider = other.terrainDensityProvider; + } + + public void assign(@Nonnull Density.Context other) { + this.position = other.position; this.terrainDensityProvider = other.terrainDensityProvider; } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/worldstructure/WorldStructure.java b/src/com/hypixel/hytale/builtin/hytalegenerator/worldstructure/WorldStructure.java new file mode 100644 index 00000000..6bc83b6a --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/worldstructure/WorldStructure.java @@ -0,0 +1,38 @@ +package com.hypixel.hytale.builtin.hytalegenerator.worldstructure; + +import com.hypixel.hytale.builtin.hytalegenerator.Registry; +import com.hypixel.hytale.builtin.hytalegenerator.biome.Biome; +import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiCarta; +import javax.annotation.Nonnull; + +public class WorldStructure { + private final BiCarta biomeMap; + private final Registry biomeRegistry; + private final int biomeTransitionDistance; + private final int maxBiomeEdgeDistance; + + public WorldStructure(@Nonnull BiCarta biomeMap, @Nonnull Registry biomeRegistry, int biomeTransitionDistance, int maxBiomeEdgeDistance) { + this.biomeMap = biomeMap; + this.biomeRegistry = biomeRegistry; + this.biomeTransitionDistance = biomeTransitionDistance; + this.maxBiomeEdgeDistance = maxBiomeEdgeDistance; + } + + @Nonnull + public BiCarta getBiomeMap() { + return this.biomeMap; + } + + @Nonnull + public Registry getBiomeRegistry() { + return this.biomeRegistry; + } + + public int getBiomeTransitionDistance() { + return this.biomeTransitionDistance; + } + + public int getMaxBiomeEdgeDistance() { + return this.maxBiomeEdgeDistance; + } +} diff --git a/src/com/hypixel/hytale/builtin/instances/command/InstanceEditCopyCommand.java b/src/com/hypixel/hytale/builtin/instances/command/InstanceEditCopyCommand.java index a118f857..8441891e 100644 --- a/src/com/hypixel/hytale/builtin/instances/command/InstanceEditCopyCommand.java +++ b/src/com/hypixel/hytale/builtin/instances/command/InstanceEditCopyCommand.java @@ -17,7 +17,9 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class InstanceEditCopyCommand extends AbstractAsyncCommand { + @Nonnull private final RequiredArg originNameArg = this.withRequiredArg("instanceToCopy", "server.commands.instances.editcopy.origin.name", ArgTypes.STRING); + @Nonnull private final RequiredArg destinationNameArg = this.withRequiredArg( "newInstanceName", "server.commands.instances.editcopy.destination.name", ArgTypes.STRING ); diff --git a/src/com/hypixel/hytale/builtin/instances/command/InstanceEditLoadCommand.java b/src/com/hypixel/hytale/builtin/instances/command/InstanceEditLoadCommand.java index 16d28ff4..8c38f0f1 100644 --- a/src/com/hypixel/hytale/builtin/instances/command/InstanceEditLoadCommand.java +++ b/src/com/hypixel/hytale/builtin/instances/command/InstanceEditLoadCommand.java @@ -33,10 +33,10 @@ public class InstanceEditLoadCommand extends AbstractAsyncCommand { return CompletableFuture.completedFuture(null); } else { String name = this.instanceNameArg.get(context); - context.sendMessage(Message.translation("server.commands.instance.beginLoading").param("name", name)); + context.sendMessage(Message.translation("server.commands.instances.beginLoading").param("name", name)); InstancesPlugin.get(); return InstancesPlugin.loadInstanceAssetForEdit(name).thenAccept(world -> { - context.sendMessage(Message.translation("server.commands.instance.doneLoading").param("world", world.getName())); + context.sendMessage(Message.translation("server.commands.instances.doneLoading").param("world", world.getName())); if (context.isPlayer()) { Ref ref = context.senderAsPlayerRef(); if (ref == null || !ref.isValid()) { diff --git a/src/com/hypixel/hytale/builtin/mounts/MountGamePacketHandler.java b/src/com/hypixel/hytale/builtin/mounts/MountGamePacketHandler.java index 7c6ddb60..5301519a 100644 --- a/src/com/hypixel/hytale/builtin/mounts/MountGamePacketHandler.java +++ b/src/com/hypixel/hytale/builtin/mounts/MountGamePacketHandler.java @@ -37,9 +37,7 @@ public class MountGamePacketHandler implements SubPacketHandler { MountedComponent mounted = store.getComponent(ref, MountedComponent.getComponentType()); if (mounted == null) { - int mountEntityId = playerComponent.getMountEntityId(); - playerComponent.setMountEntityId(0); - MountPlugin.dismountNpc(store, mountEntityId); + MountPlugin.checkDismountNpc(store, ref, playerComponent); } else { if (mounted.getControllerType() == MountController.BlockMount) { store.tryRemoveComponent(ref, MountedComponent.getComponentType()); diff --git a/src/com/hypixel/hytale/builtin/mounts/MountPlugin.java b/src/com/hypixel/hytale/builtin/mounts/MountPlugin.java index 7131700c..dad01c5d 100644 --- a/src/com/hypixel/hytale/builtin/mounts/MountPlugin.java +++ b/src/com/hypixel/hytale/builtin/mounts/MountPlugin.java @@ -9,17 +9,14 @@ import com.hypixel.hytale.builtin.mounts.npc.builders.BuilderActionMount; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; -import com.hypixel.hytale.component.Store; import com.hypixel.hytale.protocol.packets.interaction.DismountNPC; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.movement.MovementManager; -import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent; import com.hypixel.hytale.server.core.io.ServerManager; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; 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.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.NPCPlugin; @@ -73,10 +70,12 @@ public class MountPlugin extends JavaPlugin { this.getEntityStoreRegistry().registerSystem(new NPCMountSystems.OnAdd(this.mountComponentType)); this.getEntityStoreRegistry().registerSystem(new NPCMountSystems.DismountOnPlayerDeath()); this.getEntityStoreRegistry().registerSystem(new NPCMountSystems.DismountOnMountDeath()); + this.getEntityStoreRegistry().registerSystem(new NPCMountSystems.OnPlayerRemove()); this.getEntityStoreRegistry().registerSystem(new MountSystems.TrackerUpdate()); this.getEntityStoreRegistry().registerSystem(new MountSystems.TrackerRemove()); this.getEntityStoreRegistry().registerSystem(new MountSystems.RemoveMountedBy()); this.getEntityStoreRegistry().registerSystem(new MountSystems.RemoveMounted()); + this.getEntityStoreRegistry().registerSystem(new MountSystems.RemoveMountedHolder()); this.getEntityStoreRegistry().registerSystem(new MountSystems.TeleportMountedEntity()); this.getEntityStoreRegistry().registerSystem(new MountSystems.MountedEntityDeath()); this.getEntityStoreRegistry().registerSystem(new MountSystems.PlayerMount()); @@ -86,7 +85,6 @@ public class MountPlugin extends JavaPlugin { this.getEntityStoreRegistry().registerSystem(new MountSystems.OnMinecartHit()); this.getChunkStoreRegistry().registerSystem(new MountSystems.RemoveBlockSeat()); ServerManager.get().registerSubPacketHandlers(MountGamePacketHandler::new); - this.getEventRegistry().register(PlayerDisconnectEvent.class, MountPlugin::onPlayerDisconnect); this.getCommandRegistry().registerCommand(new MountCommand()); Interaction.CODEC.register("SpawnMinecart", SpawnMinecartInteraction.class, SpawnMinecartInteraction.CODEC); Interaction.CODEC.register("Mount", MountInteraction.class, MountInteraction.CODEC); @@ -97,31 +95,15 @@ public class MountPlugin extends JavaPlugin { return this.blockMountComponentType; } - private static void onPlayerDisconnect(@Nonnull PlayerDisconnectEvent event) { - PlayerRef playerRef = event.getPlayerRef(); - Ref ref = playerRef.getReference(); - if (ref != null) { - Store store = ref.getStore(); - World world = store.getExternalData().getWorld(); - world.execute(() -> { - if (ref.isValid()) { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); - if (playerComponent != null) { - checkDismountNpc(store, playerComponent); - } - } - }); - } - } - - public static void checkDismountNpc(@Nonnull ComponentAccessor store, @Nonnull Player playerComponent) { + public static void checkDismountNpc(@Nonnull ComponentAccessor store, @Nonnull Ref ref, @Nonnull Player playerComponent) { int mountEntityId = playerComponent.getMountEntityId(); if (mountEntityId != 0) { - dismountNpc(store, mountEntityId); + playerComponent.setMountEntityId(0); + dismountNpc(store, ref, mountEntityId); } } - public static void dismountNpc(@Nonnull ComponentAccessor store, int mountEntityId) { + private static void dismountNpc(@Nonnull ComponentAccessor store, @Nonnull Ref playerRef, int mountEntityId) { Ref entityReference = store.getExternalData().getRefFromNetworkId(mountEntityId); if (entityReference != null && entityReference.isValid()) { NPCMountComponent mountComponent = store.getComponent(entityReference, NPCMountComponent.getComponentType()); @@ -129,10 +111,7 @@ public class MountPlugin extends JavaPlugin { assert mountComponent != null; resetOriginalMountRole(entityReference, store, mountComponent); - PlayerRef ownerPlayerRef = mountComponent.getOwnerPlayerRef(); - if (ownerPlayerRef != null) { - resetOriginalPlayerMovementSettings(ownerPlayerRef, store); - } + resetOriginalPlayerMovementSettings(playerRef, store); } } @@ -147,15 +126,15 @@ public class MountPlugin extends JavaPlugin { store.removeComponent(entityReference, NPCMountComponent.getComponentType()); } - public static void resetOriginalPlayerMovementSettings(@Nonnull PlayerRef playerRef, @Nonnull ComponentAccessor store) { - Ref reference = playerRef.getReference(); - if (reference != null) { + public static void resetOriginalPlayerMovementSettings(@Nonnull Ref ref, @Nonnull ComponentAccessor store) { + PlayerRef playerRef = store.getComponent(ref, PlayerRef.getComponentType()); + if (playerRef != null) { playerRef.getPacketHandler().write(new DismountNPC()); - MovementManager movementManagerComponent = store.getComponent(reference, MovementManager.getComponentType()); + MovementManager movementManagerComponent = store.getComponent(ref, MovementManager.getComponentType()); assert movementManagerComponent != null; - movementManagerComponent.resetDefaultsAndUpdate(reference, store); + movementManagerComponent.resetDefaultsAndUpdate(ref, store); } } } diff --git a/src/com/hypixel/hytale/builtin/mounts/MountSystems.java b/src/com/hypixel/hytale/builtin/mounts/MountSystems.java index 588e9fac..b893c56e 100644 --- a/src/com/hypixel/hytale/builtin/mounts/MountSystems.java +++ b/src/com/hypixel/hytale/builtin/mounts/MountSystems.java @@ -63,6 +63,7 @@ import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class MountSystems { private static void handleMountedRemoval(Ref ref, @Nonnull CommandBuffer commandBuffer, @Nonnull MountedComponent component) { @@ -156,11 +157,15 @@ public class MountSystems { if (q instanceof PlayerInput.RelativeMovement relative) { relative.apply(commandBuffer, archetypeChunk, index); TransformComponent transform = commandBuffer.getComponent(targetRef, TransformComponent.getComponentType()); - transform.getPosition().add(relative.getX(), relative.getY(), relative.getZ()); + if (transform != null) { + transform.getPosition().add(relative.getX(), relative.getY(), relative.getZ()); + } } else if (q instanceof PlayerInput.AbsoluteMovement absolute) { absolute.apply(commandBuffer, archetypeChunk, index); TransformComponent transform = commandBuffer.getComponent(targetRef, TransformComponent.getComponentType()); - transform.getPosition().assign(absolute.getX(), absolute.getY(), absolute.getZ()); + if (transform != null) { + transform.getPosition().assign(absolute.getX(), absolute.getY(), absolute.getZ()); + } } else if (q instanceof PlayerInput.SetMovementStates sx) { MovementStates states = sx.movementStates(); MovementStatesComponent movementStatesComponent = commandBuffer.getComponent(targetRef, MovementStatesComponent.getComponentType()); @@ -170,7 +175,9 @@ public class MountSystems { } else if (q instanceof PlayerInput.SetBody body) { body.apply(commandBuffer, archetypeChunk, index); TransformComponent transform = commandBuffer.getComponent(targetRef, TransformComponent.getComponentType()); - transform.getRotation().assign(body.direction().pitch, body.direction().yaw, body.direction().roll); + if (transform != null) { + transform.getRotation().assign(body.direction().pitch, body.direction().yaw, body.direction().roll); + } } else if (q instanceof PlayerInput.SetHead head) { head.apply(commandBuffer, archetypeChunk, index); } @@ -326,9 +333,12 @@ public class MountSystems { Ref mountRef = mounted.getMountedToEntity(); if (mountRef != null && mountRef.isValid()) { - int mountNetworkId = commandBuffer.getComponent(mountRef, NetworkId.getComponentType()).getId(); - input.setMountId(mountNetworkId); - input.getMovementUpdateQueue().clear(); + NetworkId mountNetworkIdComponent = commandBuffer.getComponent(mountRef, NetworkId.getComponentType()); + if (mountNetworkIdComponent != null) { + int mountNetworkId = mountNetworkIdComponent.getId(); + input.setMountId(mountNetworkId); + input.getMovementUpdateQueue().clear(); + } } } @@ -401,7 +411,6 @@ public class MountSystems { @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { MountedComponent mounted = commandBuffer.getComponent(ref, MountedComponent.getComponentType()); - commandBuffer.removeComponent(ref, MountedComponent.getComponentType()); MountSystems.handleMountedRemoval(ref, commandBuffer, mounted); } @@ -443,6 +452,22 @@ public class MountSystems { } } + public static class RemoveMountedHolder extends HolderSystem { + @Override + public Query getQuery() { + return MountedComponent.getComponentType(); + } + + @Override + public void onEntityAdd(@NonNullDecl Holder holder, @NonNullDecl AddReason reason, @NonNullDecl Store store) { + } + + @Override + public void onEntityRemoved(@NonNullDecl Holder holder, @NonNullDecl RemoveReason reason, @NonNullDecl Store store) { + holder.removeComponent(MountedComponent.getComponentType()); + } + } + public static class TeleportMountedEntity extends RefChangeSystem { private static final Set> DEPENDENCIES = Set.of( new SystemDependency<>(Order.BEFORE, TeleportSystems.MoveSystem.class, OrderPriority.CLOSEST), @@ -631,7 +656,12 @@ public class MountSystems { com.hypixel.hytale.protocol.Vector3f netOffset = new com.hypixel.hytale.protocol.Vector3f(offset.x, offset.y, offset.z); MountedUpdate mountedUpdate; if (mountedToEntity != null) { - int mountedToNetworkId = ref.getStore().getComponent(mountedToEntity, NetworkId.getComponentType()).getId(); + NetworkId mountedToNetworkIdComponent = ref.getStore().getComponent(mountedToEntity, NetworkId.getComponentType()); + if (mountedToNetworkIdComponent == null) { + return; + } + + int mountedToNetworkId = mountedToNetworkIdComponent.getId(); mountedUpdate = new MountedUpdate(mountedToNetworkId, netOffset, component.getControllerType(), null); } else { if (mountedToBlock == null) { diff --git a/src/com/hypixel/hytale/builtin/mounts/NPCMountSystems.java b/src/com/hypixel/hytale/builtin/mounts/NPCMountSystems.java index 3d8ff16f..3231b4ec 100644 --- a/src/com/hypixel/hytale/builtin/mounts/NPCMountSystems.java +++ b/src/com/hypixel/hytale/builtin/mounts/NPCMountSystems.java @@ -18,6 +18,8 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.entities.NPCEntity; import com.hypixel.hytale.server.npc.systems.RoleChangeSystem; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class NPCMountSystems { public static class DismountOnMountDeath extends DeathSystems.OnDeathSystem { @@ -35,7 +37,10 @@ public class NPCMountSystems { PlayerRef playerRef = mountComponent.getOwnerPlayerRef(); if (playerRef != null) { - MountPlugin.resetOriginalPlayerMovementSettings(playerRef, store); + Ref playerEntityRef = playerRef.getReference(); + if (playerEntityRef != null && playerEntityRef.isValid()) { + MountPlugin.resetOriginalPlayerMovementSettings(playerEntityRef, store); + } } } } @@ -54,7 +59,7 @@ public class NPCMountSystems { assert playerComponent != null; - MountPlugin.checkDismountNpc(commandBuffer, playerComponent); + MountPlugin.checkDismountNpc(commandBuffer, ref, playerComponent); } } @@ -84,21 +89,18 @@ public class NPCMountSystems { resetOriginalRoleMount(ref, store, commandBuffer, mountComponent); } else { NPCEntity npcComponent = store.getComponent(ref, NPCEntity.getComponentType()); - - assert npcComponent != null; - - NetworkId networkIdComponent = store.getComponent(ref, NetworkId.getComponentType()); - - assert networkIdComponent != null; - - int networkId = networkIdComponent.getId(); - MountNPC packet = new MountNPC(mountComponent.getAnchorX(), mountComponent.getAnchorY(), mountComponent.getAnchorZ(), networkId); - Player playerComponent = playerRef.getComponent(Player.getComponentType()); - - assert playerComponent != null; - - playerComponent.setMountEntityId(networkId); - playerRef.getPacketHandler().write(packet); + if (npcComponent != null) { + NetworkId networkIdComponent = store.getComponent(ref, NetworkId.getComponentType()); + if (networkIdComponent != null) { + int networkId = networkIdComponent.getId(); + MountNPC packet = new MountNPC(mountComponent.getAnchorX(), mountComponent.getAnchorY(), mountComponent.getAnchorZ(), networkId); + Player playerComponent = playerRef.getComponent(Player.getComponentType()); + if (playerComponent != null) { + playerComponent.setMountEntityId(networkId); + playerRef.getPacketHandler().write(packet); + } + } + } } } @@ -109,11 +111,10 @@ public class NPCMountSystems { @Nonnull NPCMountComponent mountComponent ) { NPCEntity npcComponent = store.getComponent(ref, NPCEntity.getComponentType()); - - assert npcComponent != null; - - RoleChangeSystem.requestRoleChange(ref, npcComponent.getRole(), mountComponent.getOriginalRoleIndex(), false, "Idle", null, store); - commandBuffer.removeComponent(ref, NPCMountComponent.getComponentType()); + if (npcComponent != null) { + RoleChangeSystem.requestRoleChange(ref, npcComponent.getRole(), mountComponent.getOriginalRoleIndex(), false, "Idle", null, store); + commandBuffer.removeComponent(ref, NPCMountComponent.getComponentType()); + } } @Override @@ -122,4 +123,35 @@ public class NPCMountSystems { ) { } } + + public static class OnPlayerRemove extends RefSystem { + @Override + public void onEntityAdded( + @NonNullDecl Ref ref, + @NonNullDecl AddReason reason, + @NonNullDecl Store store, + @NonNullDecl CommandBuffer commandBuffer + ) { + } + + @Override + public void onEntityRemove( + @NonNullDecl Ref ref, + @NonNullDecl RemoveReason reason, + @NonNullDecl Store store, + @NonNullDecl CommandBuffer commandBuffer + ) { + Player player = commandBuffer.getComponent(ref, Player.getComponentType()); + + assert player != null; + + MountPlugin.checkDismountNpc(commandBuffer, ref, player); + } + + @Nullable + @Override + public Query getQuery() { + return Player.getComponentType(); + } + } } diff --git a/src/com/hypixel/hytale/builtin/portals/PortalsPlugin.java b/src/com/hypixel/hytale/builtin/portals/PortalsPlugin.java index 5baefc54..e603bf3f 100644 --- a/src/com/hypixel/hytale/builtin/portals/PortalsPlugin.java +++ b/src/com/hypixel/hytale/builtin/portals/PortalsPlugin.java @@ -93,7 +93,7 @@ public class PortalsPlugin extends JavaPlugin { this.getCodecRegistry(GameplayConfig.PLUGIN_CODEC).register(PortalGameplayConfig.class, "Portal", PortalGameplayConfig.CODEC); } - private void turnOffPortalWhenWorldRemoved(RemoveWorldEvent event) { + private void turnOffPortalWhenWorldRemoved(@Nonnull RemoveWorldEvent event) { for (World world : Universe.get().getWorlds().values()) { if (world != event.getWorld()) { world.execute(() -> PortalInvalidDestinationSystem.turnOffPortalsInWorld(world, event.getWorld())); diff --git a/src/com/hypixel/hytale/builtin/portals/commands/PortalWorldCommandBase.java b/src/com/hypixel/hytale/builtin/portals/commands/PortalWorldCommandBase.java index 918efc99..cb95e323 100644 --- a/src/com/hypixel/hytale/builtin/portals/commands/PortalWorldCommandBase.java +++ b/src/com/hypixel/hytale/builtin/portals/commands/PortalWorldCommandBase.java @@ -10,17 +10,20 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public abstract class PortalWorldCommandBase extends AbstractWorldCommand { - public PortalWorldCommandBase(String name, String description) { + @Nonnull + private static final Message MESSAGE_SERVER_COMMANDS_PORTALS_NOT_IN_PORTAL = Message.translation("server.commands.portals.notInPortal"); + + public PortalWorldCommandBase(@Nonnull String name, @Nonnull String description) { super(name, description); } @Override protected final void execute(@Nonnull CommandContext context, @Nonnull World world, @Nonnull Store store) { - PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType()); - if (!portalWorld.exists()) { - context.sendMessage(Message.translation("server.commands.portals.notInPortal")); + PortalWorld portalWorldResource = store.getResource(PortalWorld.getResourceType()); + if (!portalWorldResource.exists()) { + context.sendMessage(MESSAGE_SERVER_COMMANDS_PORTALS_NOT_IN_PORTAL); } else { - this.execute(context, world, portalWorld, store); + this.execute(context, world, portalWorldResource, store); } } diff --git a/src/com/hypixel/hytale/builtin/portals/commands/TimerFragmentCommand.java b/src/com/hypixel/hytale/builtin/portals/commands/TimerFragmentCommand.java index 6d195a61..3a5e3dc8 100644 --- a/src/com/hypixel/hytale/builtin/portals/commands/TimerFragmentCommand.java +++ b/src/com/hypixel/hytale/builtin/portals/commands/TimerFragmentCommand.java @@ -11,6 +11,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class TimerFragmentCommand extends PortalWorldCommandBase { + @Nonnull private final RequiredArg remainingSecondsArg = this.withRequiredArg("seconds", "server.commands.fragment.timer.arg.seconds.desc", ArgTypes.INTEGER); public TimerFragmentCommand() { @@ -21,7 +22,7 @@ public class TimerFragmentCommand extends PortalWorldCommandBase { protected void execute(@Nonnull CommandContext context, @Nonnull World world, @Nonnull PortalWorld portalWorld, @Nonnull Store store) { int before = (int)portalWorld.getRemainingSeconds(world); int desired = this.remainingSecondsArg.get(context); - portalWorld.setRemainingSeconds(world, desired); + PortalWorld.setRemainingSeconds(world, desired); context.sendMessage(Message.translation("server.commands.fragment.timer.success").param("before", before).param("after", desired)); } } diff --git a/src/com/hypixel/hytale/builtin/portals/commands/player/LeaveCommand.java b/src/com/hypixel/hytale/builtin/portals/commands/player/LeaveCommand.java index 9272e5ef..494faf99 100644 --- a/src/com/hypixel/hytale/builtin/portals/commands/player/LeaveCommand.java +++ b/src/com/hypixel/hytale/builtin/portals/commands/player/LeaveCommand.java @@ -29,19 +29,18 @@ public class LeaveCommand extends AbstractPlayerCommand { @Nonnull CommandContext context, @Nonnull Store store, @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world ) { Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + PortalWorld portalWorldResource = store.getResource(PortalWorld.getResourceType()); + if (!portalWorldResource.exists()) { + playerRef.sendMessage(MESSAGE_COMMANDS_LEAVE_NOT_IN_PORTAL); + } else { + boolean uncursedAny = CursedItems.uncurseAll(playerComponent.getInventory().getCombinedEverything()); + if (uncursedAny) { + playerRef.sendMessage(MESSAGE_COMMANDS_LEAVE_UNCURSED_TEMP); + } - assert playerComponent != null; - - PortalWorld portalWorldResource = store.getResource(PortalWorld.getResourceType()); - if (!portalWorldResource.exists()) { - playerRef.sendMessage(MESSAGE_COMMANDS_LEAVE_NOT_IN_PORTAL); - } else { - boolean uncursedAny = CursedItems.uncurseAll(playerComponent.getInventory().getCombinedEverything()); - if (uncursedAny) { - playerRef.sendMessage(MESSAGE_COMMANDS_LEAVE_UNCURSED_TEMP); + InstancesPlugin.exitInstance(ref, store); } - - InstancesPlugin.exitInstance(ref, store); } } } diff --git a/src/com/hypixel/hytale/builtin/portals/commands/utils/CursedHeldItemCommand.java b/src/com/hypixel/hytale/builtin/portals/commands/utils/CursedHeldItemCommand.java index a81b11af..cf0fd595 100644 --- a/src/com/hypixel/hytale/builtin/portals/commands/utils/CursedHeldItemCommand.java +++ b/src/com/hypixel/hytale/builtin/portals/commands/utils/CursedHeldItemCommand.java @@ -27,20 +27,19 @@ public class CursedHeldItemCommand extends AbstractPlayerCommand { @Nonnull CommandContext context, @Nonnull Store store, @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world ) { Player playerComponent = store.getComponent(ref, Player.getComponentType()); - - assert playerComponent != null; - - Inventory inventory = playerComponent.getInventory(); - if (!inventory.usingToolsItem()) { - ItemStack inHandItemStack = inventory.getActiveHotbarItem(); - if (inHandItemStack != null && !inHandItemStack.isEmpty()) { - AdventureMetadata adventureMeta = inHandItemStack.getFromMetadataOrDefault("Adventure", AdventureMetadata.CODEC); - adventureMeta.setCursed(!adventureMeta.isCursed()); - ItemStack edited = inHandItemStack.withMetadata(AdventureMetadata.KEYED_CODEC, adventureMeta); - inventory.getHotbar().replaceItemStackInSlot(inventory.getActiveHotbarSlot(), inHandItemStack, edited); - playerRef.sendMessage(Message.translation("server.commands.cursethis.done").param("state", adventureMeta.isCursed())); - } else { - playerRef.sendMessage(MESSAGE_COMMANDS_CURSE_THIS_NOT_HOLDING_ITEM); + if (playerComponent != null) { + Inventory inventory = playerComponent.getInventory(); + if (!inventory.usingToolsItem()) { + ItemStack inHandItemStack = inventory.getActiveHotbarItem(); + if (inHandItemStack != null && !inHandItemStack.isEmpty()) { + AdventureMetadata adventureMeta = inHandItemStack.getFromMetadataOrDefault("Adventure", AdventureMetadata.CODEC); + adventureMeta.setCursed(!adventureMeta.isCursed()); + ItemStack edited = inHandItemStack.withMetadata(AdventureMetadata.KEYED_CODEC, adventureMeta); + inventory.getHotbar().replaceItemStackInSlot(inventory.getActiveHotbarSlot(), inHandItemStack, edited); + playerRef.sendMessage(Message.translation("server.commands.cursethis.done").param("state", adventureMeta.isCursed())); + } else { + playerRef.sendMessage(MESSAGE_COMMANDS_CURSE_THIS_NOT_HOLDING_ITEM); + } } } } diff --git a/src/com/hypixel/hytale/builtin/portals/commands/voidevent/StartVoidEventCommand.java b/src/com/hypixel/hytale/builtin/portals/commands/voidevent/StartVoidEventCommand.java index d7193162..fbac0b88 100644 --- a/src/com/hypixel/hytale/builtin/portals/commands/voidevent/StartVoidEventCommand.java +++ b/src/com/hypixel/hytale/builtin/portals/commands/voidevent/StartVoidEventCommand.java @@ -16,8 +16,11 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class StartVoidEventCommand extends AbstractWorldCommand { + @Nonnull private final FlagArg overrideWorld = this.withFlagArg("override", "server.commands.voidevent.start.overrideArg"); + @Nonnull private static final String HARDCODED_GAMEPLAY_CONFIG = "Portal"; + @Nonnull private static final String HARDCODED_PORTAL_TYPE = "Hederas_Lair"; public StartVoidEventCommand() { @@ -49,7 +52,7 @@ public class StartVoidEventCommand extends AbstractWorldCommand { context.sendMessage(Message.translation("server.commands.voidevent.start.overrode")); } - portalWorld.setRemainingSeconds(world, 1.0); + PortalWorld.setRemainingSeconds(world, 1.0); context.sendMessage(Message.translation("server.commands.voidevent.start.success")); } } diff --git a/src/com/hypixel/hytale/builtin/portals/components/PortalDevice.java b/src/com/hypixel/hytale/builtin/portals/components/PortalDevice.java index 933e3316..a48cdb38 100644 --- a/src/com/hypixel/hytale/builtin/portals/components/PortalDevice.java +++ b/src/com/hypixel/hytale/builtin/portals/components/PortalDevice.java @@ -11,9 +11,11 @@ import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import java.util.UUID; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PortalDevice implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PortalDevice.class, PortalDevice::new) .append(new KeyedCodec<>("Config", PortalDeviceConfig.CODEC), (portal, o) -> portal.config = o, portal -> portal.config) .add() @@ -46,6 +48,7 @@ public class PortalDevice implements Component { return this.baseBlockTypeKey; } + @Nullable public BlockType getBaseBlockType() { return BlockType.getAssetMap().getAsset(this.baseBlockTypeKey); } @@ -65,7 +68,7 @@ public class PortalDevice implements Component { } } - public void setDestinationWorld(World world) { + public void setDestinationWorld(@Nonnull World world) { this.destinationWorldUuid = world.getWorldConfig().getUuid(); } diff --git a/src/com/hypixel/hytale/builtin/portals/components/PortalDeviceConfig.java b/src/com/hypixel/hytale/builtin/portals/components/PortalDeviceConfig.java index bcb8758e..e71cc3f3 100644 --- a/src/com/hypixel/hytale/builtin/portals/components/PortalDeviceConfig.java +++ b/src/com/hypixel/hytale/builtin/portals/components/PortalDeviceConfig.java @@ -5,9 +5,11 @@ import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PortalDeviceConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PortalDeviceConfig.class, PortalDeviceConfig::new) .appendInherited( new KeyedCodec<>("SpawningState", Codec.STRING), @@ -64,14 +66,15 @@ public class PortalDeviceConfig { return this.returnBlock; } + @Nonnull public String[] getBlockStates() { return new String[]{this.onState, this.spawningState, this.offState}; } - public boolean areBlockStatesValid(BlockType baseBlockType) { + public boolean areBlockStatesValid(@Nonnull BlockType baseBlockType) { for (String stateKey : this.getBlockStates()) { - BlockType state = BlockTypeUtils.getBlockForState(baseBlockType, stateKey); - if (state == null) { + BlockType blockType = BlockTypeUtils.getBlockForState(baseBlockType, stateKey); + if (blockType == null) { return false; } } diff --git a/src/com/hypixel/hytale/builtin/portals/components/voidevent/VoidEvent.java b/src/com/hypixel/hytale/builtin/portals/components/voidevent/VoidEvent.java index e077e153..24f01b4c 100644 --- a/src/com/hypixel/hytale/builtin/portals/components/voidevent/VoidEvent.java +++ b/src/com/hypixel/hytale/builtin/portals/components/voidevent/VoidEvent.java @@ -10,22 +10,27 @@ import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class VoidEvent implements Component { public static final double MIN_BLOCKS_BETWEEN_SPAWNERS = 62.0; + @Nonnull private SpatialHashGrid> voidSpawners = new SpatialHashGrid<>(62.0); + @Nullable private VoidEventStage activeStage; public static ComponentType getComponentType() { return PortalsPlugin.getInstance().getVoidEventComponentType(); } - public VoidEventConfig getConfig(World world) { + @Nullable + public static VoidEventConfig getConfig(@Nonnull World world) { PortalGameplayConfig portalConfig = world.getGameplayConfig().getPluginConfig().get(PortalGameplayConfig.class); - return portalConfig.getVoidEvent(); + return portalConfig != null ? portalConfig.getVoidEvent() : null; } + @Nonnull public SpatialHashGrid> getVoidSpawners() { return this.voidSpawners; } diff --git a/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/InvasionPortalConfig.java b/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/InvasionPortalConfig.java index 711591db..dc29ebe1 100644 --- a/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/InvasionPortalConfig.java +++ b/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/InvasionPortalConfig.java @@ -7,9 +7,11 @@ import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import java.util.Arrays; import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class InvasionPortalConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(InvasionPortalConfig.class, InvasionPortalConfig::new) .append(new KeyedCodec<>("BlockKey", Codec.STRING), (config, o) -> config.blockKey = o, config -> config.blockKey) .documentation("The block used for evil portals that spawn around the world during the event") @@ -29,6 +31,7 @@ public class InvasionPortalConfig { return this.blockKey; } + @Nullable public BlockType getBlockType() { return BlockType.getAssetMap().getAsset(this.blockKey); } @@ -43,6 +46,7 @@ public class InvasionPortalConfig { return this.spawnBeacons; } + @Nonnull public List getSpawnBeaconsList() { return this.spawnBeacons == null ? Collections.emptyList() : Arrays.asList(this.spawnBeacons); } diff --git a/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/VoidEventConfig.java b/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/VoidEventConfig.java index bc0344e5..9c328e8e 100644 --- a/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/VoidEventConfig.java +++ b/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/VoidEventConfig.java @@ -9,9 +9,11 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class VoidEventConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(VoidEventConfig.class, VoidEventConfig::new) .append(new KeyedCodec<>("DurationSeconds", Codec.INTEGER), (config, o) -> config.durationSeconds = o, config -> config.durationSeconds) .documentation( diff --git a/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/VoidEventStage.java b/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/VoidEventStage.java index 5449248e..8ae23cd2 100644 --- a/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/VoidEventStage.java +++ b/src/com/hypixel/hytale/builtin/portals/components/voidevent/config/VoidEventStage.java @@ -4,9 +4,11 @@ import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.server.core.asset.type.weather.config.Weather; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class VoidEventStage { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(VoidEventStage.class, VoidEventStage::new) .append(new KeyedCodec<>("SecondsInto", Codec.INTEGER), (stage, o) -> stage.secondsInto = o, stage -> stage.secondsInto) .documentation("How many seconds into the void event does this stage becomes the active stage.") diff --git a/src/com/hypixel/hytale/builtin/portals/integrations/PortalGameplayConfig.java b/src/com/hypixel/hytale/builtin/portals/integrations/PortalGameplayConfig.java index e9823407..373b9068 100644 --- a/src/com/hypixel/hytale/builtin/portals/integrations/PortalGameplayConfig.java +++ b/src/com/hypixel/hytale/builtin/portals/integrations/PortalGameplayConfig.java @@ -3,9 +3,11 @@ package com.hypixel.hytale.builtin.portals.integrations; import com.hypixel.hytale.builtin.portals.components.voidevent.config.VoidEventConfig; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PortalGameplayConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PortalGameplayConfig.class, PortalGameplayConfig::new) .append(new KeyedCodec<>("VoidEvent", VoidEventConfig.CODEC), (config, o) -> config.voidEvent = o, config -> config.voidEvent) .add() diff --git a/src/com/hypixel/hytale/builtin/portals/integrations/PortalMarkerProvider.java b/src/com/hypixel/hytale/builtin/portals/integrations/PortalMarkerProvider.java index 076ad035..0a718243 100644 --- a/src/com/hypixel/hytale/builtin/portals/integrations/PortalMarkerProvider.java +++ b/src/com/hypixel/hytale/builtin/portals/integrations/PortalMarkerProvider.java @@ -2,31 +2,25 @@ package com.hypixel.hytale.builtin.portals.integrations; import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.spawn.IndividualSpawnProvider; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; -import com.hypixel.hytale.server.core.util.PositionUtil; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; +import javax.annotation.Nonnull; public class PortalMarkerProvider implements WorldMapManager.MarkerProvider { public static final PortalMarkerProvider INSTANCE = new PortalMarkerProvider(); @Override - public void update(World world, MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { if (world.getWorldConfig().getSpawnProvider() instanceof IndividualSpawnProvider individualSpawnProvider) { Transform spawnPoint = individualSpawnProvider.getFirstSpawnPoint(); if (spawnPoint != null) { - tracker.trySendMarker( - chunkViewRadius, - playerChunkX, - playerChunkZ, - spawnPoint.getPosition(), - spawnPoint.getRotation().getYaw(), - "Portal", - "Fragment Exit", - spawnPoint, - (id, name, sp) -> new MapMarker(id, name, "Portal.png", PositionUtil.toTransformPacket(sp), null) - ); + MapMarker marker = new MapMarkerBuilder("Portal", "Portal.png", spawnPoint).withName(Message.translation("server.portals.exit.marker")).build(); + collector.add(marker); } } } diff --git a/src/com/hypixel/hytale/builtin/portals/integrations/PortalRemovalCondition.java b/src/com/hypixel/hytale/builtin/portals/integrations/PortalRemovalCondition.java index 1e1f32ac..20453439 100644 --- a/src/com/hypixel/hytale/builtin/portals/integrations/PortalRemovalCondition.java +++ b/src/com/hypixel/hytale/builtin/portals/integrations/PortalRemovalCondition.java @@ -17,12 +17,14 @@ import java.time.Instant; import javax.annotation.Nonnull; public class PortalRemovalCondition implements RemovalCondition { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PortalRemovalCondition.class, PortalRemovalCondition::new) .documentation("A condition for temporary portal worlds.") - .append(new KeyedCodec<>("TimeoutSeconds", Codec.DOUBLE), (o, i) -> o.setTimeLimitSeconds(i), o -> o.getTimeLimitSeconds()) + .append(new KeyedCodec<>("TimeoutSeconds", Codec.DOUBLE), PortalRemovalCondition::setTimeLimitSeconds, o -> o.getTimeLimitSeconds()) .documentation("How long the portal world will stay open (in seconds) after being joined.") .add() .build(); + @Nonnull private final WorldEmptyCondition worldEmptyCondition = new WorldEmptyCondition(90.0); private TimeoutCondition timeLimitCondition; @@ -42,13 +44,13 @@ public class PortalRemovalCondition implements RemovalCondition { this.timeLimitCondition = new TimeoutCondition(timeLimitSeconds); } - public double getElapsedSeconds(World world) { + public double getElapsedSeconds(@Nonnull World world) { double timeLimitSeconds = this.timeLimitCondition.getTimeoutSeconds(); double remainingSeconds = this.getRemainingSeconds(world); return Math.max(0.0, timeLimitSeconds - remainingSeconds); } - public double getRemainingSeconds(World world) { + public double getRemainingSeconds(@Nonnull World world) { Store chunkStore = world.getChunkStore().getStore(); Store entityStore = world.getEntityStore().getStore(); InstanceDataResource instanceData = chunkStore.getResource(InstanceDataResource.getResourceType()); @@ -62,7 +64,7 @@ public class PortalRemovalCondition implements RemovalCondition { } } - public void setRemainingSeconds(World world, double seconds) { + public static void setRemainingSeconds(@Nonnull World world, double seconds) { seconds = Math.max(0.0, seconds); Store chunkStore = world.getChunkStore().getStore(); Store entityStore = world.getEntityStore().getStore(); diff --git a/src/com/hypixel/hytale/builtin/portals/interactions/EnterPortalInteraction.java b/src/com/hypixel/hytale/builtin/portals/interactions/EnterPortalInteraction.java index 170c24f1..a42b35cb 100644 --- a/src/com/hypixel/hytale/builtin/portals/interactions/EnterPortalInteraction.java +++ b/src/com/hypixel/hytale/builtin/portals/interactions/EnterPortalInteraction.java @@ -35,6 +35,14 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class EnterPortalInteraction extends SimpleBlockInteraction { + @Nonnull + private static final Message MESSAGE_PORTALS_DEVICE_REF_INVALID = Message.translation("server.portals.device.refInvalid"); + @Nonnull + private static final Message MESSAGE_PORTALS_DEVICE_WORLD_IS_DEAD = Message.translation("server.portals.device.worldIsDead"); + @Nonnull + private static final Message MESSAGE_PORTALS_DEVICE_NO_SPAWN = Message.translation("server.portals.device.worldNoSpawn"); + @Nonnull + private static final Message MESSAGE_PORTALS_DEVICE_BLOCK_ENTITY_REF_INVALID = Message.translation("server.portals.device.blockEntityRefInvalid"); @Nonnull public static final Duration MINIMUM_TIME_IN_WORLD = Duration.ofMillis(3000L); @Nonnull @@ -42,10 +50,6 @@ public class EnterPortalInteraction extends SimpleBlockInteraction { EnterPortalInteraction.class, EnterPortalInteraction::new, SimpleBlockInteraction.CODEC ) .build(); - private static final Message MESSAGE_PORTALS_DEVICE_REF_INVALID = Message.translation("server.portals.device.refInvalid"); - private static final Message MESSAGE_PORTALS_DEVICE_WORLD_IS_DEAD = Message.translation("server.portals.device.worldIsDead"); - private static final Message MESSAGE_PORTALS_DEVICE_NO_SPAWN = Message.translation("server.portals.device.worldNoSpawn"); - private static final Message MESSAGE_PORTALS_DEVICE_BLOCK_ENTITY_REF_INVALID = Message.translation("server.portals.device.blockEntityRefInvalid"); @Nonnull @Override @@ -70,11 +74,12 @@ public class EnterPortalInteraction extends SimpleBlockInteraction { } else if (playerComponent.getSinceLastSpawnNanos() < MINIMUM_TIME_IN_WORLD.toNanos()) { context.getState().state = InteractionState.Failed; } else { - PortalDevice portalDevice = BlockModule.get().getComponent(PortalDevice.getComponentType(), world, targetBlock.x, targetBlock.y, targetBlock.z); + PortalDevice portalDevice = BlockModule.getComponent(PortalDevice.getComponentType(), world, targetBlock.x, targetBlock.y, targetBlock.z); if (portalDevice == null) { context.getState().state = InteractionState.Failed; } else { - WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z)); + long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); + WorldChunk chunk = world.getChunkIfInMemory(chunkIndex); if (chunk == null) { context.getState().state = InteractionState.Failed; } else { @@ -91,44 +96,53 @@ public class EnterPortalInteraction extends SimpleBlockInteraction { context.getState().state = InteractionState.Failed; } else { UUIDComponent uuidComponent = commandBuffer.getComponent(ref, UUIDComponent.getComponentType()); - - assert uuidComponent != null; - - UUID playerUuid = uuidComponent.getUuid(); - fetchTargetWorldState(targetWorld, playerUuid).thenAcceptAsync(state -> { - if (!ref.isValid()) { - playerComponent.sendMessage(MESSAGE_PORTALS_DEVICE_REF_INVALID); - context.getState().state = InteractionState.Failed; - } else { - switch (state) { - case OKAY: - InstancesPlugin.teleportPlayerToInstance(ref, commandBuffer, targetWorld, returnTransform); - break; - case WORLD_DEAD: - playerComponent.sendMessage(MESSAGE_PORTALS_DEVICE_WORLD_IS_DEAD); - context.getState().state = InteractionState.Failed; - break; - case DIED_IN_WORLD: - PlayerRef playerRefComponent = commandBuffer.getComponent(ref, PlayerRef.getComponentType()); - - assert playerRefComponent != null; - - Ref blockEntityRef = BlockModule.getBlockEntity(world, targetBlock.x, targetBlock.y, targetBlock.z); - if (blockEntityRef == null || !blockEntityRef.isValid()) { - playerComponent.sendMessage(MESSAGE_PORTALS_DEVICE_BLOCK_ENTITY_REF_INVALID); + if (uuidComponent == null) { + context.getState().state = InteractionState.Failed; + } else { + UUID playerUuid = uuidComponent.getUuid(); + fetchTargetWorldState(targetWorld, playerUuid) + .thenAcceptAsync( + state -> { + if (!ref.isValid()) { + playerComponent.sendMessage(MESSAGE_PORTALS_DEVICE_REF_INVALID); context.getState().state = InteractionState.Failed; - return; - } + } else { + switch (state) { + case OKAY: + InstancesPlugin.teleportPlayerToInstance(ref, commandBuffer, targetWorld, returnTransform); + break; + case WORLD_DEAD: + playerComponent.sendMessage(MESSAGE_PORTALS_DEVICE_WORLD_IS_DEAD); + context.getState().state = InteractionState.Failed; + break; + case DIED_IN_WORLD: + PlayerRef playerRefComponent = commandBuffer.getComponent(ref, PlayerRef.getComponentType()); + if (playerRefComponent == null) { + context.getState().state = InteractionState.Failed; + return; + } - PortalDeviceActivePage activePage = new PortalDeviceActivePage(playerRefComponent, portalDevice.getConfig(), blockEntityRef); - playerComponent.getPageManager().openCustomPage(ref, world.getEntityStore().getStore(), activePage); - break; - case NO_SPAWN_AVAILABLE: - playerComponent.sendMessage(MESSAGE_PORTALS_DEVICE_NO_SPAWN); - context.getState().state = InteractionState.Failed; - } - } - }, world); + Ref blockEntityRef = BlockModule.getBlockEntity(world, targetBlock.x, targetBlock.y, targetBlock.z); + if (blockEntityRef == null || !blockEntityRef.isValid()) { + playerComponent.sendMessage(MESSAGE_PORTALS_DEVICE_BLOCK_ENTITY_REF_INVALID); + context.getState().state = InteractionState.Failed; + return; + } + + PortalDeviceActivePage activePage = new PortalDeviceActivePage( + playerRefComponent, portalDevice.getConfig(), blockEntityRef + ); + playerComponent.getPageManager().openCustomPage(ref, world.getEntityStore().getStore(), activePage); + break; + case NO_SPAWN_AVAILABLE: + playerComponent.sendMessage(MESSAGE_PORTALS_DEVICE_NO_SPAWN); + context.getState().state = InteractionState.Failed; + } + } + }, + world + ); + } } } } diff --git a/src/com/hypixel/hytale/builtin/portals/interactions/ReturnPortalInteraction.java b/src/com/hypixel/hytale/builtin/portals/interactions/ReturnPortalInteraction.java index de1858af..94b97804 100644 --- a/src/com/hypixel/hytale/builtin/portals/interactions/ReturnPortalInteraction.java +++ b/src/com/hypixel/hytale/builtin/portals/interactions/ReturnPortalInteraction.java @@ -32,7 +32,9 @@ public class ReturnPortalInteraction extends SimpleBlockInteraction { ReturnPortalInteraction.class, ReturnPortalInteraction::new, SimpleBlockInteraction.CODEC ) .build(); + @Nonnull private static final Message MESSAGE_PORTALS_ATTUNING_TO_WORLD = Message.translation("server.portals.attuningToWorld"); + @Nonnull private static final Message MESSAGE_PORTALS_DEVICE_NOT_IN_PORTAL_WORLD = Message.translation("server.portals.device.notInPortalWorld"); @Override diff --git a/src/com/hypixel/hytale/builtin/portals/resources/PortalWorld.java b/src/com/hypixel/hytale/builtin/portals/resources/PortalWorld.java index 724a649f..a24d4037 100644 --- a/src/com/hypixel/hytale/builtin/portals/resources/PortalWorld.java +++ b/src/com/hypixel/hytale/builtin/portals/resources/PortalWorld.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PortalWorld implements Resource { @@ -29,13 +30,16 @@ public class PortalWorld implements Resource { private Set diedInWorld; private Set seesUi; private Transform spawnPoint; + @Nullable private Ref voidEventRef; public static ResourceType getResourceType() { return PortalsPlugin.getInstance().getPortalResourceType(); } - public void init(PortalType portalType, int timeLimitSeconds, PortalRemovalCondition removalCondition, PortalGameplayConfig gameplayConfig) { + public void init( + @Nonnull PortalType portalType, int timeLimitSeconds, @Nonnull PortalRemovalCondition removalCondition, @Nonnull PortalGameplayConfig gameplayConfig + ) { this.portalTypeId = portalType.getId(); this.timeLimitSeconds = timeLimitSeconds; this.worldRemovalCondition = removalCondition; @@ -44,6 +48,7 @@ public class PortalWorld implements Resource { this.seesUi = Collections.newSetFromMap(new ConcurrentHashMap<>()); } + @Nullable public PortalType getPortalType() { return this.portalTypeId == null ? null : PortalType.getAssetMap().getAsset(this.portalTypeId); } @@ -56,16 +61,16 @@ public class PortalWorld implements Resource { return this.timeLimitSeconds; } - public double getElapsedSeconds(World world) { + public double getElapsedSeconds(@Nonnull World world) { return this.worldRemovalCondition.getElapsedSeconds(world); } - public double getRemainingSeconds(World world) { + public double getRemainingSeconds(@Nonnull World world) { return this.worldRemovalCondition.getRemainingSeconds(world); } - public void setRemainingSeconds(World world, double seconds) { - this.worldRemovalCondition.setRemainingSeconds(world, seconds); + public static void setRemainingSeconds(@Nonnull World world, double seconds) { + PortalRemovalCondition.setRemainingSeconds(world, seconds); } public Set getDiedInWorld() { @@ -77,11 +82,17 @@ public class PortalWorld implements Resource { } public PortalGameplayConfig getGameplayConfig() { - GameplayConfig gameplayConfig = this.getPortalType().getGameplayConfig(); - PortalGameplayConfig portalGameplayConfig = gameplayConfig == null ? null : gameplayConfig.getPluginConfig().get(PortalGameplayConfig.class); - return portalGameplayConfig != null ? portalGameplayConfig : this.storedGameplayConfig; + PortalType portalType = this.getPortalType(); + if (portalType == null) { + return this.storedGameplayConfig; + } else { + GameplayConfig gameplayConfig = this.getPortalType().getGameplayConfig(); + PortalGameplayConfig portalGameplayConfig = gameplayConfig == null ? null : gameplayConfig.getPluginConfig().get(PortalGameplayConfig.class); + return portalGameplayConfig != null ? portalGameplayConfig : this.storedGameplayConfig; + } } + @Nullable public VoidEventConfig getVoidEventConfig() { return this.getGameplayConfig().getVoidEvent(); } @@ -108,35 +119,44 @@ public class PortalWorld implements Resource { return this.getVoidEventRef() != null; } - public void setVoidEventRef(Ref voidEventRef) { + public void setVoidEventRef(@Nullable Ref voidEventRef) { this.voidEventRef = voidEventRef; } - public UpdatePortal createFullPacket(World world) { - boolean hasBreach = this.getPortalType().isVoidInvasionEnabled(); + @Nonnull + public UpdatePortal createFullPacket(@Nonnull World world) { + PortalType portalType = this.getPortalType(); + boolean hasBreach = portalType.isVoidInvasionEnabled(); int explorationSeconds; int breachSeconds; if (hasBreach) { - breachSeconds = this.getGameplayConfig().getVoidEvent().getDurationSeconds(); + VoidEventConfig voidEvent = this.getGameplayConfig().getVoidEvent(); + breachSeconds = voidEvent.getDurationSeconds(); explorationSeconds = this.timeLimitSeconds - breachSeconds; } else { explorationSeconds = this.timeLimitSeconds; breachSeconds = 0; } - PortalDef portalDef = new PortalDef(this.getPortalType().getDescription().getDisplayNameKey(), explorationSeconds, breachSeconds); + PortalDef portalDef = new PortalDef(portalType.getDescription().getDisplayNameKey(), explorationSeconds, breachSeconds); return new UpdatePortal(this.createStateForPacket(world), portalDef); } - public UpdatePortal createUpdatePacket(World world) { + @Nonnull + public UpdatePortal createUpdatePacket(@Nonnull World world) { return new UpdatePortal(this.createStateForPacket(world), null); } - private PortalState createStateForPacket(World world) { + @Nonnull + private PortalState createStateForPacket(@Nonnull World world) { double remainingSeconds = this.worldRemovalCondition.getRemainingSeconds(world); - int breachSeconds = this.getGameplayConfig().getVoidEvent().getDurationSeconds(); - if (this.getPortalType().isVoidInvasionEnabled() && remainingSeconds > breachSeconds) { - remainingSeconds -= breachSeconds; + VoidEventConfig voidEvent = this.getVoidEventConfig(); + PortalType portalType = this.getPortalType(); + if (voidEvent != null && portalType != null) { + int breachSeconds = voidEvent.getDurationSeconds(); + if (portalType.isVoidInvasionEnabled() && remainingSeconds > breachSeconds) { + remainingSeconds -= breachSeconds; + } } return new PortalState((int)Math.ceil(remainingSeconds), this.isVoidEventActive()); diff --git a/src/com/hypixel/hytale/builtin/portals/systems/CloseWorldWhenBreakingDeviceSystems.java b/src/com/hypixel/hytale/builtin/portals/systems/CloseWorldWhenBreakingDeviceSystems.java index 74ba5736..4a7978ec 100644 --- a/src/com/hypixel/hytale/builtin/portals/systems/CloseWorldWhenBreakingDeviceSystems.java +++ b/src/com/hypixel/hytale/builtin/portals/systems/CloseWorldWhenBreakingDeviceSystems.java @@ -30,6 +30,7 @@ public final class CloseWorldWhenBreakingDeviceSystems { } public static class ComponentRemoved extends RefChangeSystem { + @Nonnull @Override public ComponentType componentType() { return PortalDevice.getComponentType(); diff --git a/src/com/hypixel/hytale/builtin/portals/systems/PortalInvalidDestinationSystem.java b/src/com/hypixel/hytale/builtin/portals/systems/PortalInvalidDestinationSystem.java index 4b9be220..65023af5 100644 --- a/src/com/hypixel/hytale/builtin/portals/systems/PortalInvalidDestinationSystem.java +++ b/src/com/hypixel/hytale/builtin/portals/systems/PortalInvalidDestinationSystem.java @@ -49,38 +49,48 @@ public class PortalInvalidDestinationSystem extends RefSystem { return Query.and(PortalDevice.getComponentType(), BlockModule.BlockStateInfo.getComponentType()); } - public static void turnOffPortalsInWorld(World originWorld, World destinationWorld) { + public static void turnOffPortalsInWorld(@Nonnull World originWorld, @Nonnull World destinationWorld) { UUID destinationWorldUuid = destinationWorld.getWorldConfig().getUuid(); - Store store = originWorld.getChunkStore().getStore(); + Store originStore = originWorld.getChunkStore().getStore(); AndQuery entityQuery = Query.and(PortalDevice.getComponentType(), BlockModule.BlockStateInfo.getComponentType()); - store.forEachEntityParallel(entityQuery, (id, archetypeChunk, commandBuffer) -> { + originStore.forEachEntityParallel(entityQuery, (id, archetypeChunk, commandBuffer) -> { PortalDevice portalDevice = archetypeChunk.getComponent(id, PortalDevice.getComponentType()); - if (destinationWorldUuid.equals(portalDevice.getDestinationWorldUuid())) { + if (portalDevice != null && destinationWorldUuid.equals(portalDevice.getDestinationWorldUuid())) { BlockModule.BlockStateInfo blockStateInfo = archetypeChunk.getComponent(id, BlockModule.BlockStateInfo.getComponentType()); originWorld.execute(() -> turnOffPortalBlock(originWorld, portalDevice, blockStateInfo)); } }); } - private static void turnOffPortalBlock(World world, PortalDevice portalDevice, BlockModule.BlockStateInfo blockStateInfo) { + private static void turnOffPortalBlock(@Nonnull World world, @Nonnull PortalDevice portalDevice, @Nonnull BlockModule.BlockStateInfo blockStateInfo) { Ref chunkRef = blockStateInfo.getChunkRef(); - if (chunkRef != null && chunkRef.isValid()) { + if (chunkRef.isValid()) { Store store = world.getChunkStore().getStore(); - WorldChunk worldChunk = store.getComponent(chunkRef, WorldChunk.getComponentType()); - if (worldChunk != null) { + WorldChunk worldChunkComponent = store.getComponent(chunkRef, WorldChunk.getComponentType()); + if (worldChunkComponent != null) { int index = blockStateInfo.getIndex(); int x = ChunkUtil.xFromBlockInColumn(index); int y = ChunkUtil.yFromBlockInColumn(index); int z = ChunkUtil.zFromBlockInColumn(index); PortalDeviceConfig config = portalDevice.getConfig(); - BlockType blockType = worldChunk.getBlockType(x, y, z); - BlockType offState = BlockTypeUtils.getBlockForState(blockType, config.getOffState()); - if (offState == null) { + BlockType blockType = worldChunkComponent.getBlockType(x, y, z); + if (blockType == null) { HytaleLogger.getLogger() .at(Level.WARNING) - .log("Couldn't find/set off set for portal block, either " + blockType.getId() + " is misconfigured or the block changed unexpectedly"); + .log( + "Couldn't find portal block at expected location, either " + + portalDevice.getBaseBlockTypeKey() + + " is misconfigured or the block changed unexpectedly" + ); } else { - worldChunk.setBlockInteractionState(x, y, z, blockType, config.getOffState(), false); + BlockType offBlockType = BlockTypeUtils.getBlockForState(blockType, config.getOffState()); + if (offBlockType == null) { + HytaleLogger.getLogger() + .at(Level.WARNING) + .log("Couldn't find/set off set for portal block, either " + blockType.getId() + " is misconfigured or the block changed unexpectedly"); + } else { + worldChunkComponent.setBlockInteractionState(x, y, z, blockType, config.getOffState(), false); + } } } } diff --git a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/StartVoidEventInFragmentSystem.java b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/StartVoidEventInFragmentSystem.java index 72cd2495..5b33d532 100644 --- a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/StartVoidEventInFragmentSystem.java +++ b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/StartVoidEventInFragmentSystem.java @@ -20,16 +20,16 @@ public class StartVoidEventInFragmentSystem extends DelayedSystem { @Override public void delayedTick(float dt, int systemIndex, @Nonnull Store store) { - PortalWorld portalWorld = store.getResource(PortalWorld.getResourceType()); - if (portalWorld.exists()) { - if (portalWorld.getPortalType().isVoidInvasionEnabled()) { + PortalWorld portalWorldResource = store.getResource(PortalWorld.getResourceType()); + if (portalWorldResource.exists()) { + if (portalWorldResource.getPortalType().isVoidInvasionEnabled()) { World world = store.getExternalData().getWorld(); - VoidEventConfig voidEventConfig = portalWorld.getVoidEventConfig(); - int timeLimitSeconds = portalWorld.getTimeLimitSeconds(); + VoidEventConfig voidEventConfig = portalWorldResource.getVoidEventConfig(); + int timeLimitSeconds = portalWorldResource.getTimeLimitSeconds(); int shouldStartAfter = voidEventConfig.getShouldStartAfterSeconds(timeLimitSeconds); - int elapsedSeconds = (int)Math.ceil(portalWorld.getElapsedSeconds(world)); - Ref voidEventRef = portalWorld.getVoidEventRef(); - boolean exists = voidEventRef != null; + int elapsedSeconds = (int)Math.ceil(portalWorldResource.getElapsedSeconds(world)); + Ref voidEventRef = portalWorldResource.getVoidEventRef(); + boolean exists = voidEventRef != null && voidEventRef.isValid(); boolean shouldExist = elapsedSeconds >= shouldStartAfter; if (exists && !shouldExist) { store.removeEntity(voidEventRef, RemoveReason.REMOVE); @@ -39,7 +39,7 @@ public class StartVoidEventInFragmentSystem extends DelayedSystem { Holder holder = EntityStore.REGISTRY.newHolder(); holder.addComponent(VoidEvent.getComponentType(), new VoidEvent()); Ref spawnedEventRef = store.addEntity(holder, AddReason.SPAWN); - portalWorld.setVoidEventRef(spawnedEventRef); + portalWorldResource.setVoidEventRef(spawnedEventRef); } } } diff --git a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidEventRefSystem.java b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidEventRefSystem.java index 691fca6c..e19c4641 100644 --- a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidEventRefSystem.java +++ b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidEventRefSystem.java @@ -50,7 +50,7 @@ public final class VoidEventRefSystem extends RefSystem { VoidEvent voidEvent = commandBuffer.getComponent(ref, VoidEvent.getComponentType()); VoidEventStage activeStage = voidEvent.getActiveStage(); if (activeStage != null) { - VoidEventStagesSystem.stopStage(activeStage, world, store, commandBuffer); + VoidEventStagesSystem.stopStage(activeStage, store, commandBuffer); voidEvent.setActiveStage(null); } } diff --git a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidEventStagesSystem.java b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidEventStagesSystem.java index 1dcf2813..cf9cf874 100644 --- a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidEventStagesSystem.java +++ b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidEventStagesSystem.java @@ -39,29 +39,31 @@ public class VoidEventStagesSystem extends DelayedEntitySystem { if (voidEvent != null) { World world = store.getExternalData().getWorld(); VoidEventConfig voidEventConfig = portalWorld.getVoidEventConfig(); - double elapsedSecondsInPortal = portalWorld.getElapsedSeconds(world); - int timeLimitSeconds = portalWorld.getTimeLimitSeconds(); - int shouldStartAfter = voidEventConfig.getShouldStartAfterSeconds(timeLimitSeconds); - int elapsedSecondsInEvent = (int)Math.max(0.0, elapsedSecondsInPortal - shouldStartAfter); - VoidEventStage currentStage = voidEvent.getActiveStage(); - VoidEventStage desiredStage = this.computeAppropriateStage(voidEventConfig, elapsedSecondsInEvent); - if (currentStage != desiredStage) { - if (currentStage != null) { - stopStage(currentStage, world, store, commandBuffer); - } + if (voidEventConfig != null) { + double elapsedSecondsInPortal = portalWorld.getElapsedSeconds(world); + int timeLimitSeconds = portalWorld.getTimeLimitSeconds(); + int shouldStartAfter = voidEventConfig.getShouldStartAfterSeconds(timeLimitSeconds); + int elapsedSecondsInEvent = (int)Math.max(0.0, elapsedSecondsInPortal - shouldStartAfter); + VoidEventStage currentStage = voidEvent.getActiveStage(); + VoidEventStage desiredStage = computeAppropriateStage(voidEventConfig, elapsedSecondsInEvent); + if (currentStage != desiredStage) { + if (currentStage != null) { + stopStage(currentStage, store, commandBuffer); + } - if (desiredStage != null) { - startStage(desiredStage, world, store, commandBuffer); - } + if (desiredStage != null) { + startStage(desiredStage, store, commandBuffer); + } - voidEvent.setActiveStage(desiredStage); + voidEvent.setActiveStage(desiredStage); + } } } } } @Nullable - private VoidEventStage computeAppropriateStage(VoidEventConfig config, int elapsedSeconds) { + private static VoidEventStage computeAppropriateStage(@Nonnull VoidEventConfig config, int elapsedSeconds) { List stages = config.getStagesSortedByStartTime(); for (int i = stages.size() - 1; i >= 0; i--) { @@ -74,7 +76,7 @@ public class VoidEventStagesSystem extends DelayedEntitySystem { return null; } - public static void startStage(VoidEventStage stage, World world, Store store, CommandBuffer commandBuffer) { + public static void startStage(@Nonnull VoidEventStage stage, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer) { HytaleLogger.getLogger().at(Level.INFO).log("Starting stage SecondsInto=" + stage.getSecondsInto() + " in portal void event"); String forcedWeatherId = stage.getForcedWeatherId(); if (forcedWeatherId != null) { @@ -83,7 +85,7 @@ public class VoidEventStagesSystem extends DelayedEntitySystem { } } - public static void stopStage(VoidEventStage stage, World world, Store store, CommandBuffer commandBuffer) { + public static void stopStage(@Nonnull VoidEventStage stage, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer) { HytaleLogger.getLogger().at(Level.INFO).log("Stopping stage SecondsInto=" + stage.getSecondsInto() + " in portal void event"); String forcedWeatherId = stage.getForcedWeatherId(); if (forcedWeatherId != null) { diff --git a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidInvasionPortalsSpawnSystem.java b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidInvasionPortalsSpawnSystem.java index 693e2b87..ee42c624 100644 --- a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidInvasionPortalsSpawnSystem.java +++ b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidInvasionPortalsSpawnSystem.java @@ -40,7 +40,10 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class VoidInvasionPortalsSpawnSystem extends DelayedEntitySystem { + @Nonnull + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); private static final int MAX_PORTALS = 24; + @Nullable private CompletableFuture findPortalSpawnPos; public VoidInvasionPortalsSpawnSystem() { @@ -55,20 +58,23 @@ public class VoidInvasionPortalsSpawnSystem extends DelayedEntitySystem store, @Nonnull CommandBuffer commandBuffer ) { - VoidEvent voidEvent = archetypeChunk.getComponent(index, VoidEvent.getComponentType()); + VoidEvent voidEventComponent = archetypeChunk.getComponent(index, VoidEvent.getComponentType()); + + assert voidEventComponent != null; + World world = store.getExternalData().getWorld(); if (this.findPortalSpawnPos == null) { - SpatialHashGrid> spawners = this.cleanupAndGetSpawners(voidEvent); + SpatialHashGrid> spawners = cleanupAndGetSpawners(voidEventComponent); if (spawners.size() < 24) { - this.findPortalSpawnPos = this.findPortalSpawnPosition(world, voidEvent, commandBuffer); + this.findPortalSpawnPos = findPortalSpawnPosition(world, voidEventComponent, commandBuffer); } } else if (this.findPortalSpawnPos.isDone()) { Vector3d portalPos; try { portalPos = this.findPortalSpawnPos.join(); this.findPortalSpawnPos = null; - } catch (Throwable var14) { - HytaleLogger.getLogger().at(Level.SEVERE).withCause(var14).log("Error trying to find a void event spawn position"); + } catch (Throwable var16) { + LOGGER.at(Level.SEVERE).withCause(var16).log("Error trying to find a void event spawn position"); return; } @@ -77,52 +83,75 @@ public class VoidInvasionPortalsSpawnSystem extends DelayedEntitySystem voidSpawner = commandBuffer.addEntity(voidSpawnerHolder, AddReason.SPAWN); - voidEvent.getVoidSpawners().add(portalPos, voidSpawner); - VoidEventConfig eventConfig = voidEvent.getConfig(world); + voidEventComponent.getVoidSpawners().add(portalPos, voidSpawner); + VoidEventConfig eventConfig = VoidEvent.getConfig(world); if (eventConfig == null) { - HytaleLogger.getLogger().at(Level.WARNING).log("There's a Void Event entity but no void event config in the gameplay config"); + LOGGER.at(Level.WARNING).log("There's a Void Event entity but no void event config in the gameplay config"); } else { InvasionPortalConfig invasionPortalConfig = eventConfig.getInvasionPortalConfig(); Vector3i portalBlockPos = portalPos.toVector3i(); - world.getChunkAsync(ChunkUtil.indexChunkFromBlock(portalBlockPos.x, portalBlockPos.z)).thenAcceptAsync(chunk -> { - BlockType blockType = invasionPortalConfig.getBlockType(); - chunk.setBlock(portalBlockPos.x, portalBlockPos.y, portalBlockPos.z, blockType, 4); - }, world); + long chunkIndex = ChunkUtil.indexChunkFromBlock(portalBlockPos.x, portalBlockPos.z); + world.getChunkAsync(chunkIndex) + .thenAcceptAsync( + chunk -> { + BlockType blockType = invasionPortalConfig.getBlockType(); + if (blockType == null) { + LOGGER.at(Level.WARNING) + .log( + "Failed to place invasion portal block at %s, %s, %s. Block type is not configured", + portalBlockPos.x, + portalBlockPos.y, + portalBlockPos.z + ); + } else { + chunk.setBlock(portalBlockPos.x, portalBlockPos.y, portalBlockPos.z, blockType, 4); + } + }, + world + ); } } } } - private CompletableFuture findPortalSpawnPosition(World world, VoidEvent voidEvent, CommandBuffer commandBuffer) { + @Nullable + private static CompletableFuture findPortalSpawnPosition( + @Nonnull World world, @Nonnull VoidEvent voidEvent, @Nonnull CommandBuffer commandBuffer + ) { PortalWorld portalWorld = commandBuffer.getResource(PortalWorld.getResourceType()); if (!portalWorld.exists()) { return null; } else { - Vector3d spawnPos = portalWorld.getSpawnPoint().getPosition(); - Transform playerTransform = this.findRandomPlayerTransform(world, commandBuffer); - if (playerTransform == null) { + Transform spawnPoint = portalWorld.getSpawnPoint(); + if (spawnPoint == null) { return null; } else { - Vector3d origin = playerTransform.getPosition().clone().add(0.0, 5.0, 0.0); - Vector3d direction = playerTransform.getDirection(); - SpatialHashGrid> existingSpawners = voidEvent.getVoidSpawners(); - NotNearAnyInHashGrid noNearbySpawners = new NotNearAnyInHashGrid(existingSpawners, 62.0); - return CompletableFuture.supplyAsync( - () -> new SearchCone(direction, 48.0, 64.0, 90.0, 8) - .filter(noNearbySpawners) - .filter(new NotNearPointXZ(spawnPos, 18.0)) - .then(new SearchBelow(12)) - .filter(new FitsAPortal()) - .execute(world, origin) - .orElse(null), - world - ); + Vector3d spawnPos = spawnPoint.getPosition(); + Transform playerTransform = findRandomPlayerTransform(world, commandBuffer); + if (playerTransform == null) { + return null; + } else { + Vector3d originPosition = playerTransform.getPosition().clone().add(0.0, 5.0, 0.0); + Vector3d direction = playerTransform.getDirection(); + SpatialHashGrid> existingSpawners = voidEvent.getVoidSpawners(); + NotNearAnyInHashGrid noNearbySpawners = new NotNearAnyInHashGrid(existingSpawners, 62.0); + return CompletableFuture.supplyAsync( + () -> new SearchCone(direction, 48.0, 64.0, 90.0, 8) + .filter(noNearbySpawners) + .filter(new NotNearPointXZ(spawnPos, 18.0)) + .then(new SearchBelow(12)) + .filter(new FitsAPortal()) + .execute(world, originPosition) + .orElse(null), + world + ); + } } } } @Nullable - private Transform findRandomPlayerTransform(World world, CommandBuffer commandBuffer) { + private static Transform findRandomPlayerTransform(@Nonnull World world, @Nonnull CommandBuffer commandBuffer) { Collection playerRefs = world.getPlayerRefs(); if (playerRefs.isEmpty()) { return null; @@ -142,7 +171,8 @@ public class VoidInvasionPortalsSpawnSystem extends DelayedEntitySystem> cleanupAndGetSpawners(VoidEvent voidEvent) { + @Nonnull + private static SpatialHashGrid> cleanupAndGetSpawners(@Nonnull VoidEvent voidEvent) { SpatialHashGrid> spawners = voidEvent.getVoidSpawners(); spawners.removeIf(ref -> !ref.isValid()); return spawners; diff --git a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidSpawnerSystems.java b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidSpawnerSystems.java index f06d10fa..dcfb660b 100644 --- a/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidSpawnerSystems.java +++ b/src/com/hypixel/hytale/builtin/portals/systems/voidevent/VoidSpawnerSystems.java @@ -30,6 +30,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public final class VoidSpawnerSystems { + @Nonnull private static final Query QUERY = Query.and(VoidSpawner.getComponentType(), TransformComponent.getComponentType()); public static class Instantiate extends RefSystem { diff --git a/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceActivePage.java b/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceActivePage.java index 933c3058..b74a9cb6 100644 --- a/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceActivePage.java +++ b/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceActivePage.java @@ -79,7 +79,8 @@ public class PortalDeviceActivePage extends InteractiveCustomUIPage ref, @Nonnull ComponentAccessor componentAccessor) { + @Nonnull + private PortalDeviceActivePage.State computeState(@Nonnull Ref ref, @Nonnull ComponentAccessor componentAccessor) { if (!this.blockRef.isValid()) { return PortalDeviceActivePage.Error.INVALID_BLOCK; } else { @@ -117,12 +119,13 @@ public class PortalDeviceActivePage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder( PortalDeviceActivePage.Data.class, PortalDeviceActivePage.Data::new ) diff --git a/src/com/hypixel/hytale/builtin/portals/ui/PortalDevicePageSupplier.java b/src/com/hypixel/hytale/builtin/portals/ui/PortalDevicePageSupplier.java index e24550b6..9e922d3b 100644 --- a/src/com/hypixel/hytale/builtin/portals/ui/PortalDevicePageSupplier.java +++ b/src/com/hypixel/hytale/builtin/portals/ui/PortalDevicePageSupplier.java @@ -23,9 +23,11 @@ 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.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PortalDevicePageSupplier implements OpenCustomUIInteraction.CustomPageSupplier { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PortalDevicePageSupplier.class, PortalDevicePageSupplier::new) .appendInherited( new KeyedCodec<>("Config", PortalDeviceConfig.CODEC), @@ -39,45 +41,57 @@ public class PortalDevicePageSupplier implements OpenCustomUIInteraction.CustomP private PortalDeviceConfig config; @Override - public CustomUIPage tryCreate(Ref ref, ComponentAccessor store, PlayerRef playerRef, InteractionContext context) { + public CustomUIPage tryCreate( + @Nonnull Ref ref, @Nonnull ComponentAccessor store, @Nonnull PlayerRef playerRef, @Nonnull InteractionContext context + ) { BlockPosition targetBlock = context.getTargetBlock(); if (targetBlock == null) { return null; } else { Player playerComponent = store.getComponent(ref, Player.getComponentType()); - - assert playerComponent != null; - - ItemStack inHand = playerComponent.getInventory().getItemInHand(); - World world = store.getExternalData().getWorld(); - BlockType blockType = world.getBlockType(targetBlock.x, targetBlock.y, targetBlock.z); - - for (String blockStateKey : this.config.getBlockStates()) { - BlockType blockState = BlockTypeUtils.getBlockForState(blockType, blockStateKey); - if (blockState == null) { - playerRef.sendMessage(Message.translation("server.portals.device.blockStateMisconfigured").param("state", blockStateKey)); - return null; - } - } - - BlockType onBlock = BlockTypeUtils.getBlockForState(blockType, this.config.getOnState()); - ChunkStore chunkStore = world.getChunkStore(); - Ref blockRef = BlockModule.getBlockEntity(world, targetBlock.x, targetBlock.y, targetBlock.z); - if (blockRef == null) { - playerRef.sendMessage(Message.translation("server.portals.device.blockEntityMisconfigured")); + if (playerComponent == null) { return null; } else { - PortalDevice existingDevice = chunkStore.getStore().getComponent(blockRef, PortalDevice.getComponentType()); - World destinationWorld = existingDevice == null ? null : existingDevice.getDestinationWorld(); - if (existingDevice != null && blockType == onBlock && !isPortalWorldValid(destinationWorld)) { - world.setBlockInteractionState(new Vector3i(targetBlock.x, targetBlock.y, targetBlock.z), blockType, this.config.getOffState()); - playerRef.sendMessage(Message.translation("server.portals.device.adjusted").color("#ff0000")); + ItemStack inHand = playerComponent.getInventory().getItemInHand(); + World world = store.getExternalData().getWorld(); + BlockType blockType = world.getBlockType(targetBlock.x, targetBlock.y, targetBlock.z); + if (blockType == null) { + playerRef.sendMessage( + Message.translation("server.portals.device.blockTypeMisconfigured") + .param("x", targetBlock.x) + .param("y", targetBlock.y) + .param("z", targetBlock.z) + ); return null; - } else if (existingDevice != null && destinationWorld != null) { - return new PortalDeviceActivePage(playerRef, this.config, blockRef); } else { - chunkStore.getStore().putComponent(blockRef, PortalDevice.getComponentType(), new PortalDevice(this.config, blockType.getId())); - return new PortalDeviceSummonPage(playerRef, this.config, blockRef, inHand); + for (String blockStateKey : this.config.getBlockStates()) { + BlockType blockState = BlockTypeUtils.getBlockForState(blockType, blockStateKey); + if (blockState == null) { + playerRef.sendMessage(Message.translation("server.portals.device.blockStateMisconfigured").param("state", blockStateKey)); + return null; + } + } + + BlockType onBlockType = BlockTypeUtils.getBlockForState(blockType, this.config.getOnState()); + ChunkStore chunkStore = world.getChunkStore(); + Ref blockRef = BlockModule.getBlockEntity(world, targetBlock.x, targetBlock.y, targetBlock.z); + if (blockRef == null) { + playerRef.sendMessage(Message.translation("server.portals.device.blockEntityMisconfigured")); + return null; + } else { + PortalDevice existingDevice = chunkStore.getStore().getComponent(blockRef, PortalDevice.getComponentType()); + World destinationWorld = existingDevice == null ? null : existingDevice.getDestinationWorld(); + if (existingDevice != null && blockType == onBlockType && !isPortalWorldValid(destinationWorld)) { + world.setBlockInteractionState(new Vector3i(targetBlock.x, targetBlock.y, targetBlock.z), blockType, this.config.getOffState()); + playerRef.sendMessage(Message.translation("server.portals.device.adjusted").color("#ff0000")); + return null; + } else if (existingDevice != null && destinationWorld != null) { + return new PortalDeviceActivePage(playerRef, this.config, blockRef); + } else { + chunkStore.getStore().putComponent(blockRef, PortalDevice.getComponentType(), new PortalDevice(this.config, blockType.getId())); + return new PortalDeviceSummonPage(playerRef, this.config, blockRef, inHand); + } + } } } } diff --git a/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceSummonPage.java b/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceSummonPage.java index cf06ab48..ef655d46 100644 --- a/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceSummonPage.java +++ b/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceSummonPage.java @@ -63,10 +63,12 @@ import javax.annotation.Nullable; public class PortalDeviceSummonPage extends InteractiveCustomUIPage { private final PortalDeviceConfig config; private final Ref blockRef; + @Nullable private final ItemStack offeredItemStack; + @Nonnull private static final Transform DEFAULT_WORLDGEN_SPAWN = new Transform(0.0, 140.0, 0.0); - public PortalDeviceSummonPage(@Nonnull PlayerRef playerRef, PortalDeviceConfig config, Ref blockRef, ItemStack offeredItemStack) { + public PortalDeviceSummonPage(@Nonnull PlayerRef playerRef, PortalDeviceConfig config, Ref blockRef, @Nullable ItemStack offeredItemStack) { super(playerRef, CustomPageLifetime.CanDismissOrCloseThroughInteraction, PortalDeviceSummonPage.Data.CODEC); this.config = config; this.blockRef = blockRef; @@ -146,7 +148,7 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage pills = portalType.getDescription().getPillTags(); for (int i = 0; i < pills.size(); i++) { @@ -158,7 +160,7 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage spawnReturnPortal(World world, PortalWorld portalWorld, UUID sampleUuid, String portalBlockType) { + @Nonnull + private static CompletableFuture spawnReturnPortal( + @Nonnull World world, @Nonnull PortalWorld portalWorld, @Nonnull UUID sampleUuid, @Nonnull String portalBlockType + ) { PortalSpawn portalSpawn = portalWorld.getPortalType().getPortalSpawn(); return getSpawnTransform(world, sampleUuid, portalSpawn) .thenCompose( @@ -306,7 +313,8 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage getSpawnTransform(World world, UUID sampleUuid, @Nullable PortalSpawn portalSpawn) { + @Nonnull + private static CompletableFuture getSpawnTransform(@Nonnull World world, @Nonnull UUID sampleUuid, @Nullable PortalSpawn portalSpawn) { ISpawnProvider spawnProvider = world.getWorldConfig().getSpawnProvider(); if (spawnProvider == null) { return CompletableFuture.completedFuture(null); @@ -325,6 +333,7 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage componentAccessor) { if (!this.blockRef.isValid()) { return PortalDeviceSummonPage.Error.INVALID_BLOCK; @@ -338,7 +347,9 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage chunkRef = blockStateInfo.getChunkRef(); - if (chunkRef != null && chunkRef.isValid()) { + if (!chunkRef.isValid()) { + return PortalDeviceSummonPage.Error.INVALID_BLOCK; + } else { WorldChunk worldChunk = chunkStore.getComponent(chunkRef, WorldChunk.getComponentType()); if (worldChunk == null) { return PortalDeviceSummonPage.Error.INVALID_BLOCK; @@ -390,8 +401,6 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder( PortalDeviceSummonPage.Data.class, PortalDeviceSummonPage.Data::new ) diff --git a/src/com/hypixel/hytale/builtin/portals/ui/PortalSpawnFinder.java b/src/com/hypixel/hytale/builtin/portals/ui/PortalSpawnFinder.java index eb6cea8f..3c5e8496 100644 --- a/src/com/hypixel/hytale/builtin/portals/ui/PortalSpawnFinder.java +++ b/src/com/hypixel/hytale/builtin/portals/ui/PortalSpawnFinder.java @@ -28,7 +28,7 @@ import javax.annotation.Nullable; public final class PortalSpawnFinder { @Nullable - public static Transform computeSpawnTransform(World world, PortalSpawn config) { + public static Transform computeSpawnTransform(@Nonnull World world, @Nonnull PortalSpawn config) { Vector3d spawn = findSpawnByThrowingDarts(world, config); if (spawn == null) { spawn = findFallbackPositionOnGround(world, config); @@ -47,7 +47,7 @@ public final class PortalSpawnFinder { } @Nullable - private static Vector3d findSpawnByThrowingDarts(World world, PortalSpawn config) { + private static Vector3d findSpawnByThrowingDarts(@Nonnull World world, @Nonnull PortalSpawn config) { Vector3d center = config.getCenter().toVector3d(); center.setY(config.getCheckSpawnY()); int halfwayThrows = config.getChunkDartThrows() / 2; @@ -76,14 +76,14 @@ public final class PortalSpawnFinder { } @Nullable - private static Vector3d findGroundWithinChunk(WorldChunk chunk, PortalSpawn config, boolean checkIfPortalFitsNice) { + private static Vector3d findGroundWithinChunk(@Nonnull WorldChunk chunk, @Nonnull PortalSpawn config, boolean checkIfPortalFitsNice) { int chunkBlockX = ChunkUtil.minBlock(chunk.getX()); int chunkBlockZ = ChunkUtil.minBlock(chunk.getZ()); - ThreadLocalRandom rand = ThreadLocalRandom.current(); + ThreadLocalRandom random = ThreadLocalRandom.current(); for (int i = 0; i < config.getChecksPerChunk(); i++) { - int x = chunkBlockX + rand.nextInt(2, 14); - int z = chunkBlockZ + rand.nextInt(2, 14); + int x = chunkBlockX + random.nextInt(2, 14); + int z = chunkBlockZ + random.nextInt(2, 14); Vector3d point = findWithGroundBelow(chunk, x, config.getCheckSpawnY(), z, config.getScanHeight(), false); if (point != null && (!checkIfPortalFitsNice || FitsAPortal.check(chunk.getWorld(), point))) { return point; @@ -94,30 +94,42 @@ public final class PortalSpawnFinder { } @Nullable - private static Vector3d findWithGroundBelow(WorldChunk chunk, int x, int y, int z, int scanHeight, boolean fluidsAreAcceptable) { + private static Vector3d findWithGroundBelow(@Nonnull WorldChunk chunk, int x, int y, int z, int scanHeight, boolean fluidsAreAcceptable) { World world = chunk.getWorld(); ChunkStore chunkStore = world.getChunkStore(); Ref chunkRef = chunk.getReference(); - Store chunkStoreAccessor = chunkStore.getStore(); - ChunkColumn chunkColumnComponent = chunkStoreAccessor.getComponent(chunkRef, ChunkColumn.getComponentType()); - BlockChunk blockChunkComponent = chunkStoreAccessor.getComponent(chunkRef, BlockChunk.getComponentType()); + if (chunkRef != null && chunkRef.isValid()) { + Store chunkStoreAccessor = chunkStore.getStore(); + ChunkColumn chunkColumnComponent = chunkStoreAccessor.getComponent(chunkRef, ChunkColumn.getComponentType()); + if (chunkColumnComponent == null) { + return null; + } else { + BlockChunk blockChunkComponent = chunkStoreAccessor.getComponent(chunkRef, BlockChunk.getComponentType()); + if (blockChunkComponent == null) { + return null; + } else { + for (int dy = 0; dy < scanHeight; dy++) { + PortalSpawnFinder.Material selfMat = getMaterial(chunkStoreAccessor, chunkColumnComponent, blockChunkComponent, x, y - dy, z); + PortalSpawnFinder.Material belowMat = getMaterial(chunkStoreAccessor, chunkColumnComponent, blockChunkComponent, x, y - dy - 1, z); + boolean selfValid = selfMat == PortalSpawnFinder.Material.AIR || fluidsAreAcceptable && selfMat == PortalSpawnFinder.Material.FLUID; + if (!selfValid) { + break; + } - for (int dy = 0; dy < scanHeight; dy++) { - PortalSpawnFinder.Material selfMat = getMaterial(chunkStoreAccessor, chunkColumnComponent, blockChunkComponent, x, y - dy, z); - PortalSpawnFinder.Material belowMat = getMaterial(chunkStoreAccessor, chunkColumnComponent, blockChunkComponent, x, y - dy - 1, z); - boolean selfValid = selfMat == PortalSpawnFinder.Material.AIR || fluidsAreAcceptable && selfMat == PortalSpawnFinder.Material.FLUID; - if (!selfValid) { - break; - } + if (belowMat == PortalSpawnFinder.Material.SOLID) { + return new Vector3d(x, y - dy, z); + } + } - if (belowMat == PortalSpawnFinder.Material.SOLID) { - return new Vector3d(x, y - dy, z); + return null; + } } + } else { + return null; } - - return null; } + @Nonnull private static PortalSpawnFinder.Material getMaterial( @Nonnull ComponentAccessor chunkStore, @Nonnull ChunkColumn chunkColumnComponent, @@ -148,10 +160,11 @@ public final class PortalSpawnFinder { } @Nullable - private static Vector3d findFallbackPositionOnGround(World world, PortalSpawn config) { + private static Vector3d findFallbackPositionOnGround(@Nonnull World world, @Nonnull PortalSpawn config) { Vector3i center = config.getCenter(); - WorldChunk centerChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(center.x, center.z)); - return findWithGroundBelow(centerChunk, 0, 319, 0, 319, true); + long chunkIndex = ChunkUtil.indexChunkFromBlock(center.x, center.z); + WorldChunk centerChunk = world.getChunk(chunkIndex); + return centerChunk == null ? null : findWithGroundBelow(centerChunk, 0, 319, 0, 319, true); } private static enum Material { diff --git a/src/com/hypixel/hytale/builtin/portals/utils/BlockTypeUtils.java b/src/com/hypixel/hytale/builtin/portals/utils/BlockTypeUtils.java index 5e2a5b75..8465c369 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/BlockTypeUtils.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/BlockTypeUtils.java @@ -1,14 +1,18 @@ package com.hypixel.hytale.builtin.portals.utils; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class BlockTypeUtils { - private BlockTypeUtils() { - } - - public static BlockType getBlockForState(BlockType blockType, String state) { + @Nullable + public static BlockType getBlockForState(@Nonnull BlockType blockType, @Nonnull String state) { String baseKey = blockType.getDefaultStateKey(); BlockType baseBlock = baseKey == null ? blockType : BlockType.getAssetMap().getAsset(baseKey); - return "default".equals(state) ? baseBlock : baseBlock.getBlockForState(state); + if ("default".equals(state)) { + return baseBlock; + } else { + return baseBlock != null ? baseBlock.getBlockForState(state) : null; + } } } diff --git a/src/com/hypixel/hytale/builtin/portals/utils/CursedItems.java b/src/com/hypixel/hytale/builtin/portals/utils/CursedItems.java index 1f673351..16112f7f 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/CursedItems.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/CursedItems.java @@ -5,12 +5,13 @@ import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.inventory.container.ItemContainer; import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.Nonnull; public final class CursedItems { private CursedItems() { } - public static boolean uncurseAll(ItemContainer itemContainer) { + public static boolean uncurseAll(@Nonnull ItemContainer itemContainer) { AtomicBoolean uncursedAny = new AtomicBoolean(false); itemContainer.replaceAll((slot, existing) -> { AdventureMetadata adventureMeta = existing.getFromMetadataOrNull("Adventure", AdventureMetadata.CODEC); @@ -27,11 +28,11 @@ public final class CursedItems { return uncursedAny.get(); } - public static void deleteAll(Player player) { + public static void deleteAll(@Nonnull Player player) { deleteAll(player.getInventory().getCombinedEverything()); } - public static void deleteAll(ItemContainer itemContainer) { + public static void deleteAll(@Nonnull ItemContainer itemContainer) { itemContainer.replaceAll((slot, existing) -> { AdventureMetadata adventureMeta = existing.getFromMetadataOrNull(AdventureMetadata.KEYED_CODEC); boolean cursed = adventureMeta != null && adventureMeta.isCursed(); diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/PositionPredicate.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/PositionPredicate.java index 4fc5d4b2..6e7520c7 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/PositionPredicate.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/PositionPredicate.java @@ -2,7 +2,8 @@ package com.hypixel.hytale.builtin.portals.utils.posqueries; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; +import javax.annotation.Nonnull; public interface PositionPredicate { - boolean test(World var1, Vector3d var2); + boolean test(@Nonnull World var1, @Nonnull Vector3d var2); } diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/SpatialQuery.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/SpatialQuery.java index 1b4de6bf..58258f15 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/SpatialQuery.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/SpatialQuery.java @@ -8,28 +8,34 @@ import com.hypixel.hytale.server.core.universe.world.World; import java.util.Optional; import java.util.logging.Level; import java.util.stream.Stream; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public interface SpatialQuery { - Stream createCandidates(World var1, Vector3d var2, @Nullable SpatialQueryDebug var3); + @Nonnull + Stream createCandidates(@Nonnull World var1, @Nonnull Vector3d var2, @Nullable SpatialQueryDebug var3); - default SpatialQuery then(SpatialQuery expand) { + @Nonnull + default SpatialQuery then(@Nonnull SpatialQuery expand) { return new FlatMapQuery(this, expand); } - default SpatialQuery filter(PositionPredicate predicate) { + @Nonnull + default SpatialQuery filter(@Nonnull PositionPredicate predicate) { return new FilterQuery(this, predicate); } - default Optional execute(World world, Vector3d origin) { + @Nonnull + default Optional execute(@Nonnull World world, @Nonnull Vector3d origin) { return this.createCandidates(world, origin, null).findFirst(); } - default Optional debug(World world, Vector3d origin) { + @Nonnull + default Optional debug(@Nonnull World world, @Nonnull Vector3d origin) { try { SpatialQueryDebug debug = new SpatialQueryDebug(); Optional output = this.createCandidates(world, origin, debug).findFirst(); - debug.appendLine("-> OUTPUT: " + output.map(debug::fmt).orElse("")); + debug.appendLine("-> OUTPUT: " + output.map(SpatialQueryDebug::fmt).orElse("")); HytaleLogger.getLogger().at(Level.INFO).log(debug.toString()); return output; } catch (Throwable var5) { diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/SpatialQueryDebug.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/SpatialQueryDebug.java index 46b6a651..2980c35d 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/SpatialQueryDebug.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/SpatialQueryDebug.java @@ -4,28 +4,35 @@ import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.vector.Vector3d; import java.util.Stack; import java.util.logging.Level; +import javax.annotation.Nonnull; public class SpatialQueryDebug { + @Nonnull private final StringBuilder builder = new StringBuilder(); + @Nonnull private String indent = ""; - private Stack scope = new Stack<>(); + @Nonnull + private final Stack scope = new Stack<>(); public SpatialQueryDebug() { this.appendLine("SPATIAL QUERY DEBUG"); } - public SpatialQueryDebug appendLine(String string) { + @Nonnull + public SpatialQueryDebug appendLine(@Nonnull String string) { HytaleLogger.getLogger().at(Level.INFO).log(this.indent + "| " + string); return this; } - public SpatialQueryDebug indent(String scopeReason) { + @Nonnull + public SpatialQueryDebug indent(@Nonnull String scopeReason) { HytaleLogger.getLogger().at(Level.INFO).log(this.indent + "⮑ " + scopeReason); this.indent = this.indent + " "; this.scope.add(scopeReason); return this; } + @Nonnull public SpatialQueryDebug unindent() { if (this.indent.length() >= 2) { this.indent = this.indent.substring(0, this.indent.length() - 2); @@ -39,10 +46,12 @@ public class SpatialQueryDebug { return this; } - public String fmt(Vector3d point) { + @Nonnull + public static String fmt(@Nonnull Vector3d point) { return "(" + String.format("%.1f", point.x) + ", " + String.format("%.1f", point.y) + ", " + String.format("%.1f", point.z) + ")"; } + @Nonnull @Override public String toString() { return this.builder.toString(); diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchBelow.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchBelow.java index a09705e8..1bef7e0a 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchBelow.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchBelow.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; import java.util.stream.IntStream; import java.util.stream.Stream; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SearchBelow implements SpatialQuery { @@ -15,10 +16,11 @@ public class SearchBelow implements SpatialQuery { this.height = height; } + @Nonnull @Override - public Stream createCandidates(World world, Vector3d origin, @Nullable SpatialQueryDebug debug) { + public Stream createCandidates(@Nonnull World world, @Nonnull Vector3d origin, @Nullable SpatialQueryDebug debug) { if (debug != null) { - debug.appendLine("Searching up to " + this.height + " blocks below " + debug.fmt(origin) + ":"); + debug.appendLine("Searching up to " + this.height + " blocks below " + SpatialQueryDebug.fmt(origin) + ":"); } return IntStream.rangeClosed(0, this.height).mapToObj(dy -> origin.clone().add(0.0, -dy, 0.0)); diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchCircular.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchCircular.java index d48a717c..1d0b7882 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchCircular.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchCircular.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Stream; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SearchCircular implements SpatialQuery { @@ -23,13 +24,14 @@ public class SearchCircular implements SpatialQuery { this.attempts = attempts; } + @Nonnull @Override - public Stream createCandidates(World world, Vector3d origin, @Nullable SpatialQueryDebug debug) { + public Stream createCandidates(@Nonnull World world, @Nonnull Vector3d origin, @Nullable SpatialQueryDebug debug) { if (debug != null) { String radiusFmt = this.minRadius == this.maxRadius ? String.format("%.1f", this.minRadius) : String.format("%.1f", this.minRadius) + "-" + String.format("%.1f", this.maxRadius); - debug.appendLine("Searching in a " + radiusFmt + " radius circle around " + debug.fmt(origin) + ":"); + debug.appendLine("Searching in a " + radiusFmt + " radius circle around " + SpatialQueryDebug.fmt(origin) + ":"); } return Stream.generate(() -> { diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchCone.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchCone.java index de873c6d..96616090 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchCone.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/generators/SearchCone.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Stream; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SearchCone implements SpatialQuery { @@ -27,8 +28,9 @@ public class SearchCone implements SpatialQuery { this.attempts = attempts; } + @Nonnull @Override - public Stream createCandidates(World world, Vector3d origin, @Nullable SpatialQueryDebug debug) { + public Stream createCandidates(@Nonnull World world, @Nonnull Vector3d origin, @Nullable SpatialQueryDebug debug) { if (debug != null) { String radiusFmt = this.minRadius == this.maxRadius ? String.format("%.1f", this.minRadius) @@ -39,18 +41,18 @@ public class SearchCone implements SpatialQuery { + " radius cone (max " + String.format("%.1f", this.maxDegrees) + "°) in direction " - + debug.fmt(this.direction) + + SpatialQueryDebug.fmt(this.direction) + " from " - + debug.fmt(origin) + + SpatialQueryDebug.fmt(origin) + ":" ); } double maxRadians = Math.toRadians(this.maxDegrees); return Stream.generate(() -> { - ThreadLocalRandom rand = ThreadLocalRandom.current(); - double distance = this.minRadius + rand.nextDouble() * (this.maxRadius - this.minRadius); - double yawOffset = (rand.nextDouble() - 0.5) * maxRadians; + ThreadLocalRandom random = ThreadLocalRandom.current(); + double distance = this.minRadius + random.nextDouble() * (this.maxRadius - this.minRadius); + double yawOffset = (random.nextDouble() - 0.5) * maxRadians; Vector3d dir = this.direction.clone().rotateY((float)yawOffset).setLength(distance); return dir.add(origin); }).limit(this.attempts); diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/FitsAPortal.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/FitsAPortal.java index eaa86d5e..3fc1ab72 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/FitsAPortal.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/FitsAPortal.java @@ -15,34 +15,53 @@ 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.storage.ChunkStore; +import javax.annotation.Nonnull; public class FitsAPortal implements PositionPredicate { + @Nonnull private static final int[] THREES = new int[]{-1, 0, 1}; @Override - public boolean test(World world, Vector3d point) { + public boolean test(@Nonnull World world, @Nonnull Vector3d point) { return check(world, point); } - public static boolean check(World world, Vector3d point) { + public static boolean check(@Nonnull World world, @Nonnull Vector3d point) { ChunkStore chunkStore = world.getChunkStore(); for (int x : THREES) { for (int z : THREES) { for (int y = -1; y <= 3; y++) { Vector3i rel = point.toVector3i().add(x, y, z); - WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(rel.x, rel.z)); + long chunkIndex = ChunkUtil.indexChunkFromBlock(rel.x, rel.z); + WorldChunk chunk = world.getChunk(chunkIndex); + if (chunk == null) { + return false; + } + Ref chunkRef = chunk.getReference(); + if (chunkRef == null || !chunkRef.isValid()) { + return false; + } + Store chunkStoreAccessor = chunkStore.getStore(); ChunkColumn chunkColumnComponent = chunkStoreAccessor.getComponent(chunkRef, ChunkColumn.getComponentType()); + if (chunkColumnComponent == null) { + return false; + } + BlockChunk blockChunkComponent = chunkStoreAccessor.getComponent(chunkRef, BlockChunk.getComponentType()); + if (blockChunkComponent == null) { + return false; + } + int fluidId = WorldUtil.getFluidIdAtPosition(chunkStoreAccessor, chunkColumnComponent, rel.x, rel.y, rel.z); if (fluidId != 0) { return false; } - BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(rel.y); - int blockId = blockSection.get(rel.x, rel.y, rel.z); + BlockSection blockSectionComponent = blockChunkComponent.getSectionAtBlockY(rel.y); + int blockId = blockSectionComponent.get(rel.x, rel.y, rel.z); BlockType blockType = BlockType.getAssetMap().getAsset(blockId); if (blockType == null) { return false; diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearAnyInHashGrid.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearAnyInHashGrid.java index b084645e..baea9e93 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearAnyInHashGrid.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearAnyInHashGrid.java @@ -4,10 +4,11 @@ import com.hypixel.hytale.builtin.portals.utils.posqueries.PositionPredicate; import com.hypixel.hytale.builtin.portals.utils.spatial.SpatialHashGrid; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; +import javax.annotation.Nonnull; public record NotNearAnyInHashGrid(SpatialHashGrid hashGrid, double radius) implements PositionPredicate { @Override - public boolean test(World world, Vector3d point) { + public boolean test(@Nonnull World world, @Nonnull Vector3d point) { return !this.hashGrid.hasAnyWithin(point, this.radius); } } diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearPoint.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearPoint.java index e53700c0..0c181326 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearPoint.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearPoint.java @@ -3,18 +3,20 @@ package com.hypixel.hytale.builtin.portals.utils.posqueries.predicates; import com.hypixel.hytale.builtin.portals.utils.posqueries.PositionPredicate; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; +import javax.annotation.Nonnull; public final class NotNearPoint implements PositionPredicate { + @Nonnull private final Vector3d point; private final double radiusSq; - public NotNearPoint(Vector3d point, double radius) { + public NotNearPoint(@Nonnull Vector3d point, double radius) { this.point = point; this.radiusSq = radius * radius; } @Override - public boolean test(World world, Vector3d origin) { + public boolean test(@Nonnull World world, @Nonnull Vector3d origin) { return origin.distanceSquaredTo(this.point) >= this.radiusSq; } } diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearPointXZ.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearPointXZ.java index 9f474ba1..b8886752 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearPointXZ.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/NotNearPointXZ.java @@ -3,6 +3,7 @@ package com.hypixel.hytale.builtin.portals.utils.posqueries.predicates; import com.hypixel.hytale.builtin.portals.utils.posqueries.PositionPredicate; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; +import javax.annotation.Nonnull; public final class NotNearPointXZ implements PositionPredicate { private final Vector3d point; @@ -14,7 +15,7 @@ public final class NotNearPointXZ implements PositionPredicate { } @Override - public boolean test(World world, Vector3d origin) { + public boolean test(@Nonnull World world, @Nonnull Vector3d origin) { Vector3d pointAtHeight = this.point.clone(); pointAtHeight.y = origin.y; return origin.distanceSquaredTo(pointAtHeight) >= this.radiusSq; diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/generic/FilterQuery.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/generic/FilterQuery.java index 62216a5d..3050b7f6 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/generic/FilterQuery.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/generic/FilterQuery.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class FilterQuery implements SpatialQuery { @@ -24,8 +25,9 @@ public class FilterQuery implements SpatialQuery { this.failFast = failFast; } + @Nonnull @Override - public Stream createCandidates(World world, Vector3d origin, @Nullable SpatialQueryDebug debug) { + public Stream createCandidates(@Nonnull World world, @Nonnull Vector3d origin, @Nullable SpatialQueryDebug debug) { Stream stream = this.query.createCandidates(world, origin, debug); AtomicBoolean failed = new AtomicBoolean(); if (this.failFast) { @@ -35,7 +37,7 @@ public class FilterQuery implements SpatialQuery { return stream.filter(candidate -> { boolean accepted = this.predicate.test(world, candidate); if (debug != null) { - debug.appendLine(this.predicate.getClass().getSimpleName() + " on " + debug.fmt(candidate) + " = " + accepted); + debug.appendLine(this.predicate.getClass().getSimpleName() + " on " + SpatialQueryDebug.fmt(candidate) + " = " + accepted); } if (!accepted) { diff --git a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/generic/FlatMapQuery.java b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/generic/FlatMapQuery.java index 309ed1a3..b608edf8 100644 --- a/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/generic/FlatMapQuery.java +++ b/src/com/hypixel/hytale/builtin/portals/utils/posqueries/predicates/generic/FlatMapQuery.java @@ -5,23 +5,27 @@ import com.hypixel.hytale.builtin.portals.utils.posqueries.SpatialQueryDebug; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.universe.world.World; import java.util.stream.Stream; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class FlatMapQuery implements SpatialQuery { + @Nonnull private final SpatialQuery generator; + @Nonnull private final SpatialQuery expand; - public FlatMapQuery(SpatialQuery generator, SpatialQuery expand) { + public FlatMapQuery(@Nonnull SpatialQuery generator, @Nonnull SpatialQuery expand) { this.generator = generator; this.expand = expand; } + @Nonnull @Override - public Stream createCandidates(World world, Vector3d origin, @Nullable SpatialQueryDebug debug) { + public Stream createCandidates(@Nonnull World world, @Nonnull Vector3d origin, @Nullable SpatialQueryDebug debug) { return this.generator.createCandidates(world, origin, debug).flatMap(candidate -> { Stream candidates = this.expand.createCandidates(world, candidate, debug); if (debug != null) { - debug.indent("Flat-map expand from " + debug.fmt(candidate) + ":"); + debug.indent("Flat-map expand from " + SpatialQueryDebug.fmt(candidate) + ":"); return Stream.concat(candidates, Stream.of((Vector3d)null).peek(x -> debug.unindent()).flatMap(x -> Stream.empty())); } else { return candidates; diff --git a/src/com/hypixel/hytale/builtin/teleport/TeleportPlugin.java b/src/com/hypixel/hytale/builtin/teleport/TeleportPlugin.java index 4af949af..11350cf0 100644 --- a/src/com/hypixel/hytale/builtin/teleport/TeleportPlugin.java +++ b/src/com/hypixel/hytale/builtin/teleport/TeleportPlugin.java @@ -21,6 +21,7 @@ import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig; import com.hypixel.hytale.server.core.asset.type.model.config.Model; import com.hypixel.hytale.server.core.asset.type.model.config.ModelAsset; import com.hypixel.hytale.server.core.command.system.CommandRegistry; +import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.nameplate.Nameplate; import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox; import com.hypixel.hytale.server.core.modules.entity.component.HiddenFromAdventurePlayers; @@ -39,9 +40,9 @@ import com.hypixel.hytale.server.core.universe.world.events.AllWorldsLoadedEvent import com.hypixel.hytale.server.core.universe.world.events.ChunkPreLoadProcessEvent; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import com.hypixel.hytale.server.core.util.BsonUtil; -import com.hypixel.hytale.server.core.util.PositionUtil; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -249,24 +250,17 @@ public class TeleportPlugin extends JavaPlugin { public static final TeleportPlugin.WarpMarkerProvider INSTANCE = new TeleportPlugin.WarpMarkerProvider(); @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { Map warps = TeleportPlugin.get().getWarps(); if (!warps.isEmpty()) { GameplayConfig gameplayConfig = world.getGameplayConfig(); if (gameplayConfig.getWorldMapConfig().isDisplayWarps()) { for (Warp warp : warps.values()) { if (warp.getWorld().equals(world.getName())) { - tracker.trySendMarker( - chunkViewRadius, - playerChunkX, - playerChunkZ, - warp.getTransform().getPosition(), - warp.getTransform().getRotation().getYaw(), - "Warp-" + warp.getId(), - "Warp: " + warp.getId(), - warp, - (id, name, w) -> new MapMarker(id, name, "Warp.png", PositionUtil.toTransformPacket(w.getTransform()), null) - ); + MapMarker marker = new MapMarkerBuilder("Warp-" + warp.getId(), "Warp.png", warp.getTransform()) + .withCustomName("Warp: " + warp.getId()) + .build(); + collector.add(marker); } } } diff --git a/src/com/hypixel/hytale/builtin/worldgen/FeatureFlags.java b/src/com/hypixel/hytale/builtin/worldgen/FeatureFlags.java new file mode 100644 index 00000000..9062c106 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/worldgen/FeatureFlags.java @@ -0,0 +1,19 @@ +package com.hypixel.hytale.builtin.worldgen; + +import com.hypixel.hytale.server.worldgen.util.LogUtil; +import java.util.logging.Level; +import javax.annotation.Nonnull; + +public interface FeatureFlags { + @Deprecated(since = "2026-01-19", forRemoval = true) + boolean VERSION_OVERRIDES = of("hytale.worldgen.version_overrides"); + + static boolean of(@Nonnull String featureFlag) { + if (System.getProperty(featureFlag) == null && System.getenv(featureFlag) == null) { + return false; + } else { + LogUtil.getLogger().at(Level.INFO).log("Feature %s is enabled.", featureFlag); + return true; + } + } +} diff --git a/src/com/hypixel/hytale/builtin/worldgen/WorldGenPlugin.java b/src/com/hypixel/hytale/builtin/worldgen/WorldGenPlugin.java index 956507f3..26c79fe8 100644 --- a/src/com/hypixel/hytale/builtin/worldgen/WorldGenPlugin.java +++ b/src/com/hypixel/hytale/builtin/worldgen/WorldGenPlugin.java @@ -1,15 +1,43 @@ package com.hypixel.hytale.builtin.worldgen; +import com.hypixel.hytale.codec.ExtraInfo; import com.hypixel.hytale.codec.lookup.Priority; +import com.hypixel.hytale.codec.util.RawJsonReader; +import com.hypixel.hytale.common.plugin.PluginManifest; +import com.hypixel.hytale.common.semver.Semver; +import com.hypixel.hytale.procedurallib.file.FileIO; +import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; +import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.world.worldgen.provider.IWorldGenProvider; import com.hypixel.hytale.server.worldgen.BiomeDataSystem; import com.hypixel.hytale.server.worldgen.HytaleWorldGenProvider; +import com.hypixel.hytale.server.worldgen.util.LogUtil; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectLists; +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.logging.Level; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class WorldGenPlugin extends JavaPlugin { + private static final String VERSIONS_DIR_NAME = "$Versions"; + private static final String MANIFEST_FILENAME = "manifest.json"; private static WorldGenPlugin instance; + private final Object lock = new Object(); + private final Map versions = new Object2ObjectOpenHashMap<>(); public static WorldGenPlugin get() { return instance; @@ -24,5 +52,169 @@ public class WorldGenPlugin extends JavaPlugin { instance = this; this.getEntityStoreRegistry().registerSystem(new BiomeDataSystem()); IWorldGenProvider.CODEC.register(Priority.DEFAULT.before(1), "Hytale", HytaleWorldGenProvider.class, HytaleWorldGenProvider.CODEC); + FileIO.setDefaultRoot(AssetModule.get().getBaseAssetPack().getRoot()); + if (FeatureFlags.VERSION_OVERRIDES) { + AssetModule assets = AssetModule.get(); + List packs = loadVersionPacks(assets); + Object2ObjectOpenHashMap versions = new Object2ObjectOpenHashMap<>(); + + for (WorldGenPlugin.Version version : packs) { + validateVersion(version, packs); + assets.registerPack(version.getPackName(), version.path, version.manifest); + Semver latest = versions.get(version.name); + if (latest == null || version.manifest.getVersion().compareTo(latest) > 0) { + versions.put(version.name, version.manifest.getVersion()); + } + } + + synchronized (this.lock) { + this.versions.clear(); + this.versions.putAll(versions); + } + } + } + + public Semver getLatestVersion(@Nonnull String name, @Nonnull Semver minVersion) { + synchronized (this.lock) { + return this.versions.getOrDefault(name, minVersion); + } + } + + private static List loadVersionPacks(@Nonnull AssetModule assets) { + Path versionsDir = getVersionsPath(); + if (!Files.exists(versionsDir)) { + return ObjectLists.emptyList(); + } else { + Path root = assets.getBaseAssetPack().getRoot(); + Path assetPath = root.relativize(Universe.getWorldGenPath()); + + try { + ObjectArrayList var14; + try (DirectoryStream stream = Files.newDirectoryStream(versionsDir)) { + ObjectArrayList list = new ObjectArrayList<>(); + + for (Path path : stream) { + if (Files.isDirectory(path)) { + String name = getWorldConfigName(path, assetPath); + if (name != null) { + Path manifestPath = path.resolve("manifest.json"); + if (Files.exists(manifestPath)) { + PluginManifest manifest = loadManifest(manifestPath); + if (manifest != null) { + list.add(new WorldGenPlugin.Version(name, path, manifest)); + } + } + } + } + } + + Collections.sort(list); + var14 = list; + } + + return var14; + } catch (IOException var13) { + throw new RuntimeException(var13); + } + } + } + + private static void validateVersion(@Nonnull WorldGenPlugin.Version version, @Nonnull List versions) { + if (version.manifest.getVersion().compareTo(HytaleWorldGenProvider.MIN_VERSION) <= 0) { + throw new IllegalArgumentException( + String.format( + "Invalid $Version AssetPack: %s. Pack version number: %s must be greater than: %s", + version.path(), + version.manifest.getVersion(), + HytaleWorldGenProvider.MIN_VERSION + ) + ); + } else { + for (WorldGenPlugin.Version other : versions) { + if (other != version && version.name().equals(other.name()) && version.manifest.getVersion().equals(other.manifest.getVersion())) { + throw new IllegalArgumentException( + String.format( + "$Version AssetPack: %s conflicts with pack: %s. Pack version numbers must be different. Found: %s in both", + version.path(), + other.path(), + version.manifest.getVersion() + ) + ); + } + } + } + } + + @Nullable + private static String getWorldConfigName(@Nonnull Path packPath, @Nonnull Path assetPath) { + Path filepath = packPath.resolve(assetPath); + if (Files.exists(filepath) && Files.isDirectory(filepath)) { + try { + String var6; + try (DirectoryStream dirStream = Files.newDirectoryStream(filepath)) { + Iterator it = dirStream.iterator(); + if (!it.hasNext()) { + LogUtil.getLogger().at(Level.WARNING).log("WorldGen version pack: %s is empty", packPath); + return null; + } + + Path path = it.next(); + if (it.hasNext()) { + LogUtil.getLogger().at(Level.WARNING).log("WorldGen version pack: %s contains multiple world configs", packPath); + return null; + } + + if (!Files.isDirectory(path)) { + LogUtil.getLogger().at(Level.WARNING).log("WorldGen version pack: %s does not contain a world config directory", packPath); + return null; + } + + var6 = path.getFileName().toString(); + } + + return var6; + } catch (IOException var9) { + throw new RuntimeException(var9); + } + } else { + LogUtil.getLogger().at(Level.WARNING).log("WorldGen version pack: %s does not contain dir: %s", packPath, assetPath); + return null; + } + } + + @Nullable + private static PluginManifest loadManifest(@Nonnull Path manifestPath) throws IOException { + if (!Files.exists(manifestPath)) { + return null; + } else { + PluginManifest var6; + try (BufferedReader reader = Files.newBufferedReader(manifestPath, StandardCharsets.UTF_8)) { + char[] buffer = RawJsonReader.READ_BUFFER.get(); + RawJsonReader rawJsonReader = new RawJsonReader(reader, buffer); + ExtraInfo extraInfo = ExtraInfo.THREAD_LOCAL.get(); + PluginManifest manifest = PluginManifest.CODEC.decodeJson(rawJsonReader, extraInfo); + extraInfo.getValidationResults().logOrThrowValidatorExceptions(LogUtil.getLogger()); + var6 = manifest; + } + + return var6; + } + } + + public static Path getVersionsPath() { + return Universe.getWorldGenPath().resolve("$Versions"); + } + + public record Version(@Nonnull String name, @Nonnull Path path, @Nonnull PluginManifest manifest) implements Comparable { + public int compareTo(WorldGenPlugin.Version o) { + return this.manifest.getVersion().compareTo(o.manifest.getVersion()); + } + + @Nonnull + public String getPackName() { + String group = Objects.requireNonNullElse(this.manifest.getGroup(), "Unknown"); + String name = Objects.requireNonNullElse(this.manifest.getName(), "Unknown"); + return group + ":" + name; + } } } diff --git a/src/com/hypixel/hytale/component/Holder.java b/src/com/hypixel/hytale/component/Holder.java index 68f1f7c2..18b07b02 100644 --- a/src/com/hypixel/hytale/component/Holder.java +++ b/src/com/hypixel/hytale/component/Holder.java @@ -21,7 +21,6 @@ public class Holder { @Nullable private final ComponentRegistry registry; private final StampedLock lock = new StampedLock(); - @Nullable private Archetype archetype; @Nullable private Component[] components; @@ -100,7 +99,6 @@ public class Holder { } } - @Nullable public Archetype getArchetype() { return this.archetype; } diff --git a/src/com/hypixel/hytale/component/Ref.java b/src/com/hypixel/hytale/component/Ref.java index 1463cf83..64ae42b8 100644 --- a/src/com/hypixel/hytale/component/Ref.java +++ b/src/com/hypixel/hytale/component/Ref.java @@ -8,7 +8,6 @@ public class Ref { @Nonnull private final Store store; private volatile int index; - private transient volatile int hashCode; private volatile Throwable invalidatedBy; public Ref(@Nonnull Store store) { @@ -18,7 +17,6 @@ public class Ref { public Ref(@Nonnull Store store, int index) { this.store = store; this.index = index; - this.hashCode = this.hashCode0(); } @Nonnull @@ -36,16 +34,22 @@ public class Ref { void invalidate() { this.index = Integer.MIN_VALUE; - this.hashCode = this.hashCode0(); this.invalidatedBy = new Throwable(); } void invalidate(@Nullable Throwable invalidatedBy) { this.index = Integer.MIN_VALUE; - this.hashCode = this.hashCode0(); this.invalidatedBy = invalidatedBy != null ? invalidatedBy : new Throwable(); } + public void validate(@Nonnull Store store) { + if (this.store != store) { + throw new IllegalStateException("Incorrect store for entity reference"); + } else if (this.index == Integer.MIN_VALUE) { + throw new IllegalStateException("Invalid entity reference!", this.invalidatedBy); + } + } + public void validate() { if (this.index == Integer.MIN_VALUE) { throw new IllegalStateException("Invalid entity reference!", this.invalidatedBy); @@ -56,32 +60,6 @@ public class Ref { return this.index != Integer.MIN_VALUE; } - @Override - public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } else if (o != null && this.getClass() == o.getClass()) { - Ref ref = (Ref)o; - return this.index != ref.index ? false : this.store.equals(ref.store); - } else { - return false; - } - } - - public boolean equals(@Nullable Ref o) { - return this == o || o != null && this.index == o.index && this.store.equals(o.store); - } - - @Override - public int hashCode() { - return this.hashCode; - } - - public int hashCode0() { - int result = this.store.hashCode(); - return 31 * result + this.index; - } - @Nonnull @Override public String toString() { diff --git a/src/com/hypixel/hytale/component/Store.java b/src/com/hypixel/hytale/component/Store.java index 73bc3dfc..672a647c 100644 --- a/src/com/hypixel/hytale/component/Store.java +++ b/src/com/hypixel/hytale/component/Store.java @@ -611,7 +611,7 @@ public class Store implements ComponentAccessor { @Nonnull public Holder copyEntity(@Nonnull Ref ref, @Nonnull Holder holder) { this.assertThread(); - ref.validate(); + ref.validate(this); int refIndex = ref.getIndex(); int archetypeIndex = this.entityToArchetypeChunk[refIndex]; return this.archetypeChunks[archetypeIndex].copyEntity(this.entityChunkIndex[refIndex], holder); @@ -625,7 +625,7 @@ public class Store implements ComponentAccessor { @Nonnull public Holder copySerializableEntity(@Nonnull Ref ref, @Nonnull Holder holder) { this.assertThread(); - ref.validate(); + ref.validate(this); int refIndex = ref.getIndex(); int archetypeIndex = this.entityToArchetypeChunk[refIndex]; return this.archetypeChunks[archetypeIndex].copySerializableEntity(this.registry.getData(), this.entityChunkIndex[refIndex], holder); @@ -635,14 +635,14 @@ public class Store implements ComponentAccessor { @Override public Archetype getArchetype(@Nonnull Ref ref) { this.assertThread(); - ref.validate(); + ref.validate(this); int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()]; return this.archetypeChunks[archetypeIndex].getArchetype(); } @Nonnull protected Archetype __internal_getArchetype(@Nonnull Ref ref) { - ref.validate(); + ref.validate(this); int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()]; return this.archetypeChunks[archetypeIndex].getArchetype(); } @@ -662,7 +662,7 @@ public class Store implements ComponentAccessor { Holder removeEntity(@Nonnull Ref ref, @Nonnull Holder holder, @Nonnull RemoveReason reason, @Nullable Throwable proxyReason) { this.assertThread(); this.assertWriteProcessing(); - ref.validate(); + ref.validate(this); CommandBuffer commandBuffer = this.takeCommandBuffer(); int entityIndex = ref.getIndex(); int archetypeIndex = this.entityToArchetypeChunk[entityIndex]; @@ -766,7 +766,7 @@ public class Store implements ComponentAccessor { throw new IllegalArgumentException("EntityHolder start and length exceed array length!"); } else { for (int i = refStart; i < refEnd; i++) { - refArr[i].validate(); + refArr[i].validate(this); } this.assertThread(); @@ -914,7 +914,7 @@ public class Store implements ComponentAccessor { public > void addComponent(@Nonnull Ref ref, @Nonnull ComponentType componentType, @Nonnull T component) { this.assertThread(); this.assertWriteProcessing(); - ref.validate(); + ref.validate(this); componentType.validateRegistry(this.registry); componentType.validate(); Objects.requireNonNull(component); @@ -936,7 +936,7 @@ public class Store implements ComponentAccessor { ) { this.assertThread(); this.assertWriteProcessing(); - ref.validate(); + ref.validate(this); componentType.validateRegistry(this.registry); componentType.validate(); Objects.requireNonNull(component); @@ -973,7 +973,7 @@ public class Store implements ComponentAccessor { public > void putComponent(@Nonnull Ref ref, @Nonnull ComponentType componentType, @Nonnull T component) { this.assertThread(); this.assertWriteProcessing(); - ref.validate(); + ref.validate(this); componentType.validateRegistry(this.registry); componentType.validate(); Objects.requireNonNull(component); @@ -1018,7 +1018,7 @@ public class Store implements ComponentAccessor { @Nullable protected > T __internal_getComponent(@Nonnull Ref ref, @Nonnull ComponentType componentType) { - ref.validate(); + ref.validate(this); componentType.validateRegistry(this.registry); componentType.validate(); int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()]; @@ -1030,7 +1030,7 @@ public class Store implements ComponentAccessor { public > void removeComponent(@Nonnull Ref ref, @Nonnull ComponentType componentType) { this.assertThread(); this.assertWriteProcessing(); - ref.validate(); + ref.validate(this); componentType.validateRegistry(this.registry); componentType.validate(); CommandBuffer commandBuffer = this.takeCommandBuffer(); @@ -1084,7 +1084,7 @@ public class Store implements ComponentAccessor { public > boolean removeComponentIfExists(@Nonnull Ref ref, @Nonnull ComponentType componentType) { this.assertThread(); this.assertWriteProcessing(); - ref.validate(); + ref.validate(this); componentType.validateRegistry(this.registry); componentType.validate(); CommandBuffer commandBuffer = this.takeCommandBuffer(); diff --git a/src/com/hypixel/hytale/event/EventRegistry.java b/src/com/hypixel/hytale/event/EventRegistry.java index 5cc2f524..999e9c7f 100644 --- a/src/com/hypixel/hytale/event/EventRegistry.java +++ b/src/com/hypixel/hytale/event/EventRegistry.java @@ -8,13 +8,14 @@ import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Function; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class EventRegistry extends Registry> implements IEventRegistry { @Nonnull private final IEventRegistry parent; public EventRegistry( - @Nonnull List registrations, @Nonnull BooleanSupplier precondition, String preconditionMessage, @Nonnull IEventRegistry parent + @Nonnull List registrations, @Nonnull BooleanSupplier precondition, @Nullable String preconditionMessage, @Nonnull IEventRegistry parent ) { super(registrations, precondition, preconditionMessage, EventRegistration::new); this.parent = parent; diff --git a/src/com/hypixel/hytale/math/vector/Vector3d.java b/src/com/hypixel/hytale/math/vector/Vector3d.java index fe381ec4..bcda467d 100644 --- a/src/com/hypixel/hytale/math/vector/Vector3d.java +++ b/src/com/hypixel/hytale/math/vector/Vector3d.java @@ -521,6 +521,17 @@ public class Vector3d { return to.clone().subtract(from).normalize(); } + public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) { + return Math.sqrt(distanceSquared(x1, y1, z1, x2, y2, z2)); + } + + public static double distanceSquared(double x1, double y1, double z1, double x2, double y2, double z2) { + x1 -= x2; + y1 -= y2; + z1 -= z2; + return x1 * x1 + y1 * y1 + z1 * z1; + } + @Nonnull public static Vector3d add(@Nonnull Vector3d one, @Nonnull Vector3d two) { return new Vector3d().add(one).add(two); diff --git a/src/com/hypixel/hytale/procedurallib/file/AssetLoader.java b/src/com/hypixel/hytale/procedurallib/file/AssetLoader.java new file mode 100644 index 00000000..e2947677 --- /dev/null +++ b/src/com/hypixel/hytale/procedurallib/file/AssetLoader.java @@ -0,0 +1,12 @@ +package com.hypixel.hytale.procedurallib.file; + +import java.io.IOException; +import java.io.InputStream; +import javax.annotation.Nonnull; + +public interface AssetLoader { + Class type(); + + @Nonnull + T load(@Nonnull InputStream var1) throws IOException; +} diff --git a/src/com/hypixel/hytale/procedurallib/file/AssetPath.java b/src/com/hypixel/hytale/procedurallib/file/AssetPath.java new file mode 100644 index 00000000..b9f7daa4 --- /dev/null +++ b/src/com/hypixel/hytale/procedurallib/file/AssetPath.java @@ -0,0 +1,80 @@ +package com.hypixel.hytale.procedurallib.file; + +import java.nio.file.Path; +import java.util.Comparator; +import javax.annotation.Nonnull; + +public final class AssetPath { + private final Path path; + private final Path filepath; + private final transient int hash; + public static final Comparator COMPARATOR = (a, b) -> { + int max = Math.min(a.filepath.getNameCount(), b.filepath.getNameCount()); + + for (int i = 0; i < max; i++) { + int comp = a.filepath.getName(i).toString().compareTo(b.filepath.getName(i).toString()); + if (comp != 0) { + return comp; + } + } + + return Integer.compare(a.filepath.getNameCount(), b.filepath.getNameCount()); + }; + + private AssetPath(@Nonnull Path path, @Nonnull Path filepath) { + this.path = path; + this.filepath = filepath; + this.hash = FileIO.hashCode(path); + } + + @Nonnull + public AssetPath rename(@Nonnull String filename) { + Path rel = this.path.getParent().resolve(filename); + Path path = this.filepath.getParent().resolve(filename); + return new AssetPath(rel, path); + } + + @Nonnull + public Path path() { + return this.path; + } + + @Nonnull + public Path filepath() { + return this.filepath; + } + + @Nonnull + public String getFileName() { + return this.filepath.getFileName().toString(); + } + + @Override + public String toString() { + return "AssetPath{path=" + this.path + ", filepath=" + this.filepath + "}"; + } + + @Override + public int hashCode() { + return this.hash; + } + + @Override + public boolean equals(Object obj) { + return this == obj || obj instanceof AssetPath other && this.hash == other.hash && FileIO.equals(this.path, other.path); + } + + public static AssetPath fromAbsolute(@Nonnull Path root, @Nonnull Path filepath) { + assert root.getNameCount() == 0 || FileIO.startsWith(filepath, root); + + Path relPath = FileIO.relativize(filepath, root); + return new AssetPath(relPath, filepath); + } + + public static AssetPath fromRelative(@Nonnull Path root, @Nonnull Path assetPath) { + assert root.getNameCount() == 0 || !FileIO.startsWith(assetPath, root); + + Path filepath = FileIO.append(root, assetPath); + return new AssetPath(assetPath, filepath); + } +} diff --git a/src/com/hypixel/hytale/procedurallib/file/FileIO.java b/src/com/hypixel/hytale/procedurallib/file/FileIO.java new file mode 100644 index 00000000..5b55c3b7 --- /dev/null +++ b/src/com/hypixel/hytale/procedurallib/file/FileIO.java @@ -0,0 +1,148 @@ +package com.hypixel.hytale.procedurallib.file; + +import it.unimi.dsi.fastutil.Hash.Strategy; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public interface FileIO { + Strategy PATH_STRATEGY = new Strategy() { + public int hashCode(Path o) { + return FileIO.hashCode(o); + } + + public boolean equals(Path a, Path b) { + return FileIO.equals(a, b); + } + }; + + static void setDefaultRoot(@Nonnull Path path) { + FileIOSystem.Provider.setRoot(path); + } + + @Nonnull + static FileIOSystem openFileIOSystem(@Nonnull FileIOSystem fs) { + FileIOSystem.Provider.set(fs); + return fs; + } + + static void closeFileIOSystem(@Nonnull FileIOSystem fs) { + FileIOSystem.Provider.unset(); + } + + static boolean exists(@Nonnull AssetPath path) { + return Files.exists(path.filepath()); + } + + static boolean exists(@Nonnull Path root, @Nonnull Path path) { + return Files.exists(append(root, path)); + } + + @Nonnull + static AssetPath resolve(@Nonnull Path path) { + FileIOSystem fs = FileIOSystem.Provider.get(); + return fs.resolve(path); + } + + @Nonnull + static T load(@Nonnull AssetPath assetPath, @Nonnull AssetLoader loader) throws IOException { + FileIOSystem fs = FileIOSystem.Provider.get(); + return fs.load(assetPath, loader); + } + + @Nonnull + static T load(@Nonnull Path path, @Nonnull AssetLoader loader) throws IOException { + FileIOSystem fs = FileIOSystem.Provider.get(); + AssetPath assetPath = fs.resolve(path); + return fs.load(assetPath, loader); + } + + @Nonnull + static List list(@Nonnull Path path, @Nonnull Predicate matcher, @Nonnull UnaryOperator disableOp) throws IOException { + FileIOSystem fs = FileIOSystem.Provider.get(); + Path assetDirPath = relativize(path, fs.baseRoot()); + ObjectArrayList paths = new ObjectArrayList<>(); + ObjectOpenHashSet visited = new ObjectOpenHashSet<>(); + + for (Path root : fs.roots().paths) { + Path rootAssetDirPath = append(root, assetDirPath); + if (Files.exists(rootAssetDirPath) && Files.isDirectory(rootAssetDirPath)) { + try (DirectoryStream dirStream = Files.newDirectoryStream(rootAssetDirPath)) { + for (Path filepath : dirStream) { + AssetPath assetPath = AssetPath.fromAbsolute(root, filepath); + AssetPath disabledPath = disableOp.apply(assetPath); + if (disabledPath != assetPath) { + visited.add(disabledPath); + } else if (matcher.test(assetPath) && visited.add(assetPath)) { + paths.add(assetPath); + } + } + } + } + } + + return paths; + } + + static boolean startsWith(Path path, Path prefix) { + if (prefix.getNameCount() > path.getNameCount()) { + return false; + } else { + boolean match = true; + + for (int i = 0; match && i < prefix.getNameCount(); i++) { + match = path.getName(i).toString().equals(prefix.getName(i).toString()); + } + + return match; + } + } + + static Path relativize(Path child, Path parent) { + if (child.getNameCount() < parent.getNameCount()) { + return child; + } else { + return !startsWith(child, parent) ? child : child.subpath(parent.getNameCount(), child.getNameCount()); + } + } + + static Path append(Path root, Path path) { + if (path.getFileSystem() == root.getFileSystem()) { + return root.resolve(path); + } else { + Path out = root; + + for (int i = 0; i < path.getNameCount(); i++) { + out = out.resolve(path.getName(i).toString()); + } + + return out; + } + } + + static boolean equals(@Nullable Path a, @Nullable Path b) { + return a == b || a != null && b != null && a.getNameCount() == b.getNameCount() && startsWith(a, b); + } + + static int hashCode(@Nullable Path path) { + if (path == null) { + return 0; + } else { + int hashcode = 1; + + for (int i = 0; i < path.getNameCount(); i++) { + hashcode = hashcode * 31 + path.getName(i).toString().hashCode(); + } + + return hashcode; + } + } +} diff --git a/src/com/hypixel/hytale/procedurallib/file/FileIOSystem.java b/src/com/hypixel/hytale/procedurallib/file/FileIOSystem.java new file mode 100644 index 00000000..02f13a2d --- /dev/null +++ b/src/com/hypixel/hytale/procedurallib/file/FileIOSystem.java @@ -0,0 +1,109 @@ +package com.hypixel.hytale.procedurallib.file; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import javax.annotation.Nonnull; + +public interface FileIOSystem extends AutoCloseable { + @Nonnull + Path baseRoot(); + + @Nonnull + FileIOSystem.PathArray roots(); + + @Nonnull + default AssetPath resolve(@Nonnull Path path) { + Path relPath = FileIO.relativize(path, this.baseRoot()); + + for (Path root : this.roots().paths) { + AssetPath assetPath = AssetPath.fromRelative(root, relPath); + if (FileIO.exists(assetPath)) { + return assetPath; + } + } + + return AssetPath.fromRelative(this.baseRoot(), relPath); + } + + @Nonnull + default T load(@Nonnull AssetPath path, @Nonnull AssetLoader loader) throws IOException { + if (!Files.exists(path.filepath())) { + throw new FileNotFoundException("Unable to find file: " + path); + } else { + Object var4; + try (InputStream stream = Files.newInputStream(path.filepath())) { + var4 = loader.load(stream); + } + + return (T)var4; + } + } + + @Override + default void close() { + } + + public static final class PathArray { + final Path[] paths; + + public PathArray(Path... paths) { + this.paths = paths; + } + + public int size() { + return this.paths.length; + } + + public Path get(int index) { + return this.paths[index]; + } + } + + public static final class Provider { + private static final FileIOSystem.Provider.DefaultIOFileSystem DEFAULT = new FileIOSystem.Provider.DefaultIOFileSystem(); + private static final ThreadLocal HOLDER = ThreadLocal.withInitial(() -> DEFAULT); + + static FileIOSystem get() { + return HOLDER.get(); + } + + static void set(@Nonnull FileIOSystem fs) { + HOLDER.set(fs); + } + + static void unset() { + HOLDER.set(DEFAULT); + } + + static void setRoot(@Nonnull Path path) { + DEFAULT.setBase(path); + } + + private static final class DefaultIOFileSystem implements FileIOSystem { + private static final Path DEFAULT_ROOT = Paths.get(".").toAbsolutePath(); + private Path base = DEFAULT_ROOT; + private FileIOSystem.PathArray roots = new FileIOSystem.PathArray(DEFAULT_ROOT); + + public synchronized void setBase(Path base) { + this.base = base; + this.roots = new FileIOSystem.PathArray(base); + } + + @Nonnull + @Override + public synchronized Path baseRoot() { + return this.base; + } + + @Nonnull + @Override + public synchronized FileIOSystem.PathArray roots() { + return this.roots; + } + } + } +} diff --git a/src/com/hypixel/hytale/procedurallib/json/JsonLoader.java b/src/com/hypixel/hytale/procedurallib/json/JsonLoader.java index 957a9b47..6e4993a9 100644 --- a/src/com/hypixel/hytale/procedurallib/json/JsonLoader.java +++ b/src/com/hypixel/hytale/procedurallib/json/JsonLoader.java @@ -3,10 +3,8 @@ package com.hypixel.hytale.procedurallib.json; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; +import com.hypixel.hytale.procedurallib.file.FileIO; import java.io.File; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.function.Function; @@ -15,6 +13,13 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class JsonLoader extends Loader { + public static final JsonResourceLoader JSON_LOADER = new JsonResourceLoader<>(JsonElement.class, e -> !e.isJsonNull(), Function.identity()); + public static final JsonResourceLoader JSON_ARR_LOADER = new JsonResourceLoader<>( + JsonArray.class, JsonElement::isJsonArray, JsonElement::getAsJsonArray + ); + public static final JsonResourceLoader JSON_OBJ_LOADER = new JsonResourceLoader<>( + JsonObject.class, JsonElement::isJsonObject, JsonElement::getAsJsonObject + ); @Nullable protected final JsonElement json; @@ -68,14 +73,9 @@ public abstract class JsonLoader extends Loader Path file = this.dataFolder.resolve(filePath.replace('.', File.separatorChar) + ".json"); try { - JsonElement var4; - try (JsonReader reader = new JsonReader(Files.newBufferedReader(file))) { - var4 = JsonParser.parseReader(reader); - } - - return var4; - } catch (Throwable var8) { - throw new Error("Error while loading file reference." + file.toString(), var8); + return FileIO.load(file, JSON_LOADER); + } catch (Throwable var4) { + throw new Error("Error while loading file reference." + file.toString(), var4); } } diff --git a/src/com/hypixel/hytale/procedurallib/json/JsonResourceLoader.java b/src/com/hypixel/hytale/procedurallib/json/JsonResourceLoader.java new file mode 100644 index 00000000..a2d1d520 --- /dev/null +++ b/src/com/hypixel/hytale/procedurallib/json/JsonResourceLoader.java @@ -0,0 +1,52 @@ +package com.hypixel.hytale.procedurallib.json; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonParser; +import com.google.gson.Strictness; +import com.google.gson.stream.JsonReader; +import com.hypixel.hytale.procedurallib.file.AssetLoader; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.function.Function; +import java.util.function.Predicate; +import javax.annotation.Nonnull; + +public class JsonResourceLoader implements AssetLoader { + private final Class type; + private final Predicate predicate; + private final Function mapper; + + public JsonResourceLoader(@Nonnull Class type, @Nonnull Predicate predicate, @Nonnull Function mapper) { + this.type = type; + this.predicate = predicate; + this.mapper = mapper; + } + + @Override + public Class type() { + return this.type; + } + + @Nonnull + public T load(@Nonnull InputStream in) throws IOException { + JsonElement var4; + try (JsonReader reader = new JsonReader(new BufferedReader(new InputStreamReader(in)))) { + reader.setStrictness(Strictness.LENIENT); + JsonElement el = JsonParser.parseReader(reader); + if (el == JsonNull.INSTANCE) { + throw new IOException("Invalid JSON element: null"); + } + + if (!this.predicate.test(el)) { + throw new IOException("Invalid JSON element type. Expected: " + this.type.getSimpleName()); + } + + var4 = this.mapper.apply(el); + } + + return (T)var4; + } +} diff --git a/src/com/hypixel/hytale/protocol/ComponentUpdate.java b/src/com/hypixel/hytale/protocol/ComponentUpdate.java index 838efbe5..dc8628b4 100644 --- a/src/com/hypixel/hytale/protocol/ComponentUpdate.java +++ b/src/com/hypixel/hytale/protocol/ComponentUpdate.java @@ -16,9 +16,9 @@ import javax.annotation.Nullable; public class ComponentUpdate { public static final int NULLABLE_BIT_FIELD_SIZE = 3; - public static final int FIXED_BLOCK_SIZE = 159; + public static final int FIXED_BLOCK_SIZE = 160; public static final int VARIABLE_FIELD_COUNT = 13; - public static final int VARIABLE_BLOCK_START = 211; + public static final int VARIABLE_BLOCK_START = 212; public static final int MAX_SIZE = 1677721600; @Nonnull public ComponentUpdateType type = ComponentUpdateType.Nameplate; @@ -62,6 +62,7 @@ public class ComponentUpdate { public MountedUpdate mounted; @Nullable public String[] activeAnimations; + public boolean isProp; public ComponentUpdate() { } @@ -89,7 +90,8 @@ public class ComponentUpdate { @Nullable int[] soundEventIds, @Nullable String interactionHint, @Nullable MountedUpdate mounted, - @Nullable String[] activeAnimations + @Nullable String[] activeAnimations, + boolean isProp ) { this.type = type; this.nameplate = nameplate; @@ -114,6 +116,7 @@ public class ComponentUpdate { this.interactionHint = interactionHint; this.mounted = mounted; this.activeAnimations = activeAnimations; + this.isProp = isProp; } public ComponentUpdate(@Nonnull ComponentUpdate other) { @@ -140,6 +143,7 @@ public class ComponentUpdate { this.interactionHint = other.interactionHint; this.mounted = other.mounted; this.activeAnimations = other.activeAnimations; + this.isProp = other.isProp; } @Nonnull @@ -168,13 +172,14 @@ public class ComponentUpdate { obj.mounted = MountedUpdate.deserialize(buf, offset + 111); } + obj.isProp = buf.getByte(offset + 159) != 0; if ((nullBits[0] & 16) != 0) { - int varPos0 = offset + 211 + buf.getIntLE(offset + 159); + int varPos0 = offset + 212 + buf.getIntLE(offset + 160); obj.nameplate = Nameplate.deserialize(buf, varPos0); } if ((nullBits[0] & 32) != 0) { - int varPos1 = offset + 211 + buf.getIntLE(offset + 163); + int varPos1 = offset + 212 + buf.getIntLE(offset + 164); int entityUIComponentsCount = VarInt.peek(buf, varPos1); if (entityUIComponentsCount < 0) { throw ProtocolException.negativeLength("EntityUIComponents", entityUIComponentsCount); @@ -197,32 +202,32 @@ public class ComponentUpdate { } if ((nullBits[0] & 64) != 0) { - int varPos2 = offset + 211 + buf.getIntLE(offset + 167); + int varPos2 = offset + 212 + buf.getIntLE(offset + 168); obj.combatTextUpdate = CombatTextUpdate.deserialize(buf, varPos2); } if ((nullBits[0] & 128) != 0) { - int varPos3 = offset + 211 + buf.getIntLE(offset + 171); + int varPos3 = offset + 212 + buf.getIntLE(offset + 172); obj.model = Model.deserialize(buf, varPos3); } if ((nullBits[1] & 1) != 0) { - int varPos4 = offset + 211 + buf.getIntLE(offset + 175); + int varPos4 = offset + 212 + buf.getIntLE(offset + 176); obj.skin = PlayerSkin.deserialize(buf, varPos4); } if ((nullBits[1] & 2) != 0) { - int varPos5 = offset + 211 + buf.getIntLE(offset + 179); + int varPos5 = offset + 212 + buf.getIntLE(offset + 180); obj.item = ItemWithAllMetadata.deserialize(buf, varPos5); } if ((nullBits[1] & 4) != 0) { - int varPos6 = offset + 211 + buf.getIntLE(offset + 183); + int varPos6 = offset + 212 + buf.getIntLE(offset + 184); obj.equipment = Equipment.deserialize(buf, varPos6); } if ((nullBits[1] & 8) != 0) { - int varPos7 = offset + 211 + buf.getIntLE(offset + 187); + int varPos7 = offset + 212 + buf.getIntLE(offset + 188); int entityStatUpdatesCount = VarInt.peek(buf, varPos7); if (entityStatUpdatesCount < 0) { throw ProtocolException.negativeLength("EntityStatUpdates", entityStatUpdatesCount); @@ -268,7 +273,7 @@ public class ComponentUpdate { } if ((nullBits[1] & 16) != 0) { - int varPos8 = offset + 211 + buf.getIntLE(offset + 191); + int varPos8 = offset + 212 + buf.getIntLE(offset + 192); int entityEffectUpdatesCount = VarInt.peek(buf, varPos8); if (entityEffectUpdatesCount < 0) { throw ProtocolException.negativeLength("EntityEffectUpdates", entityEffectUpdatesCount); @@ -293,7 +298,7 @@ public class ComponentUpdate { } if ((nullBits[1] & 32) != 0) { - int varPos9 = offset + 211 + buf.getIntLE(offset + 195); + int varPos9 = offset + 212 + buf.getIntLE(offset + 196); int interactionsCount = VarInt.peek(buf, varPos9); if (interactionsCount < 0) { throw ProtocolException.negativeLength("Interactions", interactionsCount); @@ -318,7 +323,7 @@ public class ComponentUpdate { } if ((nullBits[1] & 64) != 0) { - int varPos10 = offset + 211 + buf.getIntLE(offset + 199); + int varPos10 = offset + 212 + buf.getIntLE(offset + 200); int soundEventIdsCount = VarInt.peek(buf, varPos10); if (soundEventIdsCount < 0) { throw ProtocolException.negativeLength("SoundEventIds", soundEventIdsCount); @@ -341,7 +346,7 @@ public class ComponentUpdate { } if ((nullBits[1] & 128) != 0) { - int varPos11 = offset + 211 + buf.getIntLE(offset + 203); + int varPos11 = offset + 212 + buf.getIntLE(offset + 204); int interactionHintLen = VarInt.peek(buf, varPos11); if (interactionHintLen < 0) { throw ProtocolException.negativeLength("InteractionHint", interactionHintLen); @@ -355,7 +360,7 @@ public class ComponentUpdate { } if ((nullBits[2] & 1) != 0) { - int varPos12 = offset + 211 + buf.getIntLE(offset + 207); + int varPos12 = offset + 212 + buf.getIntLE(offset + 208); int activeAnimationsCount = VarInt.peek(buf, varPos12); if (activeAnimationsCount < 0) { throw ProtocolException.negativeLength("ActiveAnimations", activeAnimationsCount); @@ -394,10 +399,10 @@ public class ComponentUpdate { public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte[] nullBits = PacketIO.readBytes(buf, offset, 3); - int maxEnd = 211; + int maxEnd = 212; if ((nullBits[0] & 16) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 159); - int pos0 = offset + 211 + fieldOffset0; + int fieldOffset0 = buf.getIntLE(offset + 160); + int pos0 = offset + 212 + fieldOffset0; pos0 += Nameplate.computeBytesConsumed(buf, pos0); if (pos0 - offset > maxEnd) { maxEnd = pos0 - offset; @@ -405,8 +410,8 @@ public class ComponentUpdate { } if ((nullBits[0] & 32) != 0) { - int fieldOffset1 = buf.getIntLE(offset + 163); - int pos1 = offset + 211 + fieldOffset1; + int fieldOffset1 = buf.getIntLE(offset + 164); + int pos1 = offset + 212 + fieldOffset1; int arrLen = VarInt.peek(buf, pos1); pos1 += VarInt.length(buf, pos1) + arrLen * 4; if (pos1 - offset > maxEnd) { @@ -415,8 +420,8 @@ public class ComponentUpdate { } if ((nullBits[0] & 64) != 0) { - int fieldOffset2 = buf.getIntLE(offset + 167); - int pos2 = offset + 211 + fieldOffset2; + int fieldOffset2 = buf.getIntLE(offset + 168); + int pos2 = offset + 212 + fieldOffset2; pos2 += CombatTextUpdate.computeBytesConsumed(buf, pos2); if (pos2 - offset > maxEnd) { maxEnd = pos2 - offset; @@ -424,8 +429,8 @@ public class ComponentUpdate { } if ((nullBits[0] & 128) != 0) { - int fieldOffset3 = buf.getIntLE(offset + 171); - int pos3 = offset + 211 + fieldOffset3; + int fieldOffset3 = buf.getIntLE(offset + 172); + int pos3 = offset + 212 + fieldOffset3; pos3 += Model.computeBytesConsumed(buf, pos3); if (pos3 - offset > maxEnd) { maxEnd = pos3 - offset; @@ -433,8 +438,8 @@ public class ComponentUpdate { } if ((nullBits[1] & 1) != 0) { - int fieldOffset4 = buf.getIntLE(offset + 175); - int pos4 = offset + 211 + fieldOffset4; + int fieldOffset4 = buf.getIntLE(offset + 176); + int pos4 = offset + 212 + fieldOffset4; pos4 += PlayerSkin.computeBytesConsumed(buf, pos4); if (pos4 - offset > maxEnd) { maxEnd = pos4 - offset; @@ -442,8 +447,8 @@ public class ComponentUpdate { } if ((nullBits[1] & 2) != 0) { - int fieldOffset5 = buf.getIntLE(offset + 179); - int pos5 = offset + 211 + fieldOffset5; + int fieldOffset5 = buf.getIntLE(offset + 180); + int pos5 = offset + 212 + fieldOffset5; pos5 += ItemWithAllMetadata.computeBytesConsumed(buf, pos5); if (pos5 - offset > maxEnd) { maxEnd = pos5 - offset; @@ -451,8 +456,8 @@ public class ComponentUpdate { } if ((nullBits[1] & 4) != 0) { - int fieldOffset6 = buf.getIntLE(offset + 183); - int pos6 = offset + 211 + fieldOffset6; + int fieldOffset6 = buf.getIntLE(offset + 184); + int pos6 = offset + 212 + fieldOffset6; pos6 += Equipment.computeBytesConsumed(buf, pos6); if (pos6 - offset > maxEnd) { maxEnd = pos6 - offset; @@ -460,8 +465,8 @@ public class ComponentUpdate { } if ((nullBits[1] & 8) != 0) { - int fieldOffset7 = buf.getIntLE(offset + 187); - int pos7 = offset + 211 + fieldOffset7; + int fieldOffset7 = buf.getIntLE(offset + 188); + int pos7 = offset + 212 + fieldOffset7; int dictLen = VarInt.peek(buf, pos7); pos7 += VarInt.length(buf, pos7); @@ -481,8 +486,8 @@ public class ComponentUpdate { } if ((nullBits[1] & 16) != 0) { - int fieldOffset8 = buf.getIntLE(offset + 191); - int pos8 = offset + 211 + fieldOffset8; + int fieldOffset8 = buf.getIntLE(offset + 192); + int pos8 = offset + 212 + fieldOffset8; int arrLen = VarInt.peek(buf, pos8); pos8 += VarInt.length(buf, pos8); @@ -496,8 +501,8 @@ public class ComponentUpdate { } if ((nullBits[1] & 32) != 0) { - int fieldOffset9 = buf.getIntLE(offset + 195); - int pos9 = offset + 211 + fieldOffset9; + int fieldOffset9 = buf.getIntLE(offset + 196); + int pos9 = offset + 212 + fieldOffset9; int dictLen = VarInt.peek(buf, pos9); pos9 += VarInt.length(buf, pos9); @@ -511,8 +516,8 @@ public class ComponentUpdate { } if ((nullBits[1] & 64) != 0) { - int fieldOffset10 = buf.getIntLE(offset + 199); - int pos10 = offset + 211 + fieldOffset10; + int fieldOffset10 = buf.getIntLE(offset + 200); + int pos10 = offset + 212 + fieldOffset10; int arrLen = VarInt.peek(buf, pos10); pos10 += VarInt.length(buf, pos10) + arrLen * 4; if (pos10 - offset > maxEnd) { @@ -521,8 +526,8 @@ public class ComponentUpdate { } if ((nullBits[1] & 128) != 0) { - int fieldOffset11 = buf.getIntLE(offset + 203); - int pos11 = offset + 211 + fieldOffset11; + int fieldOffset11 = buf.getIntLE(offset + 204); + int pos11 = offset + 212 + fieldOffset11; int sl = VarInt.peek(buf, pos11); pos11 += VarInt.length(buf, pos11) + sl; if (pos11 - offset > maxEnd) { @@ -531,8 +536,8 @@ public class ComponentUpdate { } if ((nullBits[2] & 1) != 0) { - int fieldOffset12 = buf.getIntLE(offset + 207); - int pos12 = offset + 211 + fieldOffset12; + int fieldOffset12 = buf.getIntLE(offset + 208); + int pos12 = offset + 212 + fieldOffset12; int arrLen = VarInt.peek(buf, pos12); pos12 += VarInt.length(buf, pos12); int bitfieldSize = (arrLen + 7) / 8; @@ -656,6 +661,7 @@ public class ComponentUpdate { buf.writeZero(48); } + buf.writeByte(this.isProp ? 1 : 0); int nameplateOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); int entityUIComponentsOffsetSlot = buf.writerIndex(); @@ -842,7 +848,7 @@ public class ComponentUpdate { } public int computeSize() { - int size = 211; + int size = 212; if (this.nameplate != null) { size += this.nameplate.computeSize(); } @@ -919,17 +925,17 @@ public class ComponentUpdate { } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 211) { - return ValidationResult.error("Buffer too small: expected at least 211 bytes"); + if (buffer.readableBytes() - offset < 212) { + return ValidationResult.error("Buffer too small: expected at least 212 bytes"); } else { byte[] nullBits = PacketIO.readBytes(buffer, offset, 3); if ((nullBits[0] & 16) != 0) { - int nameplateOffset = buffer.getIntLE(offset + 159); + int nameplateOffset = buffer.getIntLE(offset + 160); if (nameplateOffset < 0) { return ValidationResult.error("Invalid offset for Nameplate"); } - int pos = offset + 211 + nameplateOffset; + int pos = offset + 212 + nameplateOffset; if (pos >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Nameplate"); } @@ -943,12 +949,12 @@ public class ComponentUpdate { } if ((nullBits[0] & 32) != 0) { - int entityUIComponentsOffset = buffer.getIntLE(offset + 163); + int entityUIComponentsOffset = buffer.getIntLE(offset + 164); if (entityUIComponentsOffset < 0) { return ValidationResult.error("Invalid offset for EntityUIComponents"); } - int posx = offset + 211 + entityUIComponentsOffset; + int posx = offset + 212 + entityUIComponentsOffset; if (posx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for EntityUIComponents"); } @@ -970,12 +976,12 @@ public class ComponentUpdate { } if ((nullBits[0] & 64) != 0) { - int combatTextUpdateOffset = buffer.getIntLE(offset + 167); + int combatTextUpdateOffset = buffer.getIntLE(offset + 168); if (combatTextUpdateOffset < 0) { return ValidationResult.error("Invalid offset for CombatTextUpdate"); } - int posxx = offset + 211 + combatTextUpdateOffset; + int posxx = offset + 212 + combatTextUpdateOffset; if (posxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for CombatTextUpdate"); } @@ -989,12 +995,12 @@ public class ComponentUpdate { } if ((nullBits[0] & 128) != 0) { - int modelOffset = buffer.getIntLE(offset + 171); + int modelOffset = buffer.getIntLE(offset + 172); if (modelOffset < 0) { return ValidationResult.error("Invalid offset for Model"); } - int posxxx = offset + 211 + modelOffset; + int posxxx = offset + 212 + modelOffset; if (posxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Model"); } @@ -1008,12 +1014,12 @@ public class ComponentUpdate { } if ((nullBits[1] & 1) != 0) { - int skinOffset = buffer.getIntLE(offset + 175); + int skinOffset = buffer.getIntLE(offset + 176); if (skinOffset < 0) { return ValidationResult.error("Invalid offset for Skin"); } - int posxxxx = offset + 211 + skinOffset; + int posxxxx = offset + 212 + skinOffset; if (posxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Skin"); } @@ -1027,12 +1033,12 @@ public class ComponentUpdate { } if ((nullBits[1] & 2) != 0) { - int itemOffset = buffer.getIntLE(offset + 179); + int itemOffset = buffer.getIntLE(offset + 180); if (itemOffset < 0) { return ValidationResult.error("Invalid offset for Item"); } - int posxxxxx = offset + 211 + itemOffset; + int posxxxxx = offset + 212 + itemOffset; if (posxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Item"); } @@ -1046,12 +1052,12 @@ public class ComponentUpdate { } if ((nullBits[1] & 4) != 0) { - int equipmentOffset = buffer.getIntLE(offset + 183); + int equipmentOffset = buffer.getIntLE(offset + 184); if (equipmentOffset < 0) { return ValidationResult.error("Invalid offset for Equipment"); } - int posxxxxxx = offset + 211 + equipmentOffset; + int posxxxxxx = offset + 212 + equipmentOffset; if (posxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Equipment"); } @@ -1065,12 +1071,12 @@ public class ComponentUpdate { } if ((nullBits[1] & 8) != 0) { - int entityStatUpdatesOffset = buffer.getIntLE(offset + 187); + int entityStatUpdatesOffset = buffer.getIntLE(offset + 188); if (entityStatUpdatesOffset < 0) { return ValidationResult.error("Invalid offset for EntityStatUpdates"); } - int posxxxxxxx = offset + 211 + entityStatUpdatesOffset; + int posxxxxxxx = offset + 212 + entityStatUpdatesOffset; if (posxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for EntityStatUpdates"); } @@ -1106,12 +1112,12 @@ public class ComponentUpdate { } if ((nullBits[1] & 16) != 0) { - int entityEffectUpdatesOffset = buffer.getIntLE(offset + 191); + int entityEffectUpdatesOffset = buffer.getIntLE(offset + 192); if (entityEffectUpdatesOffset < 0) { return ValidationResult.error("Invalid offset for EntityEffectUpdates"); } - int posxxxxxxxx = offset + 211 + entityEffectUpdatesOffset; + int posxxxxxxxx = offset + 212 + entityEffectUpdatesOffset; if (posxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for EntityEffectUpdates"); } @@ -1138,12 +1144,12 @@ public class ComponentUpdate { } if ((nullBits[1] & 32) != 0) { - int interactionsOffset = buffer.getIntLE(offset + 195); + int interactionsOffset = buffer.getIntLE(offset + 196); if (interactionsOffset < 0) { return ValidationResult.error("Invalid offset for Interactions"); } - int posxxxxxxxxx = offset + 211 + interactionsOffset; + int posxxxxxxxxx = offset + 212 + interactionsOffset; if (posxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Interactions"); } @@ -1168,12 +1174,12 @@ public class ComponentUpdate { } if ((nullBits[1] & 64) != 0) { - int soundEventIdsOffset = buffer.getIntLE(offset + 199); + int soundEventIdsOffset = buffer.getIntLE(offset + 200); if (soundEventIdsOffset < 0) { return ValidationResult.error("Invalid offset for SoundEventIds"); } - int posxxxxxxxxxx = offset + 211 + soundEventIdsOffset; + int posxxxxxxxxxx = offset + 212 + soundEventIdsOffset; if (posxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for SoundEventIds"); } @@ -1195,12 +1201,12 @@ public class ComponentUpdate { } if ((nullBits[1] & 128) != 0) { - int interactionHintOffset = buffer.getIntLE(offset + 203); + int interactionHintOffset = buffer.getIntLE(offset + 204); if (interactionHintOffset < 0) { return ValidationResult.error("Invalid offset for InteractionHint"); } - int posxxxxxxxxxxx = offset + 211 + interactionHintOffset; + int posxxxxxxxxxxx = offset + 212 + interactionHintOffset; if (posxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for InteractionHint"); } @@ -1222,12 +1228,12 @@ public class ComponentUpdate { } if ((nullBits[2] & 1) != 0) { - int activeAnimationsOffset = buffer.getIntLE(offset + 207); + int activeAnimationsOffset = buffer.getIntLE(offset + 208); if (activeAnimationsOffset < 0) { return ValidationResult.error("Invalid offset for ActiveAnimations"); } - int posxxxxxxxxxxxx = offset + 211 + activeAnimationsOffset; + int posxxxxxxxxxxxx = offset + 212 + activeAnimationsOffset; if (posxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for ActiveAnimations"); } @@ -1297,6 +1303,7 @@ public class ComponentUpdate { copy.interactionHint = this.interactionHint; copy.mounted = this.mounted != null ? this.mounted.clone() : null; copy.activeAnimations = this.activeAnimations != null ? Arrays.copyOf(this.activeAnimations, this.activeAnimations.length) : null; + copy.isProp = this.isProp; return copy; } @@ -1329,7 +1336,8 @@ public class ComponentUpdate { && Arrays.equals(this.soundEventIds, other.soundEventIds) && Objects.equals(this.interactionHint, other.interactionHint) && Objects.equals(this.mounted, other.mounted) - && Arrays.equals((Object[])this.activeAnimations, (Object[])other.activeAnimations); + && Arrays.equals((Object[])this.activeAnimations, (Object[])other.activeAnimations) + && this.isProp == other.isProp; } } @@ -1358,6 +1366,7 @@ public class ComponentUpdate { result = 31 * result + Arrays.hashCode(this.soundEventIds); result = 31 * result + Objects.hashCode(this.interactionHint); result = 31 * result + Objects.hashCode(this.mounted); - return 31 * result + Arrays.hashCode((Object[])this.activeAnimations); + result = 31 * result + Arrays.hashCode((Object[])this.activeAnimations); + return 31 * result + Boolean.hashCode(this.isProp); } } diff --git a/src/com/hypixel/hytale/protocol/ComponentUpdateType.java b/src/com/hypixel/hytale/protocol/ComponentUpdateType.java index eb2b7775..b1448108 100644 --- a/src/com/hypixel/hytale/protocol/ComponentUpdateType.java +++ b/src/com/hypixel/hytale/protocol/ComponentUpdateType.java @@ -27,7 +27,8 @@ public enum ComponentUpdateType { Audio(21), Mounted(22), NewSpawn(23), - ActiveAnimations(24); + ActiveAnimations(24), + Prop(25); public static final ComponentUpdateType[] VALUES = values(); private final int value; diff --git a/src/com/hypixel/hytale/protocol/EntityUpdate.java b/src/com/hypixel/hytale/protocol/EntityUpdate.java index eab33dfe..541dbf04 100644 --- a/src/com/hypixel/hytale/protocol/EntityUpdate.java +++ b/src/com/hypixel/hytale/protocol/EntityUpdate.java @@ -77,8 +77,8 @@ public class EntityUpdate { } int varIntLen = VarInt.length(buf, varPos1); - if (varPos1 + varIntLen + updatesCount * 159L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall("Updates", varPos1 + varIntLen + updatesCount * 159, buf.readableBytes()); + if (varPos1 + varIntLen + updatesCount * 160L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("Updates", varPos1 + varIntLen + updatesCount * 160, buf.readableBytes()); } obj.updates = new ComponentUpdate[updatesCount]; diff --git a/src/com/hypixel/hytale/protocol/Objective.java b/src/com/hypixel/hytale/protocol/Objective.java index 9dea626d..2811bf18 100644 --- a/src/com/hypixel/hytale/protocol/Objective.java +++ b/src/com/hypixel/hytale/protocol/Objective.java @@ -20,9 +20,9 @@ public class Objective { @Nonnull public UUID objectiveUuid = new UUID(0L, 0L); @Nullable - public String objectiveTitleKey; + public FormattedMessage objectiveTitleKey; @Nullable - public String objectiveDescriptionKey; + public FormattedMessage objectiveDescriptionKey; @Nullable public String objectiveLineId; @Nullable @@ -33,8 +33,8 @@ public class Objective { public Objective( @Nonnull UUID objectiveUuid, - @Nullable String objectiveTitleKey, - @Nullable String objectiveDescriptionKey, + @Nullable FormattedMessage objectiveTitleKey, + @Nullable FormattedMessage objectiveDescriptionKey, @Nullable String objectiveLineId, @Nullable ObjectiveTask[] tasks ) { @@ -60,30 +60,12 @@ public class Objective { obj.objectiveUuid = PacketIO.readUUID(buf, offset + 1); if ((nullBits & 1) != 0) { int varPos0 = offset + 33 + buf.getIntLE(offset + 17); - int objectiveTitleKeyLen = VarInt.peek(buf, varPos0); - if (objectiveTitleKeyLen < 0) { - throw ProtocolException.negativeLength("ObjectiveTitleKey", objectiveTitleKeyLen); - } - - if (objectiveTitleKeyLen > 4096000) { - throw ProtocolException.stringTooLong("ObjectiveTitleKey", objectiveTitleKeyLen, 4096000); - } - - obj.objectiveTitleKey = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); + obj.objectiveTitleKey = FormattedMessage.deserialize(buf, varPos0); } if ((nullBits & 2) != 0) { int varPos1 = offset + 33 + buf.getIntLE(offset + 21); - int objectiveDescriptionKeyLen = VarInt.peek(buf, varPos1); - if (objectiveDescriptionKeyLen < 0) { - throw ProtocolException.negativeLength("ObjectiveDescriptionKey", objectiveDescriptionKeyLen); - } - - if (objectiveDescriptionKeyLen > 4096000) { - throw ProtocolException.stringTooLong("ObjectiveDescriptionKey", objectiveDescriptionKeyLen, 4096000); - } - - obj.objectiveDescriptionKey = PacketIO.readVarString(buf, varPos1, PacketIO.UTF8); + obj.objectiveDescriptionKey = FormattedMessage.deserialize(buf, varPos1); } if ((nullBits & 4) != 0) { @@ -134,8 +116,7 @@ public class Objective { if ((nullBits & 1) != 0) { int fieldOffset0 = buf.getIntLE(offset + 17); int pos0 = offset + 33 + fieldOffset0; - int sl = VarInt.peek(buf, pos0); - pos0 += VarInt.length(buf, pos0) + sl; + pos0 += FormattedMessage.computeBytesConsumed(buf, pos0); if (pos0 - offset > maxEnd) { maxEnd = pos0 - offset; } @@ -144,8 +125,7 @@ public class Objective { if ((nullBits & 2) != 0) { int fieldOffset1 = buf.getIntLE(offset + 21); int pos1 = offset + 33 + fieldOffset1; - int sl = VarInt.peek(buf, pos1); - pos1 += VarInt.length(buf, pos1) + sl; + pos1 += FormattedMessage.computeBytesConsumed(buf, pos1); if (pos1 - offset > maxEnd) { maxEnd = pos1 - offset; } @@ -211,14 +191,14 @@ public class Objective { int varBlockStart = buf.writerIndex(); if (this.objectiveTitleKey != null) { buf.setIntLE(objectiveTitleKeyOffsetSlot, buf.writerIndex() - varBlockStart); - PacketIO.writeVarString(buf, this.objectiveTitleKey, 4096000); + this.objectiveTitleKey.serialize(buf); } else { buf.setIntLE(objectiveTitleKeyOffsetSlot, -1); } if (this.objectiveDescriptionKey != null) { buf.setIntLE(objectiveDescriptionKeyOffsetSlot, buf.writerIndex() - varBlockStart); - PacketIO.writeVarString(buf, this.objectiveDescriptionKey, 4096000); + this.objectiveDescriptionKey.serialize(buf); } else { buf.setIntLE(objectiveDescriptionKeyOffsetSlot, -1); } @@ -249,11 +229,11 @@ public class Objective { public int computeSize() { int size = 33; if (this.objectiveTitleKey != null) { - size += PacketIO.stringSize(this.objectiveTitleKey); + size += this.objectiveTitleKey.computeSize(); } if (this.objectiveDescriptionKey != null) { - size += PacketIO.stringSize(this.objectiveDescriptionKey); + size += this.objectiveDescriptionKey.computeSize(); } if (this.objectiveLineId != null) { @@ -289,20 +269,12 @@ public class Objective { return ValidationResult.error("Offset out of bounds for ObjectiveTitleKey"); } - int objectiveTitleKeyLen = VarInt.peek(buffer, pos); - if (objectiveTitleKeyLen < 0) { - return ValidationResult.error("Invalid string length for ObjectiveTitleKey"); + ValidationResult objectiveTitleKeyResult = FormattedMessage.validateStructure(buffer, pos); + if (!objectiveTitleKeyResult.isValid()) { + return ValidationResult.error("Invalid ObjectiveTitleKey: " + objectiveTitleKeyResult.error()); } - if (objectiveTitleKeyLen > 4096000) { - return ValidationResult.error("ObjectiveTitleKey exceeds max length 4096000"); - } - - pos += VarInt.length(buffer, pos); - pos += objectiveTitleKeyLen; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading ObjectiveTitleKey"); - } + pos += FormattedMessage.computeBytesConsumed(buffer, pos); } if ((nullBits & 2) != 0) { @@ -316,20 +288,12 @@ public class Objective { return ValidationResult.error("Offset out of bounds for ObjectiveDescriptionKey"); } - int objectiveDescriptionKeyLen = VarInt.peek(buffer, posx); - if (objectiveDescriptionKeyLen < 0) { - return ValidationResult.error("Invalid string length for ObjectiveDescriptionKey"); + ValidationResult objectiveDescriptionKeyResult = FormattedMessage.validateStructure(buffer, posx); + if (!objectiveDescriptionKeyResult.isValid()) { + return ValidationResult.error("Invalid ObjectiveDescriptionKey: " + objectiveDescriptionKeyResult.error()); } - if (objectiveDescriptionKeyLen > 4096000) { - return ValidationResult.error("ObjectiveDescriptionKey exceeds max length 4096000"); - } - - posx += VarInt.length(buffer, posx); - posx += objectiveDescriptionKeyLen; - if (posx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading ObjectiveDescriptionKey"); - } + posx += FormattedMessage.computeBytesConsumed(buffer, posx); } if ((nullBits & 4) != 0) { @@ -398,8 +362,8 @@ public class Objective { public Objective clone() { Objective copy = new Objective(); copy.objectiveUuid = this.objectiveUuid; - copy.objectiveTitleKey = this.objectiveTitleKey; - copy.objectiveDescriptionKey = this.objectiveDescriptionKey; + copy.objectiveTitleKey = this.objectiveTitleKey != null ? this.objectiveTitleKey.clone() : null; + copy.objectiveDescriptionKey = this.objectiveDescriptionKey != null ? this.objectiveDescriptionKey.clone() : null; copy.objectiveLineId = this.objectiveLineId; copy.tasks = this.tasks != null ? Arrays.stream(this.tasks).map(e -> e.clone()).toArray(ObjectiveTask[]::new) : null; return copy; diff --git a/src/com/hypixel/hytale/protocol/ObjectiveTask.java b/src/com/hypixel/hytale/protocol/ObjectiveTask.java index 80a4cc4c..3aaf2545 100644 --- a/src/com/hypixel/hytale/protocol/ObjectiveTask.java +++ b/src/com/hypixel/hytale/protocol/ObjectiveTask.java @@ -1,9 +1,6 @@ package com.hypixel.hytale.protocol; -import com.hypixel.hytale.protocol.io.PacketIO; -import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; -import com.hypixel.hytale.protocol.io.VarInt; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; @@ -14,16 +11,16 @@ public class ObjectiveTask { public static final int FIXED_BLOCK_SIZE = 9; public static final int VARIABLE_FIELD_COUNT = 1; public static final int VARIABLE_BLOCK_START = 9; - public static final int MAX_SIZE = 16384014; + public static final int MAX_SIZE = 1677721600; @Nullable - public String taskDescriptionKey; + public FormattedMessage taskDescriptionKey; public int currentCompletion; public int completionNeeded; public ObjectiveTask() { } - public ObjectiveTask(@Nullable String taskDescriptionKey, int currentCompletion, int completionNeeded) { + public ObjectiveTask(@Nullable FormattedMessage taskDescriptionKey, int currentCompletion, int completionNeeded) { this.taskDescriptionKey = taskDescriptionKey; this.currentCompletion = currentCompletion; this.completionNeeded = completionNeeded; @@ -43,18 +40,8 @@ public class ObjectiveTask { obj.completionNeeded = buf.getIntLE(offset + 5); int pos = offset + 9; if ((nullBits & 1) != 0) { - int taskDescriptionKeyLen = VarInt.peek(buf, pos); - if (taskDescriptionKeyLen < 0) { - throw ProtocolException.negativeLength("TaskDescriptionKey", taskDescriptionKeyLen); - } - - if (taskDescriptionKeyLen > 4096000) { - throw ProtocolException.stringTooLong("TaskDescriptionKey", taskDescriptionKeyLen, 4096000); - } - - int taskDescriptionKeyVarLen = VarInt.length(buf, pos); - obj.taskDescriptionKey = PacketIO.readVarString(buf, pos, PacketIO.UTF8); - pos += taskDescriptionKeyVarLen + taskDescriptionKeyLen; + obj.taskDescriptionKey = FormattedMessage.deserialize(buf, pos); + pos += FormattedMessage.computeBytesConsumed(buf, pos); } return obj; @@ -64,8 +51,7 @@ public class ObjectiveTask { byte nullBits = buf.getByte(offset); int pos = offset + 9; if ((nullBits & 1) != 0) { - int sl = VarInt.peek(buf, pos); - pos += VarInt.length(buf, pos) + sl; + pos += FormattedMessage.computeBytesConsumed(buf, pos); } return pos - offset; @@ -81,14 +67,14 @@ public class ObjectiveTask { buf.writeIntLE(this.currentCompletion); buf.writeIntLE(this.completionNeeded); if (this.taskDescriptionKey != null) { - PacketIO.writeVarString(buf, this.taskDescriptionKey, 4096000); + this.taskDescriptionKey.serialize(buf); } } public int computeSize() { int size = 9; if (this.taskDescriptionKey != null) { - size += PacketIO.stringSize(this.taskDescriptionKey); + size += this.taskDescriptionKey.computeSize(); } return size; @@ -101,20 +87,12 @@ public class ObjectiveTask { byte nullBits = buffer.getByte(offset); int pos = offset + 9; if ((nullBits & 1) != 0) { - int taskDescriptionKeyLen = VarInt.peek(buffer, pos); - if (taskDescriptionKeyLen < 0) { - return ValidationResult.error("Invalid string length for TaskDescriptionKey"); + ValidationResult taskDescriptionKeyResult = FormattedMessage.validateStructure(buffer, pos); + if (!taskDescriptionKeyResult.isValid()) { + return ValidationResult.error("Invalid TaskDescriptionKey: " + taskDescriptionKeyResult.error()); } - if (taskDescriptionKeyLen > 4096000) { - return ValidationResult.error("TaskDescriptionKey exceeds max length 4096000"); - } - - pos += VarInt.length(buffer, pos); - pos += taskDescriptionKeyLen; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading TaskDescriptionKey"); - } + pos += FormattedMessage.computeBytesConsumed(buffer, pos); } return ValidationResult.OK; @@ -123,7 +101,7 @@ public class ObjectiveTask { public ObjectiveTask clone() { ObjectiveTask copy = new ObjectiveTask(); - copy.taskDescriptionKey = this.taskDescriptionKey; + copy.taskDescriptionKey = this.taskDescriptionKey != null ? this.taskDescriptionKey.clone() : null; copy.currentCompletion = this.currentCompletion; copy.completionNeeded = this.completionNeeded; return copy; diff --git a/src/com/hypixel/hytale/protocol/PacketRegistry.java b/src/com/hypixel/hytale/protocol/PacketRegistry.java index e3e8d3bd..50b807a8 100644 --- a/src/com/hypixel/hytale/protocol/PacketRegistry.java +++ b/src/com/hypixel/hytale/protocol/PacketRegistry.java @@ -126,6 +126,7 @@ import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSelectionTool import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSelectionToolReplyWithClipboard; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSelectionTransform; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSelectionUpdate; +import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSetEntityCollision; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSetEntityLight; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSetEntityPickupEnabled; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolSetEntityScale; @@ -264,6 +265,7 @@ import com.hypixel.hytale.protocol.packets.world.UpdateTime; import com.hypixel.hytale.protocol.packets.world.UpdateTimeSettings; import com.hypixel.hytale.protocol.packets.world.UpdateWeather; import com.hypixel.hytale.protocol.packets.worldmap.ClearWorldMap; +import com.hypixel.hytale.protocol.packets.worldmap.CreateUserMarker; import com.hypixel.hytale.protocol.packets.worldmap.TeleportToWorldMapMarker; import com.hypixel.hytale.protocol.packets.worldmap.TeleportToWorldMapPosition; import com.hypixel.hytale.protocol.packets.worldmap.UpdateWorldMap; @@ -335,7 +337,7 @@ public final class PacketRegistry { register(17, "PasswordRejected", PasswordRejected.class, 5, 74, false, PasswordRejected::validateStructure, PasswordRejected::deserialize); register(18, "ClientReferral", ClientReferral.class, 1, 5141, false, ClientReferral::validateStructure, ClientReferral::deserialize); register(20, "WorldSettings", WorldSettings.class, 5, 1677721600, true, WorldSettings::validateStructure, WorldSettings::deserialize); - register(21, "WorldLoadProgress", WorldLoadProgress.class, 9, 16384014, false, WorldLoadProgress::validateStructure, WorldLoadProgress::deserialize); + register(21, "WorldLoadProgress", WorldLoadProgress.class, 9, 1677721600, false, WorldLoadProgress::validateStructure, WorldLoadProgress::deserialize); register(22, "WorldLoadFinished", WorldLoadFinished.class, 0, 0, false, WorldLoadFinished::validateStructure, WorldLoadFinished::deserialize); register(23, "RequestAssets", RequestAssets.class, 1, 1677721600, true, RequestAssets::validateStructure, RequestAssets::deserialize); register(24, "AssetInitialize", AssetInitialize.class, 4, 2121, false, AssetInitialize::validateStructure, AssetInitialize::deserialize); @@ -499,7 +501,7 @@ public final class PacketRegistry { ); register(70, "UntrackObjective", UntrackObjective.class, 16, 16, false, UntrackObjective::validateStructure, UntrackObjective::deserialize); register( - 71, "UpdateObjectiveTask", UpdateObjectiveTask.class, 21, 16384035, false, UpdateObjectiveTask::validateStructure, UpdateObjectiveTask::deserialize + 71, "UpdateObjectiveTask", UpdateObjectiveTask.class, 21, 1677721600, false, UpdateObjectiveTask::validateStructure, UpdateObjectiveTask::deserialize ); register( 72, @@ -842,7 +844,7 @@ public final class PacketRegistry { 240, "UpdateWorldMapSettings", UpdateWorldMapSettings.class, - 16, + 20, 1677721600, false, UpdateWorldMapSettings::validateStructure, @@ -873,6 +875,7 @@ public final class PacketRegistry { TeleportToWorldMapPosition::validateStructure, TeleportToWorldMapPosition::deserialize ); + register(246, "CreateUserMarker", CreateUserMarker.class, 13, 32768031, false, CreateUserMarker::validateStructure, CreateUserMarker::deserialize); register(250, "RequestServerAccess", RequestServerAccess.class, 3, 3, false, RequestServerAccess::validateStructure, RequestServerAccess::deserialize); register( 251, "UpdateServerAccess", UpdateServerAccess.class, 2, 1677721600, false, UpdateServerAccess::validateStructure, UpdateServerAccess::deserialize @@ -1677,6 +1680,16 @@ public final class PacketRegistry { BuilderToolSetNPCDebug::validateStructure, BuilderToolSetNPCDebug::deserialize ); + register( + 425, + "BuilderToolSetEntityCollision", + BuilderToolSetEntityCollision.class, + 5, + 16384010, + false, + BuilderToolSetEntityCollision::validateStructure, + BuilderToolSetEntityCollision::deserialize + ); } public record PacketInfo( diff --git a/src/com/hypixel/hytale/protocol/ProtocolSettings.java b/src/com/hypixel/hytale/protocol/ProtocolSettings.java index 13f2c489..d89c6f61 100644 --- a/src/com/hypixel/hytale/protocol/ProtocolSettings.java +++ b/src/com/hypixel/hytale/protocol/ProtocolSettings.java @@ -1,11 +1,11 @@ package com.hypixel.hytale.protocol; public final class ProtocolSettings { - public static final int PROTOCOL_CRC = 1789265863; + public static final int PROTOCOL_CRC = 701662755; public static final int PROTOCOL_VERSION = 2; - public static final int PROTOCOL_BUILD_NUMBER = 2; - public static final int PACKET_COUNT = 268; - public static final int STRUCT_COUNT = 314; + public static final int PROTOCOL_BUILD_NUMBER = 5; + public static final int PACKET_COUNT = 270; + public static final int STRUCT_COUNT = 318; public static final int ENUM_COUNT = 136; public static final int MAX_PACKET_SIZE = 1677721600; @@ -13,6 +13,6 @@ public final class ProtocolSettings { } public static boolean validateCrc(int crc) { - return 1789265863 == crc; + return 701662755 == crc; } } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateObjectiveTask.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateObjectiveTask.java index 0f07666f..6282a24e 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateObjectiveTask.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateObjectiveTask.java @@ -17,7 +17,7 @@ public class UpdateObjectiveTask implements Packet { public static final int FIXED_BLOCK_SIZE = 21; public static final int VARIABLE_FIELD_COUNT = 1; public static final int VARIABLE_BLOCK_START = 21; - public static final int MAX_SIZE = 16384035; + public static final int MAX_SIZE = 1677721600; @Nonnull public UUID objectiveUuid = new UUID(0L, 0L); public int taskIndex; diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityCollision.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityCollision.java new file mode 100644 index 00000000..e09e6ecd --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityCollision.java @@ -0,0 +1,151 @@ +package com.hypixel.hytale.protocol.packets.buildertools; + +import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.io.PacketIO; +import com.hypixel.hytale.protocol.io.ProtocolException; +import com.hypixel.hytale.protocol.io.ValidationResult; +import com.hypixel.hytale.protocol.io.VarInt; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class BuilderToolSetEntityCollision implements Packet { + public static final int PACKET_ID = 425; + public static final boolean IS_COMPRESSED = false; + public static final int NULLABLE_BIT_FIELD_SIZE = 1; + public static final int FIXED_BLOCK_SIZE = 5; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 5; + public static final int MAX_SIZE = 16384010; + public int entityId; + @Nullable + public String collisionType; + + @Override + public int getId() { + return 425; + } + + public BuilderToolSetEntityCollision() { + } + + public BuilderToolSetEntityCollision(int entityId, @Nullable String collisionType) { + this.entityId = entityId; + this.collisionType = collisionType; + } + + public BuilderToolSetEntityCollision(@Nonnull BuilderToolSetEntityCollision other) { + this.entityId = other.entityId; + this.collisionType = other.collisionType; + } + + @Nonnull + public static BuilderToolSetEntityCollision deserialize(@Nonnull ByteBuf buf, int offset) { + BuilderToolSetEntityCollision obj = new BuilderToolSetEntityCollision(); + byte nullBits = buf.getByte(offset); + obj.entityId = buf.getIntLE(offset + 1); + int pos = offset + 5; + if ((nullBits & 1) != 0) { + int collisionTypeLen = VarInt.peek(buf, pos); + if (collisionTypeLen < 0) { + throw ProtocolException.negativeLength("CollisionType", collisionTypeLen); + } + + if (collisionTypeLen > 4096000) { + throw ProtocolException.stringTooLong("CollisionType", collisionTypeLen, 4096000); + } + + int collisionTypeVarLen = VarInt.length(buf, pos); + obj.collisionType = PacketIO.readVarString(buf, pos, PacketIO.UTF8); + pos += collisionTypeVarLen + collisionTypeLen; + } + + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + byte nullBits = buf.getByte(offset); + int pos = offset + 5; + if ((nullBits & 1) != 0) { + int sl = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos) + sl; + } + + return pos - offset; + } + + @Override + public void serialize(@Nonnull ByteBuf buf) { + byte nullBits = 0; + if (this.collisionType != null) { + nullBits = (byte)(nullBits | 1); + } + + buf.writeByte(nullBits); + buf.writeIntLE(this.entityId); + if (this.collisionType != null) { + PacketIO.writeVarString(buf, this.collisionType, 4096000); + } + } + + @Override + public int computeSize() { + int size = 5; + if (this.collisionType != null) { + size += PacketIO.stringSize(this.collisionType); + } + + return size; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 5) { + return ValidationResult.error("Buffer too small: expected at least 5 bytes"); + } else { + byte nullBits = buffer.getByte(offset); + int pos = offset + 5; + if ((nullBits & 1) != 0) { + int collisionTypeLen = VarInt.peek(buffer, pos); + if (collisionTypeLen < 0) { + return ValidationResult.error("Invalid string length for CollisionType"); + } + + if (collisionTypeLen > 4096000) { + return ValidationResult.error("CollisionType exceeds max length 4096000"); + } + + pos += VarInt.length(buffer, pos); + pos += collisionTypeLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading CollisionType"); + } + } + + return ValidationResult.OK; + } + } + + public BuilderToolSetEntityCollision clone() { + BuilderToolSetEntityCollision copy = new BuilderToolSetEntityCollision(); + copy.entityId = this.entityId; + copy.collisionType = this.collisionType; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof BuilderToolSetEntityCollision other) + ? false + : this.entityId == other.entityId && Objects.equals(this.collisionType, other.collisionType); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.entityId, this.collisionType); + } +} diff --git a/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadProgress.java b/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadProgress.java index 044f540b..84e94c5d 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadProgress.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadProgress.java @@ -1,10 +1,8 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.FormattedMessage; import com.hypixel.hytale.protocol.Packet; -import com.hypixel.hytale.protocol.io.PacketIO; -import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; -import com.hypixel.hytale.protocol.io.VarInt; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; @@ -17,9 +15,9 @@ public class WorldLoadProgress implements Packet { public static final int FIXED_BLOCK_SIZE = 9; public static final int VARIABLE_FIELD_COUNT = 1; public static final int VARIABLE_BLOCK_START = 9; - public static final int MAX_SIZE = 16384014; + public static final int MAX_SIZE = 1677721600; @Nullable - public String status; + public FormattedMessage status; public int percentComplete; public int percentCompleteSubitem; @@ -31,7 +29,7 @@ public class WorldLoadProgress implements Packet { public WorldLoadProgress() { } - public WorldLoadProgress(@Nullable String status, int percentComplete, int percentCompleteSubitem) { + public WorldLoadProgress(@Nullable FormattedMessage status, int percentComplete, int percentCompleteSubitem) { this.status = status; this.percentComplete = percentComplete; this.percentCompleteSubitem = percentCompleteSubitem; @@ -51,18 +49,8 @@ public class WorldLoadProgress implements Packet { obj.percentCompleteSubitem = buf.getIntLE(offset + 5); int pos = offset + 9; if ((nullBits & 1) != 0) { - int statusLen = VarInt.peek(buf, pos); - if (statusLen < 0) { - throw ProtocolException.negativeLength("Status", statusLen); - } - - if (statusLen > 4096000) { - throw ProtocolException.stringTooLong("Status", statusLen, 4096000); - } - - int statusVarLen = VarInt.length(buf, pos); - obj.status = PacketIO.readVarString(buf, pos, PacketIO.UTF8); - pos += statusVarLen + statusLen; + obj.status = FormattedMessage.deserialize(buf, pos); + pos += FormattedMessage.computeBytesConsumed(buf, pos); } return obj; @@ -72,8 +60,7 @@ public class WorldLoadProgress implements Packet { byte nullBits = buf.getByte(offset); int pos = offset + 9; if ((nullBits & 1) != 0) { - int sl = VarInt.peek(buf, pos); - pos += VarInt.length(buf, pos) + sl; + pos += FormattedMessage.computeBytesConsumed(buf, pos); } return pos - offset; @@ -90,7 +77,7 @@ public class WorldLoadProgress implements Packet { buf.writeIntLE(this.percentComplete); buf.writeIntLE(this.percentCompleteSubitem); if (this.status != null) { - PacketIO.writeVarString(buf, this.status, 4096000); + this.status.serialize(buf); } } @@ -98,7 +85,7 @@ public class WorldLoadProgress implements Packet { public int computeSize() { int size = 9; if (this.status != null) { - size += PacketIO.stringSize(this.status); + size += this.status.computeSize(); } return size; @@ -111,20 +98,12 @@ public class WorldLoadProgress implements Packet { byte nullBits = buffer.getByte(offset); int pos = offset + 9; if ((nullBits & 1) != 0) { - int statusLen = VarInt.peek(buffer, pos); - if (statusLen < 0) { - return ValidationResult.error("Invalid string length for Status"); + ValidationResult statusResult = FormattedMessage.validateStructure(buffer, pos); + if (!statusResult.isValid()) { + return ValidationResult.error("Invalid Status: " + statusResult.error()); } - if (statusLen > 4096000) { - return ValidationResult.error("Status exceeds max length 4096000"); - } - - pos += VarInt.length(buffer, pos); - pos += statusLen; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Status"); - } + pos += FormattedMessage.computeBytesConsumed(buffer, pos); } return ValidationResult.OK; @@ -133,7 +112,7 @@ public class WorldLoadProgress implements Packet { public WorldLoadProgress clone() { WorldLoadProgress copy = new WorldLoadProgress(); - copy.status = this.status; + copy.status = this.status != null ? this.status.clone() : null; copy.percentComplete = this.percentComplete; copy.percentCompleteSubitem = this.percentCompleteSubitem; return copy; diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/CreateUserMarker.java b/src/com/hypixel/hytale/protocol/packets/worldmap/CreateUserMarker.java new file mode 100644 index 00000000..cf1039a3 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/CreateUserMarker.java @@ -0,0 +1,280 @@ +package com.hypixel.hytale.protocol.packets.worldmap; + +import com.hypixel.hytale.protocol.Color; +import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.io.PacketIO; +import com.hypixel.hytale.protocol.io.ProtocolException; +import com.hypixel.hytale.protocol.io.ValidationResult; +import com.hypixel.hytale.protocol.io.VarInt; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class CreateUserMarker implements Packet { + public static final int PACKET_ID = 246; + public static final boolean IS_COMPRESSED = false; + public static final int NULLABLE_BIT_FIELD_SIZE = 1; + public static final int FIXED_BLOCK_SIZE = 13; + public static final int VARIABLE_FIELD_COUNT = 2; + public static final int VARIABLE_BLOCK_START = 21; + public static final int MAX_SIZE = 32768031; + public float x; + public float z; + @Nullable + public String name; + @Nullable + public String markerImage; + @Nullable + public Color tintColor; + public boolean shared; + + @Override + public int getId() { + return 246; + } + + public CreateUserMarker() { + } + + public CreateUserMarker(float x, float z, @Nullable String name, @Nullable String markerImage, @Nullable Color tintColor, boolean shared) { + this.x = x; + this.z = z; + this.name = name; + this.markerImage = markerImage; + this.tintColor = tintColor; + this.shared = shared; + } + + public CreateUserMarker(@Nonnull CreateUserMarker other) { + this.x = other.x; + this.z = other.z; + this.name = other.name; + this.markerImage = other.markerImage; + this.tintColor = other.tintColor; + this.shared = other.shared; + } + + @Nonnull + public static CreateUserMarker deserialize(@Nonnull ByteBuf buf, int offset) { + CreateUserMarker obj = new CreateUserMarker(); + byte nullBits = buf.getByte(offset); + obj.x = buf.getFloatLE(offset + 1); + obj.z = buf.getFloatLE(offset + 5); + if ((nullBits & 1) != 0) { + obj.tintColor = Color.deserialize(buf, offset + 9); + } + + obj.shared = buf.getByte(offset + 12) != 0; + if ((nullBits & 2) != 0) { + int varPos0 = offset + 21 + buf.getIntLE(offset + 13); + int nameLen = VarInt.peek(buf, varPos0); + if (nameLen < 0) { + throw ProtocolException.negativeLength("Name", nameLen); + } + + if (nameLen > 4096000) { + throw ProtocolException.stringTooLong("Name", nameLen, 4096000); + } + + obj.name = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); + } + + if ((nullBits & 4) != 0) { + int varPos1 = offset + 21 + buf.getIntLE(offset + 17); + int markerImageLen = VarInt.peek(buf, varPos1); + if (markerImageLen < 0) { + throw ProtocolException.negativeLength("MarkerImage", markerImageLen); + } + + if (markerImageLen > 4096000) { + throw ProtocolException.stringTooLong("MarkerImage", markerImageLen, 4096000); + } + + obj.markerImage = PacketIO.readVarString(buf, varPos1, PacketIO.UTF8); + } + + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + byte nullBits = buf.getByte(offset); + int maxEnd = 21; + if ((nullBits & 2) != 0) { + int fieldOffset0 = buf.getIntLE(offset + 13); + int pos0 = offset + 21 + fieldOffset0; + int sl = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0) + sl; + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; + } + } + + if ((nullBits & 4) != 0) { + int fieldOffset1 = buf.getIntLE(offset + 17); + int pos1 = offset + 21 + fieldOffset1; + int sl = VarInt.peek(buf, pos1); + pos1 += VarInt.length(buf, pos1) + sl; + if (pos1 - offset > maxEnd) { + maxEnd = pos1 - offset; + } + } + + return maxEnd; + } + + @Override + public void serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + byte nullBits = 0; + if (this.tintColor != null) { + nullBits = (byte)(nullBits | 1); + } + + if (this.name != null) { + nullBits = (byte)(nullBits | 2); + } + + if (this.markerImage != null) { + nullBits = (byte)(nullBits | 4); + } + + buf.writeByte(nullBits); + buf.writeFloatLE(this.x); + buf.writeFloatLE(this.z); + if (this.tintColor != null) { + this.tintColor.serialize(buf); + } else { + buf.writeZero(3); + } + + buf.writeByte(this.shared ? 1 : 0); + int nameOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int markerImageOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int varBlockStart = buf.writerIndex(); + if (this.name != null) { + buf.setIntLE(nameOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.name, 4096000); + } else { + buf.setIntLE(nameOffsetSlot, -1); + } + + if (this.markerImage != null) { + buf.setIntLE(markerImageOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.markerImage, 4096000); + } else { + buf.setIntLE(markerImageOffsetSlot, -1); + } + } + + @Override + public int computeSize() { + int size = 21; + if (this.name != null) { + size += PacketIO.stringSize(this.name); + } + + if (this.markerImage != null) { + size += PacketIO.stringSize(this.markerImage); + } + + return size; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 21) { + return ValidationResult.error("Buffer too small: expected at least 21 bytes"); + } else { + byte nullBits = buffer.getByte(offset); + if ((nullBits & 2) != 0) { + int nameOffset = buffer.getIntLE(offset + 13); + if (nameOffset < 0) { + return ValidationResult.error("Invalid offset for Name"); + } + + int pos = offset + 21 + nameOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for Name"); + } + + int nameLen = VarInt.peek(buffer, pos); + if (nameLen < 0) { + return ValidationResult.error("Invalid string length for Name"); + } + + if (nameLen > 4096000) { + return ValidationResult.error("Name exceeds max length 4096000"); + } + + pos += VarInt.length(buffer, pos); + pos += nameLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading Name"); + } + } + + if ((nullBits & 4) != 0) { + int markerImageOffset = buffer.getIntLE(offset + 17); + if (markerImageOffset < 0) { + return ValidationResult.error("Invalid offset for MarkerImage"); + } + + int posx = offset + 21 + markerImageOffset; + if (posx >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for MarkerImage"); + } + + int markerImageLen = VarInt.peek(buffer, posx); + if (markerImageLen < 0) { + return ValidationResult.error("Invalid string length for MarkerImage"); + } + + if (markerImageLen > 4096000) { + return ValidationResult.error("MarkerImage exceeds max length 4096000"); + } + + posx += VarInt.length(buffer, posx); + posx += markerImageLen; + if (posx > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading MarkerImage"); + } + } + + return ValidationResult.OK; + } + } + + public CreateUserMarker clone() { + CreateUserMarker copy = new CreateUserMarker(); + copy.x = this.x; + copy.z = this.z; + copy.name = this.name; + copy.markerImage = this.markerImage; + copy.tintColor = this.tintColor != null ? this.tintColor.clone() : null; + copy.shared = this.shared; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof CreateUserMarker other) + ? false + : this.x == other.x + && this.z == other.z + && Objects.equals(this.name, other.name) + && Objects.equals(this.markerImage, other.markerImage) + && Objects.equals(this.tintColor, other.tintColor) + && this.shared == other.shared; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.x, this.z, this.name, this.markerImage, this.tintColor, this.shared); + } +} diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/HeightDeltaIconComponent.java b/src/com/hypixel/hytale/protocol/packets/worldmap/HeightDeltaIconComponent.java new file mode 100644 index 00000000..99637838 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/HeightDeltaIconComponent.java @@ -0,0 +1,246 @@ +package com.hypixel.hytale.protocol.packets.worldmap; + +import com.hypixel.hytale.protocol.io.PacketIO; +import com.hypixel.hytale.protocol.io.ProtocolException; +import com.hypixel.hytale.protocol.io.ValidationResult; +import com.hypixel.hytale.protocol.io.VarInt; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class HeightDeltaIconComponent extends MapMarkerComponent { + public static final int NULLABLE_BIT_FIELD_SIZE = 1; + public static final int FIXED_BLOCK_SIZE = 9; + public static final int VARIABLE_FIELD_COUNT = 2; + public static final int VARIABLE_BLOCK_START = 17; + public static final int MAX_SIZE = 32768027; + public int upDelta; + @Nullable + public String upImage; + public int downDelta; + @Nullable + public String downImage; + + public HeightDeltaIconComponent() { + } + + public HeightDeltaIconComponent(int upDelta, @Nullable String upImage, int downDelta, @Nullable String downImage) { + this.upDelta = upDelta; + this.upImage = upImage; + this.downDelta = downDelta; + this.downImage = downImage; + } + + public HeightDeltaIconComponent(@Nonnull HeightDeltaIconComponent other) { + this.upDelta = other.upDelta; + this.upImage = other.upImage; + this.downDelta = other.downDelta; + this.downImage = other.downImage; + } + + @Nonnull + public static HeightDeltaIconComponent deserialize(@Nonnull ByteBuf buf, int offset) { + HeightDeltaIconComponent obj = new HeightDeltaIconComponent(); + byte nullBits = buf.getByte(offset); + obj.upDelta = buf.getIntLE(offset + 1); + obj.downDelta = buf.getIntLE(offset + 5); + if ((nullBits & 1) != 0) { + int varPos0 = offset + 17 + buf.getIntLE(offset + 9); + int upImageLen = VarInt.peek(buf, varPos0); + if (upImageLen < 0) { + throw ProtocolException.negativeLength("UpImage", upImageLen); + } + + if (upImageLen > 4096000) { + throw ProtocolException.stringTooLong("UpImage", upImageLen, 4096000); + } + + obj.upImage = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); + } + + if ((nullBits & 2) != 0) { + int varPos1 = offset + 17 + buf.getIntLE(offset + 13); + int downImageLen = VarInt.peek(buf, varPos1); + if (downImageLen < 0) { + throw ProtocolException.negativeLength("DownImage", downImageLen); + } + + if (downImageLen > 4096000) { + throw ProtocolException.stringTooLong("DownImage", downImageLen, 4096000); + } + + obj.downImage = PacketIO.readVarString(buf, varPos1, PacketIO.UTF8); + } + + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + byte nullBits = buf.getByte(offset); + int maxEnd = 17; + if ((nullBits & 1) != 0) { + int fieldOffset0 = buf.getIntLE(offset + 9); + int pos0 = offset + 17 + fieldOffset0; + int sl = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0) + sl; + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; + } + } + + if ((nullBits & 2) != 0) { + int fieldOffset1 = buf.getIntLE(offset + 13); + int pos1 = offset + 17 + fieldOffset1; + int sl = VarInt.peek(buf, pos1); + pos1 += VarInt.length(buf, pos1) + sl; + if (pos1 - offset > maxEnd) { + maxEnd = pos1 - offset; + } + } + + return maxEnd; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + byte nullBits = 0; + if (this.upImage != null) { + nullBits = (byte)(nullBits | 1); + } + + if (this.downImage != null) { + nullBits = (byte)(nullBits | 2); + } + + buf.writeByte(nullBits); + buf.writeIntLE(this.upDelta); + buf.writeIntLE(this.downDelta); + int upImageOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int downImageOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int varBlockStart = buf.writerIndex(); + if (this.upImage != null) { + buf.setIntLE(upImageOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.upImage, 4096000); + } else { + buf.setIntLE(upImageOffsetSlot, -1); + } + + if (this.downImage != null) { + buf.setIntLE(downImageOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.downImage, 4096000); + } else { + buf.setIntLE(downImageOffsetSlot, -1); + } + + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + int size = 17; + if (this.upImage != null) { + size += PacketIO.stringSize(this.upImage); + } + + if (this.downImage != null) { + size += PacketIO.stringSize(this.downImage); + } + + return size; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 17) { + return ValidationResult.error("Buffer too small: expected at least 17 bytes"); + } else { + byte nullBits = buffer.getByte(offset); + if ((nullBits & 1) != 0) { + int upImageOffset = buffer.getIntLE(offset + 9); + if (upImageOffset < 0) { + return ValidationResult.error("Invalid offset for UpImage"); + } + + int pos = offset + 17 + upImageOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for UpImage"); + } + + int upImageLen = VarInt.peek(buffer, pos); + if (upImageLen < 0) { + return ValidationResult.error("Invalid string length for UpImage"); + } + + if (upImageLen > 4096000) { + return ValidationResult.error("UpImage exceeds max length 4096000"); + } + + pos += VarInt.length(buffer, pos); + pos += upImageLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading UpImage"); + } + } + + if ((nullBits & 2) != 0) { + int downImageOffset = buffer.getIntLE(offset + 13); + if (downImageOffset < 0) { + return ValidationResult.error("Invalid offset for DownImage"); + } + + int posx = offset + 17 + downImageOffset; + if (posx >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for DownImage"); + } + + int downImageLen = VarInt.peek(buffer, posx); + if (downImageLen < 0) { + return ValidationResult.error("Invalid string length for DownImage"); + } + + if (downImageLen > 4096000) { + return ValidationResult.error("DownImage exceeds max length 4096000"); + } + + posx += VarInt.length(buffer, posx); + posx += downImageLen; + if (posx > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading DownImage"); + } + } + + return ValidationResult.OK; + } + } + + public HeightDeltaIconComponent clone() { + HeightDeltaIconComponent copy = new HeightDeltaIconComponent(); + copy.upDelta = this.upDelta; + copy.upImage = this.upImage; + copy.downDelta = this.downDelta; + copy.downImage = this.downImage; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof HeightDeltaIconComponent other) + ? false + : this.upDelta == other.upDelta + && Objects.equals(this.upImage, other.upImage) + && this.downDelta == other.downDelta + && Objects.equals(this.downImage, other.downImage); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.upDelta, this.upImage, this.downDelta, this.downImage); + } +} diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/MapMarker.java b/src/com/hypixel/hytale/protocol/packets/worldmap/MapMarker.java index 2544b4fa..f25e1c67 100644 --- a/src/com/hypixel/hytale/protocol/packets/worldmap/MapMarker.java +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/MapMarker.java @@ -1,5 +1,6 @@ package com.hypixel.hytale.protocol.packets.worldmap; +import com.hypixel.hytale.protocol.FormattedMessage; import com.hypixel.hytale.protocol.Transform; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -14,164 +15,215 @@ import javax.annotation.Nullable; public class MapMarker { public static final int NULLABLE_BIT_FIELD_SIZE = 1; public static final int FIXED_BLOCK_SIZE = 38; - public static final int VARIABLE_FIELD_COUNT = 4; - public static final int VARIABLE_BLOCK_START = 54; + public static final int VARIABLE_FIELD_COUNT = 6; + public static final int VARIABLE_BLOCK_START = 62; public static final int MAX_SIZE = 1677721600; + @Nonnull + public String id = ""; @Nullable - public String id; + public FormattedMessage name; @Nullable - public String name; - @Nullable - public String markerImage; - @Nullable - public Transform transform; + public String customName; + @Nonnull + public String markerImage = ""; + @Nonnull + public Transform transform = new Transform(); @Nullable public ContextMenuItem[] contextMenuItems; + @Nullable + public MapMarkerComponent[] components; public MapMarker() { } public MapMarker( - @Nullable String id, @Nullable String name, @Nullable String markerImage, @Nullable Transform transform, @Nullable ContextMenuItem[] contextMenuItems + @Nonnull String id, + @Nullable FormattedMessage name, + @Nullable String customName, + @Nonnull String markerImage, + @Nonnull Transform transform, + @Nullable ContextMenuItem[] contextMenuItems, + @Nullable MapMarkerComponent[] components ) { this.id = id; this.name = name; + this.customName = customName; this.markerImage = markerImage; this.transform = transform; this.contextMenuItems = contextMenuItems; + this.components = components; } public MapMarker(@Nonnull MapMarker other) { this.id = other.id; this.name = other.name; + this.customName = other.customName; this.markerImage = other.markerImage; this.transform = other.transform; this.contextMenuItems = other.contextMenuItems; + this.components = other.components; } @Nonnull public static MapMarker deserialize(@Nonnull ByteBuf buf, int offset) { MapMarker obj = new MapMarker(); byte nullBits = buf.getByte(offset); - if ((nullBits & 1) != 0) { - obj.transform = Transform.deserialize(buf, offset + 1); - } - - if ((nullBits & 2) != 0) { - int varPos0 = offset + 54 + buf.getIntLE(offset + 38); - int idLen = VarInt.peek(buf, varPos0); - if (idLen < 0) { - throw ProtocolException.negativeLength("Id", idLen); - } - - if (idLen > 4096000) { - throw ProtocolException.stringTooLong("Id", idLen, 4096000); - } - + obj.transform = Transform.deserialize(buf, offset + 1); + int varPos0 = offset + 62 + buf.getIntLE(offset + 38); + int idLen = VarInt.peek(buf, varPos0); + if (idLen < 0) { + throw ProtocolException.negativeLength("Id", idLen); + } else if (idLen > 4096000) { + throw ProtocolException.stringTooLong("Id", idLen, 4096000); + } else { obj.id = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); - } - - if ((nullBits & 4) != 0) { - int varPos1 = offset + 54 + buf.getIntLE(offset + 42); - int nameLen = VarInt.peek(buf, varPos1); - if (nameLen < 0) { - throw ProtocolException.negativeLength("Name", nameLen); + if ((nullBits & 1) != 0) { + varPos0 = offset + 62 + buf.getIntLE(offset + 42); + obj.name = FormattedMessage.deserialize(buf, varPos0); } - if (nameLen > 4096000) { - throw ProtocolException.stringTooLong("Name", nameLen, 4096000); + if ((nullBits & 2) != 0) { + varPos0 = offset + 62 + buf.getIntLE(offset + 46); + idLen = VarInt.peek(buf, varPos0); + if (idLen < 0) { + throw ProtocolException.negativeLength("CustomName", idLen); + } + + if (idLen > 4096000) { + throw ProtocolException.stringTooLong("CustomName", idLen, 4096000); + } + + obj.customName = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); } - obj.name = PacketIO.readVarString(buf, varPos1, PacketIO.UTF8); - } + varPos0 = offset + 62 + buf.getIntLE(offset + 50); + idLen = VarInt.peek(buf, varPos0); + if (idLen < 0) { + throw ProtocolException.negativeLength("MarkerImage", idLen); + } else if (idLen > 4096000) { + throw ProtocolException.stringTooLong("MarkerImage", idLen, 4096000); + } else { + obj.markerImage = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); + if ((nullBits & 4) != 0) { + varPos0 = offset + 62 + buf.getIntLE(offset + 54); + idLen = VarInt.peek(buf, varPos0); + if (idLen < 0) { + throw ProtocolException.negativeLength("ContextMenuItems", idLen); + } - if ((nullBits & 8) != 0) { - int varPos2 = offset + 54 + buf.getIntLE(offset + 46); - int markerImageLen = VarInt.peek(buf, varPos2); - if (markerImageLen < 0) { - throw ProtocolException.negativeLength("MarkerImage", markerImageLen); - } + if (idLen > 4096000) { + throw ProtocolException.arrayTooLong("ContextMenuItems", idLen, 4096000); + } - if (markerImageLen > 4096000) { - throw ProtocolException.stringTooLong("MarkerImage", markerImageLen, 4096000); - } + int varIntLen = VarInt.length(buf, varPos0); + if (varPos0 + varIntLen + idLen * 0L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("ContextMenuItems", varPos0 + varIntLen + idLen * 0, buf.readableBytes()); + } - obj.markerImage = PacketIO.readVarString(buf, varPos2, PacketIO.UTF8); - } + obj.contextMenuItems = new ContextMenuItem[idLen]; + int elemPos = varPos0 + varIntLen; - if ((nullBits & 16) != 0) { - int varPos3 = offset + 54 + buf.getIntLE(offset + 50); - int contextMenuItemsCount = VarInt.peek(buf, varPos3); - if (contextMenuItemsCount < 0) { - throw ProtocolException.negativeLength("ContextMenuItems", contextMenuItemsCount); - } + for (int i = 0; i < idLen; i++) { + obj.contextMenuItems[i] = ContextMenuItem.deserialize(buf, elemPos); + elemPos += ContextMenuItem.computeBytesConsumed(buf, elemPos); + } + } - if (contextMenuItemsCount > 4096000) { - throw ProtocolException.arrayTooLong("ContextMenuItems", contextMenuItemsCount, 4096000); - } + if ((nullBits & 8) != 0) { + varPos0 = offset + 62 + buf.getIntLE(offset + 58); + idLen = VarInt.peek(buf, varPos0); + if (idLen < 0) { + throw ProtocolException.negativeLength("Components", idLen); + } - int varIntLen = VarInt.length(buf, varPos3); - if (varPos3 + varIntLen + contextMenuItemsCount * 0L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall("ContextMenuItems", varPos3 + varIntLen + contextMenuItemsCount * 0, buf.readableBytes()); - } + if (idLen > 4096000) { + throw ProtocolException.arrayTooLong("Components", idLen, 4096000); + } - obj.contextMenuItems = new ContextMenuItem[contextMenuItemsCount]; - int elemPos = varPos3 + varIntLen; + int varIntLen = VarInt.length(buf, varPos0); + if (varPos0 + varIntLen + idLen * 1L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("Components", varPos0 + varIntLen + idLen * 1, buf.readableBytes()); + } - for (int i = 0; i < contextMenuItemsCount; i++) { - obj.contextMenuItems[i] = ContextMenuItem.deserialize(buf, elemPos); - elemPos += ContextMenuItem.computeBytesConsumed(buf, elemPos); + obj.components = new MapMarkerComponent[idLen]; + int elemPos = varPos0 + varIntLen; + + for (int i = 0; i < idLen; i++) { + obj.components[i] = MapMarkerComponent.deserialize(buf, elemPos); + elemPos += MapMarkerComponent.computeBytesConsumed(buf, elemPos); + } + } + + return obj; } } - - return obj; } public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte nullBits = buf.getByte(offset); - int maxEnd = 54; + int maxEnd = 62; + int fieldOffset0 = buf.getIntLE(offset + 38); + int pos0 = offset + 62 + fieldOffset0; + int sl = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0) + sl; + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; + } + + if ((nullBits & 1) != 0) { + fieldOffset0 = buf.getIntLE(offset + 42); + pos0 = offset + 62 + fieldOffset0; + pos0 += FormattedMessage.computeBytesConsumed(buf, pos0); + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; + } + } + if ((nullBits & 2) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 38); - int pos0 = offset + 54 + fieldOffset0; - int sl = VarInt.peek(buf, pos0); + fieldOffset0 = buf.getIntLE(offset + 46); + pos0 = offset + 62 + fieldOffset0; + sl = VarInt.peek(buf, pos0); pos0 += VarInt.length(buf, pos0) + sl; if (pos0 - offset > maxEnd) { maxEnd = pos0 - offset; } } + fieldOffset0 = buf.getIntLE(offset + 50); + pos0 = offset + 62 + fieldOffset0; + sl = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0) + sl; + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; + } + if ((nullBits & 4) != 0) { - int fieldOffset1 = buf.getIntLE(offset + 42); - int pos1 = offset + 54 + fieldOffset1; - int sl = VarInt.peek(buf, pos1); - pos1 += VarInt.length(buf, pos1) + sl; - if (pos1 - offset > maxEnd) { - maxEnd = pos1 - offset; + fieldOffset0 = buf.getIntLE(offset + 54); + pos0 = offset + 62 + fieldOffset0; + sl = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0); + + for (int i = 0; i < sl; i++) { + pos0 += ContextMenuItem.computeBytesConsumed(buf, pos0); + } + + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; } } if ((nullBits & 8) != 0) { - int fieldOffset2 = buf.getIntLE(offset + 46); - int pos2 = offset + 54 + fieldOffset2; - int sl = VarInt.peek(buf, pos2); - pos2 += VarInt.length(buf, pos2) + sl; - if (pos2 - offset > maxEnd) { - maxEnd = pos2 - offset; - } - } + fieldOffset0 = buf.getIntLE(offset + 58); + pos0 = offset + 62 + fieldOffset0; + sl = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0); - if ((nullBits & 16) != 0) { - int fieldOffset3 = buf.getIntLE(offset + 50); - int pos3 = offset + 54 + fieldOffset3; - int arrLen = VarInt.peek(buf, pos3); - pos3 += VarInt.length(buf, pos3); - - for (int i = 0; i < arrLen; i++) { - pos3 += ContextMenuItem.computeBytesConsumed(buf, pos3); + for (int i = 0; i < sl; i++) { + pos0 += MapMarkerComponent.computeBytesConsumed(buf, pos0); } - if (pos3 - offset > maxEnd) { - maxEnd = pos3 - offset; + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; } } @@ -181,63 +233,55 @@ public class MapMarker { public void serialize(@Nonnull ByteBuf buf) { int startPos = buf.writerIndex(); byte nullBits = 0; - if (this.transform != null) { + if (this.name != null) { nullBits = (byte)(nullBits | 1); } - if (this.id != null) { + if (this.customName != null) { nullBits = (byte)(nullBits | 2); } - if (this.name != null) { + if (this.contextMenuItems != null) { nullBits = (byte)(nullBits | 4); } - if (this.markerImage != null) { + if (this.components != null) { nullBits = (byte)(nullBits | 8); } - if (this.contextMenuItems != null) { - nullBits = (byte)(nullBits | 16); - } - buf.writeByte(nullBits); - if (this.transform != null) { - this.transform.serialize(buf); - } else { - buf.writeZero(37); - } - + this.transform.serialize(buf); int idOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); int nameOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); + int customNameOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); int markerImageOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); int contextMenuItemsOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); + int componentsOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); int varBlockStart = buf.writerIndex(); - if (this.id != null) { - buf.setIntLE(idOffsetSlot, buf.writerIndex() - varBlockStart); - PacketIO.writeVarString(buf, this.id, 4096000); - } else { - buf.setIntLE(idOffsetSlot, -1); - } - + buf.setIntLE(idOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.id, 4096000); if (this.name != null) { buf.setIntLE(nameOffsetSlot, buf.writerIndex() - varBlockStart); - PacketIO.writeVarString(buf, this.name, 4096000); + this.name.serialize(buf); } else { buf.setIntLE(nameOffsetSlot, -1); } - if (this.markerImage != null) { - buf.setIntLE(markerImageOffsetSlot, buf.writerIndex() - varBlockStart); - PacketIO.writeVarString(buf, this.markerImage, 4096000); + if (this.customName != null) { + buf.setIntLE(customNameOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.customName, 4096000); } else { - buf.setIntLE(markerImageOffsetSlot, -1); + buf.setIntLE(customNameOffsetSlot, -1); } + buf.setIntLE(markerImageOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.markerImage, 4096000); if (this.contextMenuItems != null) { buf.setIntLE(contextMenuItemsOffsetSlot, buf.writerIndex() - varBlockStart); if (this.contextMenuItems.length > 4096000) { @@ -252,22 +296,35 @@ public class MapMarker { } else { buf.setIntLE(contextMenuItemsOffsetSlot, -1); } + + if (this.components != null) { + buf.setIntLE(componentsOffsetSlot, buf.writerIndex() - varBlockStart); + if (this.components.length > 4096000) { + throw ProtocolException.arrayTooLong("Components", this.components.length, 4096000); + } + + VarInt.write(buf, this.components.length); + + for (MapMarkerComponent item : this.components) { + item.serializeWithTypeId(buf); + } + } else { + buf.setIntLE(componentsOffsetSlot, -1); + } } public int computeSize() { - int size = 54; - if (this.id != null) { - size += PacketIO.stringSize(this.id); - } - + int size = 62; + size += PacketIO.stringSize(this.id); if (this.name != null) { - size += PacketIO.stringSize(this.name); + size += this.name.computeSize(); } - if (this.markerImage != null) { - size += PacketIO.stringSize(this.markerImage); + if (this.customName != null) { + size += PacketIO.stringSize(this.customName); } + size += PacketIO.stringSize(this.markerImage); if (this.contextMenuItems != null) { int contextMenuItemsSize = 0; @@ -278,138 +335,193 @@ public class MapMarker { size += VarInt.size(this.contextMenuItems.length) + contextMenuItemsSize; } + if (this.components != null) { + int componentsSize = 0; + + for (MapMarkerComponent elem : this.components) { + componentsSize += elem.computeSizeWithTypeId(); + } + + size += VarInt.size(this.components.length) + componentsSize; + } + return size; } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 54) { - return ValidationResult.error("Buffer too small: expected at least 54 bytes"); + if (buffer.readableBytes() - offset < 62) { + return ValidationResult.error("Buffer too small: expected at least 62 bytes"); } else { byte nullBits = buffer.getByte(offset); - if ((nullBits & 2) != 0) { - int idOffset = buffer.getIntLE(offset + 38); - if (idOffset < 0) { - return ValidationResult.error("Invalid offset for Id"); - } - - int pos = offset + 54 + idOffset; + int idOffset = buffer.getIntLE(offset + 38); + if (idOffset < 0) { + return ValidationResult.error("Invalid offset for Id"); + } else { + int pos = offset + 62 + idOffset; if (pos >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Id"); - } + } else { + int idLen = VarInt.peek(buffer, pos); + if (idLen < 0) { + return ValidationResult.error("Invalid string length for Id"); + } else if (idLen > 4096000) { + return ValidationResult.error("Id exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + pos += idLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading Id"); + } else { + if ((nullBits & 1) != 0) { + idOffset = buffer.getIntLE(offset + 42); + if (idOffset < 0) { + return ValidationResult.error("Invalid offset for Name"); + } - int idLen = VarInt.peek(buffer, pos); - if (idLen < 0) { - return ValidationResult.error("Invalid string length for Id"); - } + pos = offset + 62 + idOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for Name"); + } - if (idLen > 4096000) { - return ValidationResult.error("Id exceeds max length 4096000"); - } + ValidationResult nameResult = FormattedMessage.validateStructure(buffer, pos); + if (!nameResult.isValid()) { + return ValidationResult.error("Invalid Name: " + nameResult.error()); + } - pos += VarInt.length(buffer, pos); - pos += idLen; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Id"); - } - } + pos += FormattedMessage.computeBytesConsumed(buffer, pos); + } - if ((nullBits & 4) != 0) { - int nameOffset = buffer.getIntLE(offset + 42); - if (nameOffset < 0) { - return ValidationResult.error("Invalid offset for Name"); - } + if ((nullBits & 2) != 0) { + idOffset = buffer.getIntLE(offset + 46); + if (idOffset < 0) { + return ValidationResult.error("Invalid offset for CustomName"); + } - int posx = offset + 54 + nameOffset; - if (posx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Name"); - } + pos = offset + 62 + idOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for CustomName"); + } - int nameLen = VarInt.peek(buffer, posx); - if (nameLen < 0) { - return ValidationResult.error("Invalid string length for Name"); - } + idLen = VarInt.peek(buffer, pos); + if (idLen < 0) { + return ValidationResult.error("Invalid string length for CustomName"); + } - if (nameLen > 4096000) { - return ValidationResult.error("Name exceeds max length 4096000"); - } + if (idLen > 4096000) { + return ValidationResult.error("CustomName exceeds max length 4096000"); + } - posx += VarInt.length(buffer, posx); - posx += nameLen; - if (posx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Name"); - } - } + pos += VarInt.length(buffer, pos); + pos += idLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading CustomName"); + } + } - if ((nullBits & 8) != 0) { - int markerImageOffset = buffer.getIntLE(offset + 46); - if (markerImageOffset < 0) { - return ValidationResult.error("Invalid offset for MarkerImage"); - } + idOffset = buffer.getIntLE(offset + 50); + if (idOffset < 0) { + return ValidationResult.error("Invalid offset for MarkerImage"); + } else { + pos = offset + 62 + idOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for MarkerImage"); + } else { + idLen = VarInt.peek(buffer, pos); + if (idLen < 0) { + return ValidationResult.error("Invalid string length for MarkerImage"); + } else if (idLen > 4096000) { + return ValidationResult.error("MarkerImage exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + pos += idLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading MarkerImage"); + } else { + if ((nullBits & 4) != 0) { + idOffset = buffer.getIntLE(offset + 54); + if (idOffset < 0) { + return ValidationResult.error("Invalid offset for ContextMenuItems"); + } - int posxx = offset + 54 + markerImageOffset; - if (posxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for MarkerImage"); - } + pos = offset + 62 + idOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for ContextMenuItems"); + } - int markerImageLen = VarInt.peek(buffer, posxx); - if (markerImageLen < 0) { - return ValidationResult.error("Invalid string length for MarkerImage"); - } + idLen = VarInt.peek(buffer, pos); + if (idLen < 0) { + return ValidationResult.error("Invalid array count for ContextMenuItems"); + } - if (markerImageLen > 4096000) { - return ValidationResult.error("MarkerImage exceeds max length 4096000"); - } + if (idLen > 4096000) { + return ValidationResult.error("ContextMenuItems exceeds max length 4096000"); + } - posxx += VarInt.length(buffer, posxx); - posxx += markerImageLen; - if (posxx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading MarkerImage"); - } - } + pos += VarInt.length(buffer, pos); - if ((nullBits & 16) != 0) { - int contextMenuItemsOffset = buffer.getIntLE(offset + 50); - if (contextMenuItemsOffset < 0) { - return ValidationResult.error("Invalid offset for ContextMenuItems"); - } + for (int i = 0; i < idLen; i++) { + ValidationResult structResult = ContextMenuItem.validateStructure(buffer, pos); + if (!structResult.isValid()) { + return ValidationResult.error("Invalid ContextMenuItem in ContextMenuItems[" + i + "]: " + structResult.error()); + } - int posxxx = offset + 54 + contextMenuItemsOffset; - if (posxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for ContextMenuItems"); - } + pos += ContextMenuItem.computeBytesConsumed(buffer, pos); + } + } - int contextMenuItemsCount = VarInt.peek(buffer, posxxx); - if (contextMenuItemsCount < 0) { - return ValidationResult.error("Invalid array count for ContextMenuItems"); - } + if ((nullBits & 8) != 0) { + idOffset = buffer.getIntLE(offset + 58); + if (idOffset < 0) { + return ValidationResult.error("Invalid offset for Components"); + } - if (contextMenuItemsCount > 4096000) { - return ValidationResult.error("ContextMenuItems exceeds max length 4096000"); - } + pos = offset + 62 + idOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for Components"); + } - posxxx += VarInt.length(buffer, posxxx); + idLen = VarInt.peek(buffer, pos); + if (idLen < 0) { + return ValidationResult.error("Invalid array count for Components"); + } - for (int i = 0; i < contextMenuItemsCount; i++) { - ValidationResult structResult = ContextMenuItem.validateStructure(buffer, posxxx); - if (!structResult.isValid()) { - return ValidationResult.error("Invalid ContextMenuItem in ContextMenuItems[" + i + "]: " + structResult.error()); + if (idLen > 4096000) { + return ValidationResult.error("Components exceeds max length 4096000"); + } + + pos += VarInt.length(buffer, pos); + + for (int i = 0; i < idLen; i++) { + ValidationResult structResult = MapMarkerComponent.validateStructure(buffer, pos); + if (!structResult.isValid()) { + return ValidationResult.error("Invalid MapMarkerComponent in Components[" + i + "]: " + structResult.error()); + } + + pos += MapMarkerComponent.computeBytesConsumed(buffer, pos); + } + } + + return ValidationResult.OK; + } + } + } + } + } } - - posxxx += ContextMenuItem.computeBytesConsumed(buffer, posxxx); } } - - return ValidationResult.OK; } } public MapMarker clone() { MapMarker copy = new MapMarker(); copy.id = this.id; - copy.name = this.name; + copy.name = this.name != null ? this.name.clone() : null; + copy.customName = this.customName; copy.markerImage = this.markerImage; - copy.transform = this.transform != null ? this.transform.clone() : null; + copy.transform = this.transform.clone(); copy.contextMenuItems = this.contextMenuItems != null ? Arrays.stream(this.contextMenuItems).map(e -> e.clone()).toArray(ContextMenuItem[]::new) : null; + copy.components = this.components != null ? Arrays.copyOf(this.components, this.components.length) : null; return copy; } @@ -422,9 +534,11 @@ public class MapMarker { ? false : Objects.equals(this.id, other.id) && Objects.equals(this.name, other.name) + && Objects.equals(this.customName, other.customName) && Objects.equals(this.markerImage, other.markerImage) && Objects.equals(this.transform, other.transform) - && Arrays.equals((Object[])this.contextMenuItems, (Object[])other.contextMenuItems); + && Arrays.equals((Object[])this.contextMenuItems, (Object[])other.contextMenuItems) + && Arrays.equals((Object[])this.components, (Object[])other.components); } } @@ -433,8 +547,10 @@ public class MapMarker { int result = 1; result = 31 * result + Objects.hashCode(this.id); result = 31 * result + Objects.hashCode(this.name); + result = 31 * result + Objects.hashCode(this.customName); result = 31 * result + Objects.hashCode(this.markerImage); result = 31 * result + Objects.hashCode(this.transform); - return 31 * result + Arrays.hashCode((Object[])this.contextMenuItems); + result = 31 * result + Arrays.hashCode((Object[])this.contextMenuItems); + return 31 * result + Arrays.hashCode((Object[])this.components); } } diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/MapMarkerComponent.java b/src/com/hypixel/hytale/protocol/packets/worldmap/MapMarkerComponent.java new file mode 100644 index 00000000..71b592d5 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/MapMarkerComponent.java @@ -0,0 +1,80 @@ +package com.hypixel.hytale.protocol.packets.worldmap; + +import com.hypixel.hytale.protocol.io.ProtocolException; +import com.hypixel.hytale.protocol.io.ValidationResult; +import com.hypixel.hytale.protocol.io.VarInt; +import io.netty.buffer.ByteBuf; +import javax.annotation.Nonnull; + +public abstract class MapMarkerComponent { + public static final int MAX_SIZE = 1677721605; + + @Nonnull + public static MapMarkerComponent deserialize(@Nonnull ByteBuf buf, int offset) { + int typeId = VarInt.peek(buf, offset); + int typeIdLen = VarInt.length(buf, offset); + + return (MapMarkerComponent)(switch (typeId) { + case 0 -> PlayerMarkerComponent.deserialize(buf, offset + typeIdLen); + case 1 -> PlacedByMarkerComponent.deserialize(buf, offset + typeIdLen); + case 2 -> HeightDeltaIconComponent.deserialize(buf, offset + typeIdLen); + case 3 -> TintComponent.deserialize(buf, offset + typeIdLen); + default -> throw ProtocolException.unknownPolymorphicType("MapMarkerComponent", typeId); + }); + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int typeId = VarInt.peek(buf, offset); + int typeIdLen = VarInt.length(buf, offset); + + return typeIdLen + switch (typeId) { + case 0 -> PlayerMarkerComponent.computeBytesConsumed(buf, offset + typeIdLen); + case 1 -> PlacedByMarkerComponent.computeBytesConsumed(buf, offset + typeIdLen); + case 2 -> HeightDeltaIconComponent.computeBytesConsumed(buf, offset + typeIdLen); + case 3 -> TintComponent.computeBytesConsumed(buf, offset + typeIdLen); + default -> throw ProtocolException.unknownPolymorphicType("MapMarkerComponent", typeId); + }; + } + + public int getTypeId() { + if (this instanceof PlayerMarkerComponent sub) { + return 0; + } else if (this instanceof PlacedByMarkerComponent sub) { + return 1; + } else if (this instanceof HeightDeltaIconComponent sub) { + return 2; + } else if (this instanceof TintComponent sub) { + return 3; + } else { + throw new IllegalStateException("Unknown subtype: " + this.getClass().getName()); + } + } + + public abstract int serialize(@Nonnull ByteBuf var1); + + public abstract int computeSize(); + + public int serializeWithTypeId(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + VarInt.write(buf, this.getTypeId()); + this.serialize(buf); + return buf.writerIndex() - startPos; + } + + public int computeSizeWithTypeId() { + return VarInt.size(this.getTypeId()) + this.computeSize(); + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + int typeId = VarInt.peek(buffer, offset); + int typeIdLen = VarInt.length(buffer, offset); + + return switch (typeId) { + case 0 -> PlayerMarkerComponent.validateStructure(buffer, offset + typeIdLen); + case 1 -> PlacedByMarkerComponent.validateStructure(buffer, offset + typeIdLen); + case 2 -> HeightDeltaIconComponent.validateStructure(buffer, offset + typeIdLen); + case 3 -> TintComponent.validateStructure(buffer, offset + typeIdLen); + default -> ValidationResult.error("Unknown polymorphic type ID " + typeId + " for MapMarkerComponent"); + }; + } +} diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/PlacedByMarkerComponent.java b/src/com/hypixel/hytale/protocol/packets/worldmap/PlacedByMarkerComponent.java new file mode 100644 index 00000000..0d0ce6b3 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/PlacedByMarkerComponent.java @@ -0,0 +1,102 @@ +package com.hypixel.hytale.protocol.packets.worldmap; + +import com.hypixel.hytale.protocol.FormattedMessage; +import com.hypixel.hytale.protocol.io.PacketIO; +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import java.util.UUID; +import javax.annotation.Nonnull; + +public class PlacedByMarkerComponent extends MapMarkerComponent { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 16; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 16; + public static final int MAX_SIZE = 1677721600; + @Nonnull + public FormattedMessage name = new FormattedMessage(); + @Nonnull + public UUID playerId = new UUID(0L, 0L); + + public PlacedByMarkerComponent() { + } + + public PlacedByMarkerComponent(@Nonnull FormattedMessage name, @Nonnull UUID playerId) { + this.name = name; + this.playerId = playerId; + } + + public PlacedByMarkerComponent(@Nonnull PlacedByMarkerComponent other) { + this.name = other.name; + this.playerId = other.playerId; + } + + @Nonnull + public static PlacedByMarkerComponent deserialize(@Nonnull ByteBuf buf, int offset) { + PlacedByMarkerComponent obj = new PlacedByMarkerComponent(); + obj.playerId = PacketIO.readUUID(buf, offset + 0); + int pos = offset + 16; + obj.name = FormattedMessage.deserialize(buf, pos); + pos += FormattedMessage.computeBytesConsumed(buf, pos); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int pos = offset + 16; + pos += FormattedMessage.computeBytesConsumed(buf, pos); + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + PacketIO.writeUUID(buf, this.playerId); + this.name.serialize(buf); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + int size = 16; + return size + this.name.computeSize(); + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 16) { + return ValidationResult.error("Buffer too small: expected at least 16 bytes"); + } else { + int pos = offset + 16; + ValidationResult nameResult = FormattedMessage.validateStructure(buffer, pos); + if (!nameResult.isValid()) { + return ValidationResult.error("Invalid Name: " + nameResult.error()); + } else { + pos += FormattedMessage.computeBytesConsumed(buffer, pos); + return ValidationResult.OK; + } + } + } + + public PlacedByMarkerComponent clone() { + PlacedByMarkerComponent copy = new PlacedByMarkerComponent(); + copy.name = this.name.clone(); + copy.playerId = this.playerId; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof PlacedByMarkerComponent other) + ? false + : Objects.equals(this.name, other.name) && Objects.equals(this.playerId, other.playerId); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.name, this.playerId); + } +} diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/PlayerMarkerComponent.java b/src/com/hypixel/hytale/protocol/packets/worldmap/PlayerMarkerComponent.java new file mode 100644 index 00000000..0b74b8d6 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/PlayerMarkerComponent.java @@ -0,0 +1,76 @@ +package com.hypixel.hytale.protocol.packets.worldmap; + +import com.hypixel.hytale.protocol.io.PacketIO; +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import java.util.UUID; +import javax.annotation.Nonnull; + +public class PlayerMarkerComponent extends MapMarkerComponent { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 16; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 16; + public static final int MAX_SIZE = 16; + @Nonnull + public UUID playerId = new UUID(0L, 0L); + + public PlayerMarkerComponent() { + } + + public PlayerMarkerComponent(@Nonnull UUID playerId) { + this.playerId = playerId; + } + + public PlayerMarkerComponent(@Nonnull PlayerMarkerComponent other) { + this.playerId = other.playerId; + } + + @Nonnull + public static PlayerMarkerComponent deserialize(@Nonnull ByteBuf buf, int offset) { + PlayerMarkerComponent obj = new PlayerMarkerComponent(); + obj.playerId = PacketIO.readUUID(buf, offset + 0); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 16; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + PacketIO.writeUUID(buf, this.playerId); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 16; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 16 ? ValidationResult.error("Buffer too small: expected at least 16 bytes") : ValidationResult.OK; + } + + public PlayerMarkerComponent clone() { + PlayerMarkerComponent copy = new PlayerMarkerComponent(); + copy.playerId = this.playerId; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof PlayerMarkerComponent other ? Objects.equals(this.playerId, other.playerId) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.playerId); + } +} diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/TintComponent.java b/src/com/hypixel/hytale/protocol/packets/worldmap/TintComponent.java new file mode 100644 index 00000000..d13b3f63 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/TintComponent.java @@ -0,0 +1,75 @@ +package com.hypixel.hytale.protocol.packets.worldmap; + +import com.hypixel.hytale.protocol.Color; +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; + +public class TintComponent extends MapMarkerComponent { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 3; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 3; + public static final int MAX_SIZE = 3; + @Nonnull + public Color color = new Color(); + + public TintComponent() { + } + + public TintComponent(@Nonnull Color color) { + this.color = color; + } + + public TintComponent(@Nonnull TintComponent other) { + this.color = other.color; + } + + @Nonnull + public static TintComponent deserialize(@Nonnull ByteBuf buf, int offset) { + TintComponent obj = new TintComponent(); + obj.color = Color.deserialize(buf, offset + 0); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 3; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + this.color.serialize(buf); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 3; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 3 ? ValidationResult.error("Buffer too small: expected at least 3 bytes") : ValidationResult.OK; + } + + public TintComponent clone() { + TintComponent copy = new TintComponent(); + copy.color = this.color.clone(); + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof TintComponent other ? Objects.equals(this.color, other.color) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.color); + } +} diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapSettings.java b/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapSettings.java index 65c0d3ec..4a8eb0c2 100644 --- a/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapSettings.java +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapSettings.java @@ -16,15 +16,19 @@ public class UpdateWorldMapSettings implements Packet { public static final int PACKET_ID = 240; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; - public static final int FIXED_BLOCK_SIZE = 16; + public static final int FIXED_BLOCK_SIZE = 20; public static final int VARIABLE_FIELD_COUNT = 1; - public static final int VARIABLE_BLOCK_START = 16; + public static final int VARIABLE_BLOCK_START = 20; public static final int MAX_SIZE = 1677721600; public boolean enabled = true; @Nullable public Map biomeDataMap; public boolean allowTeleportToCoordinates; public boolean allowTeleportToMarkers; + public boolean allowShowOnMapToggle; + public boolean allowCompassTrackingToggle; + public boolean allowCreatingMapMarkers; + public boolean allowRemovingOtherPlayersMarkers; public float defaultScale = 32.0F; public float minScale = 2.0F; public float maxScale = 256.0F; @@ -42,6 +46,10 @@ public class UpdateWorldMapSettings implements Packet { @Nullable Map biomeDataMap, boolean allowTeleportToCoordinates, boolean allowTeleportToMarkers, + boolean allowShowOnMapToggle, + boolean allowCompassTrackingToggle, + boolean allowCreatingMapMarkers, + boolean allowRemovingOtherPlayersMarkers, float defaultScale, float minScale, float maxScale @@ -50,6 +58,10 @@ public class UpdateWorldMapSettings implements Packet { this.biomeDataMap = biomeDataMap; this.allowTeleportToCoordinates = allowTeleportToCoordinates; this.allowTeleportToMarkers = allowTeleportToMarkers; + this.allowShowOnMapToggle = allowShowOnMapToggle; + this.allowCompassTrackingToggle = allowCompassTrackingToggle; + this.allowCreatingMapMarkers = allowCreatingMapMarkers; + this.allowRemovingOtherPlayersMarkers = allowRemovingOtherPlayersMarkers; this.defaultScale = defaultScale; this.minScale = minScale; this.maxScale = maxScale; @@ -60,6 +72,10 @@ public class UpdateWorldMapSettings implements Packet { this.biomeDataMap = other.biomeDataMap; this.allowTeleportToCoordinates = other.allowTeleportToCoordinates; this.allowTeleportToMarkers = other.allowTeleportToMarkers; + this.allowShowOnMapToggle = other.allowShowOnMapToggle; + this.allowCompassTrackingToggle = other.allowCompassTrackingToggle; + this.allowCreatingMapMarkers = other.allowCreatingMapMarkers; + this.allowRemovingOtherPlayersMarkers = other.allowRemovingOtherPlayersMarkers; this.defaultScale = other.defaultScale; this.minScale = other.minScale; this.maxScale = other.maxScale; @@ -72,10 +88,14 @@ public class UpdateWorldMapSettings implements Packet { obj.enabled = buf.getByte(offset + 1) != 0; obj.allowTeleportToCoordinates = buf.getByte(offset + 2) != 0; obj.allowTeleportToMarkers = buf.getByte(offset + 3) != 0; - obj.defaultScale = buf.getFloatLE(offset + 4); - obj.minScale = buf.getFloatLE(offset + 8); - obj.maxScale = buf.getFloatLE(offset + 12); - int pos = offset + 16; + obj.allowShowOnMapToggle = buf.getByte(offset + 4) != 0; + obj.allowCompassTrackingToggle = buf.getByte(offset + 5) != 0; + obj.allowCreatingMapMarkers = buf.getByte(offset + 6) != 0; + obj.allowRemovingOtherPlayersMarkers = buf.getByte(offset + 7) != 0; + obj.defaultScale = buf.getFloatLE(offset + 8); + obj.minScale = buf.getFloatLE(offset + 12); + obj.maxScale = buf.getFloatLE(offset + 16); + int pos = offset + 20; if ((nullBits & 1) != 0) { int biomeDataMapCount = VarInt.peek(buf, pos); if (biomeDataMapCount < 0) { @@ -105,7 +125,7 @@ public class UpdateWorldMapSettings implements Packet { public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte nullBits = buf.getByte(offset); - int pos = offset + 16; + int pos = offset + 20; if ((nullBits & 1) != 0) { int dictLen = VarInt.peek(buf, pos); pos += VarInt.length(buf, pos); @@ -130,6 +150,10 @@ public class UpdateWorldMapSettings implements Packet { buf.writeByte(this.enabled ? 1 : 0); buf.writeByte(this.allowTeleportToCoordinates ? 1 : 0); buf.writeByte(this.allowTeleportToMarkers ? 1 : 0); + buf.writeByte(this.allowShowOnMapToggle ? 1 : 0); + buf.writeByte(this.allowCompassTrackingToggle ? 1 : 0); + buf.writeByte(this.allowCreatingMapMarkers ? 1 : 0); + buf.writeByte(this.allowRemovingOtherPlayersMarkers ? 1 : 0); buf.writeFloatLE(this.defaultScale); buf.writeFloatLE(this.minScale); buf.writeFloatLE(this.maxScale); @@ -149,7 +173,7 @@ public class UpdateWorldMapSettings implements Packet { @Override public int computeSize() { - int size = 16; + int size = 20; if (this.biomeDataMap != null) { int biomeDataMapSize = 0; @@ -164,11 +188,11 @@ public class UpdateWorldMapSettings implements Packet { } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 16) { - return ValidationResult.error("Buffer too small: expected at least 16 bytes"); + if (buffer.readableBytes() - offset < 20) { + return ValidationResult.error("Buffer too small: expected at least 20 bytes"); } else { byte nullBits = buffer.getByte(offset); - int pos = offset + 16; + int pos = offset + 20; if ((nullBits & 1) != 0) { int biomeDataMapCount = VarInt.peek(buffer, pos); if (biomeDataMapCount < 0) { @@ -210,6 +234,10 @@ public class UpdateWorldMapSettings implements Packet { copy.allowTeleportToCoordinates = this.allowTeleportToCoordinates; copy.allowTeleportToMarkers = this.allowTeleportToMarkers; + copy.allowShowOnMapToggle = this.allowShowOnMapToggle; + copy.allowCompassTrackingToggle = this.allowCompassTrackingToggle; + copy.allowCreatingMapMarkers = this.allowCreatingMapMarkers; + copy.allowRemovingOtherPlayersMarkers = this.allowRemovingOtherPlayersMarkers; copy.defaultScale = this.defaultScale; copy.minScale = this.minScale; copy.maxScale = this.maxScale; @@ -227,6 +255,10 @@ public class UpdateWorldMapSettings implements Packet { && Objects.equals(this.biomeDataMap, other.biomeDataMap) && this.allowTeleportToCoordinates == other.allowTeleportToCoordinates && this.allowTeleportToMarkers == other.allowTeleportToMarkers + && this.allowShowOnMapToggle == other.allowShowOnMapToggle + && this.allowCompassTrackingToggle == other.allowCompassTrackingToggle + && this.allowCreatingMapMarkers == other.allowCreatingMapMarkers + && this.allowRemovingOtherPlayersMarkers == other.allowRemovingOtherPlayersMarkers && this.defaultScale == other.defaultScale && this.minScale == other.minScale && this.maxScale == other.maxScale; @@ -236,7 +268,17 @@ public class UpdateWorldMapSettings implements Packet { @Override public int hashCode() { return Objects.hash( - this.enabled, this.biomeDataMap, this.allowTeleportToCoordinates, this.allowTeleportToMarkers, this.defaultScale, this.minScale, this.maxScale + this.enabled, + this.biomeDataMap, + this.allowTeleportToCoordinates, + this.allowTeleportToMarkers, + this.allowShowOnMapToggle, + this.allowCompassTrackingToggle, + this.allowCreatingMapMarkers, + this.allowRemovingOtherPlayersMarkers, + this.defaultScale, + this.minScale, + this.maxScale ); } } diff --git a/src/com/hypixel/hytale/registry/Registry.java b/src/com/hypixel/hytale/registry/Registry.java index ffe4281a..862e2752 100644 --- a/src/com/hypixel/hytale/registry/Registry.java +++ b/src/com/hypixel/hytale/registry/Registry.java @@ -5,10 +5,12 @@ import java.util.Collections; import java.util.List; import java.util.function.BooleanSupplier; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public abstract class Registry { @Nonnull private final BooleanSupplier precondition; + @Nullable private final String preconditionMessage; private final Registry.RegistrationWrapFunction wrappingFunction; @Nonnull @@ -20,7 +22,7 @@ public abstract class Registry { protected Registry( @Nonnull List registrations, @Nonnull BooleanSupplier precondition, - String preconditionMessage, + @Nullable String preconditionMessage, @Nonnull Registry.RegistrationWrapFunction wrappingFunction ) { this.registrations = registrations; diff --git a/src/com/hypixel/hytale/server/core/HytaleServer.java b/src/com/hypixel/hytale/server/core/HytaleServer.java index 5cafb933..95018b52 100644 --- a/src/com/hypixel/hytale/server/core/HytaleServer.java +++ b/src/com/hypixel/hytale/server/core/HytaleServer.java @@ -30,6 +30,7 @@ import com.hypixel.hytale.server.core.event.events.ShutdownEvent; import com.hypixel.hytale.server.core.io.ServerManager; import com.hypixel.hytale.server.core.io.netty.NettyUtil; import com.hypixel.hytale.server.core.modules.singleplayer.SingleplayerModule; +import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.PluginBase; import com.hypixel.hytale.server.core.plugin.PluginClassLoader; import com.hypixel.hytale.server.core.plugin.PluginManager; @@ -116,7 +117,9 @@ public class HytaleServer { LOGGER.at(Level.INFO).log("Authentication mode: %s", optionSet.valueOf(Options.AUTH_MODE)); ServerAuthManager.getInstance().initialize(); if (EarlyPluginLoader.hasTransformers()) { - HytaleLogger.getLogger().at(Level.INFO).log("Early plugins loaded!! Disabling Sentry!!"); + LOGGER.at(Level.INFO).log("Early plugins loaded!! Disabling Sentry!!"); + } else if (!ManifestUtil.isJar() || ManifestUtil.getVersion() == null) { + LOGGER.at(Level.INFO).log("Sentry disabled: development build (no version)"); } else if (!optionSet.has(Options.DISABLE_SENTRY)) { LOGGER.at(Level.INFO).log("Enabling Sentry"); SentryOptions options = new SentryOptions(); @@ -151,6 +154,7 @@ public class HytaleServer { } HashMap pluginsContext = new HashMap<>(); + boolean hasExternalPlugins = false; for (PluginBase plugin : this.pluginManager.getPlugins()) { PluginManifest manifestxx = plugin.getManifest(); @@ -158,10 +162,14 @@ public class HytaleServer { pluginInfo.put("version", manifestxx.getVersion().toString()); pluginInfo.put("state", plugin.getState().name()); pluginsContext.put(plugin.getIdentifier().toString(), pluginInfo); + if (plugin instanceof JavaPlugin jp && !jp.getClassLoader().isInServerClassPath()) { + hasExternalPlugins = true; + } } contexts.put("plugins", pluginsContext); AssetModule assetModule = AssetModule.get(); + boolean hasUserPacks = false; if (assetModule != null) { HashMap packsContext = new HashMap<>(); @@ -174,11 +182,16 @@ public class HytaleServer { packInfo.put("immutable", pack.isImmutable()); packsContext.put(pack.getName(), packInfo); + if (!pack.isImmutable()) { + hasUserPacks = true; + } } contexts.put("packs", packsContext); } + event.setTag("has-plugins", String.valueOf(hasExternalPlugins)); + event.setTag("has-packs", String.valueOf(hasUserPacks)); User user = new User(); HashMap unknown = new HashMap<>(); user.setUnknown(unknown); diff --git a/src/com/hypixel/hytale/server/core/HytaleServerConfig.java b/src/com/hypixel/hytale/server/core/HytaleServerConfig.java index de96474b..e3947a99 100644 --- a/src/com/hypixel/hytale/server/core/HytaleServerConfig.java +++ b/src/com/hypixel/hytale/server/core/HytaleServerConfig.java @@ -37,14 +37,14 @@ import javax.annotation.Nullable; import org.bson.BsonDocument; public class HytaleServerConfig { - public static final int VERSION = 3; + public static final int VERSION = 4; public static final int DEFAULT_MAX_VIEW_RADIUS = 32; @Nonnull public static final Path PATH = Path.of("config.json"); @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(HytaleServerConfig.class, HytaleServerConfig::new) .versioned() - .codecVersion(3) + .codecVersion(4) .append(new KeyedCodec<>("ServerName", Codec.STRING), (o, s) -> o.serverName = s, o -> o.serverName) .add() .append(new KeyedCodec<>("MOTD", Codec.STRING), (o, s) -> o.motd = s, o -> o.motd) @@ -92,6 +92,9 @@ public class HytaleServerConfig { o -> o.modConfig ) .add() + .append(new KeyedCodec<>("DefaultModsEnabled", Codec.BOOLEAN), (o, v) -> o.defaultModsEnabled = v, o -> o.defaultModsEnabled) + .setVersionRange(4, Integer.MAX_VALUE) + .add() .append( new KeyedCodec<>("DisplayTmpTagsInStrings", Codec.BOOLEAN), (o, displayTmpTagsInStrings) -> o.displayTmpTagsInStrings = displayTmpTagsInStrings, @@ -104,7 +107,7 @@ public class HytaleServerConfig { .add() .append(new KeyedCodec<>("Update", HytaleServerConfig.UpdateConfig.CODEC), (o, value) -> o.updateConfig = value, o -> o.updateConfig) .add() - .afterDecode(config -> { + .afterDecode((config, extraInfo) -> { config.defaults.hytaleServerConfig = config; config.connectionTimeouts.setHytaleServerConfig(config); config.rateLimitConfig.hytaleServerConfig = config; @@ -118,6 +121,11 @@ public class HytaleServerConfig { config.legacyPluginConfig = null; config.markChanged(); } + + if (config.defaultModsEnabled == null && extraInfo.getVersion() < 4) { + config.defaultModsEnabled = true; + config.markChanged(); + } }) .build(); @Nonnull @@ -141,6 +149,8 @@ public class HytaleServerConfig { private transient Map legacyPluginConfig; @Nonnull private Map modConfig = new ConcurrentHashMap<>(); + @Nullable + private Boolean defaultModsEnabled; @Nonnull private Map unmodifiableModules = Collections.unmodifiableMap(this.modules); @Nonnull @@ -273,6 +283,10 @@ public class HytaleServerConfig { this.markChanged(); } + public boolean getDefaultModsEnabled() { + return this.defaultModsEnabled != null ? this.defaultModsEnabled : !Constants.SINGLEPLAYER; + } + @Nonnull public PlayerStorageProvider getPlayerStorageProvider() { return this.playerStorageProvider; diff --git a/src/com/hypixel/hytale/server/core/Options.java b/src/com/hypixel/hytale/server/core/Options.java index 0dbba4a4..af3601f1 100644 --- a/src/com/hypixel/hytale/server/core/Options.java +++ b/src/com/hypixel/hytale/server/core/Options.java @@ -97,6 +97,10 @@ public class Options { .withRequiredArg() .withValuesConvertedBy(new Options.PathConverter(Options.PathConverter.PathType.DIR)); public static final OptionSpec BACKUP_MAX_COUNT = PARSER.accepts("backup-max-count").withRequiredArg().ofType(Integer.class).defaultsTo(5); + public static final OptionSpec BACKUP_ARCHIVE_MAX_COUNT = PARSER.accepts("backup-archive-max-count") + .withRequiredArg() + .ofType(Integer.class) + .defaultsTo(5); public static final OptionSpec SINGLEPLAYER = PARSER.accepts("singleplayer"); public static final OptionSpec OWNER_NAME = PARSER.accepts("owner-name").withRequiredArg(); public static final OptionSpec OWNER_UUID = PARSER.accepts("owner-uuid").withRequiredArg().withValuesConvertedBy(new Options.UUIDConverter()); diff --git a/src/com/hypixel/hytale/server/core/asset/AssetModule.java b/src/com/hypixel/hytale/server/core/asset/AssetModule.java index bffe73a1..0c03200f 100644 --- a/src/com/hypixel/hytale/server/core/asset/AssetModule.java +++ b/src/com/hypixel/hytale/server/core/asset/AssetModule.java @@ -85,7 +85,7 @@ public class AssetModule extends JavaPlugin { } for (Path path : Options.getOptionSet().valuesOf(Options.ASSET_DIRECTORY)) { - this.loadAndRegisterPack(path); + this.loadAndRegisterPack(path, false); } this.loadPacksFromDirectory(PluginManager.MODS_PATH); @@ -244,7 +244,7 @@ public class AssetModule extends JavaPlugin { try (DirectoryStream stream = Files.newDirectoryStream(modsPath)) { for (Path packPath : stream) { if (packPath.getFileName() != null && !packPath.getFileName().toString().toLowerCase().endsWith(".jar")) { - this.loadAndRegisterPack(packPath); + this.loadAndRegisterPack(packPath, true); } } } catch (IOException var7) { @@ -253,7 +253,7 @@ public class AssetModule extends JavaPlugin { } } - private void loadAndRegisterPack(Path packPath) { + private void loadAndRegisterPack(Path packPath, boolean isExternal) { PluginManifest manifest; try { manifest = this.loadPackManifest(packPath); @@ -261,14 +261,21 @@ public class AssetModule extends JavaPlugin { this.getLogger().at(Level.WARNING).log("Skipping pack at %s: missing or invalid manifest.json", packPath.getFileName()); return; } - } catch (Exception var7) { - this.getLogger().at(Level.WARNING).withCause(var7).log("Failed to load manifest for pack at %s", packPath); + } catch (Exception var9) { + this.getLogger().at(Level.WARNING).withCause(var9).log("Failed to load manifest for pack at %s", packPath); return; } PluginIdentifier packIdentifier = new PluginIdentifier(manifest); - HytaleServerConfig.ModConfig modConfig = HytaleServer.get().getConfig().getModConfig().get(packIdentifier); - boolean enabled = modConfig == null || modConfig.getEnabled() == null || modConfig.getEnabled(); + HytaleServerConfig serverConfig = HytaleServer.get().getConfig(); + HytaleServerConfig.ModConfig modConfig = serverConfig.getModConfig().get(packIdentifier); + boolean enabled; + if (modConfig != null && modConfig.getEnabled() != null) { + enabled = modConfig.getEnabled(); + } else { + enabled = !manifest.isDisabledByDefault() && (!isExternal || serverConfig.getDefaultModsEnabled()); + } + String packId = packIdentifier.toString(); if (enabled) { this.registerPack(packId, packPath, manifest); diff --git a/src/com/hypixel/hytale/server/core/asset/common/CommonAssetModule.java b/src/com/hypixel/hytale/server/core/asset/common/CommonAssetModule.java index 59a521ad..36ca343f 100644 --- a/src/com/hypixel/hytale/server/core/asset/common/CommonAssetModule.java +++ b/src/com/hypixel/hytale/server/core/asset/common/CommonAssetModule.java @@ -509,7 +509,11 @@ public class CommonAssetModule extends JavaPlugin { packets[0] = new AssetInitialize(thisAsset.toPacket(), allBytes.length); for (int partIndex = 0; partIndex < parts.length; partIndex++) { - packets[1 + partIndex * 2] = new WorldLoadProgress("Loading asset " + thisAsset.getName(), thisPercent, 100 * partIndex / parts.length); + packets[1 + partIndex * 2] = new WorldLoadProgress( + Message.translation("client.general.worldLoad.loadingAsset").param("assetName", thisAsset.getName()).getFormattedMessage(), + thisPercent, + 100 * partIndex / parts.length + ); packets[1 + partIndex * 2 + 1] = new AssetPart(parts[partIndex]); } diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/FarmingData.java b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/FarmingData.java index 76ae08d0..2fbf2e23 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/FarmingData.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/FarmingData.java @@ -99,6 +99,7 @@ public class FarmingData { } public static class SoilConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(FarmingData.SoilConfig.class, FarmingData.SoilConfig::new) .appendInherited( new KeyedCodec<>("TargetBlock", Codec.STRING), (o, v) -> o.targetBlock = v, o -> o.targetBlock, (o, p) -> o.targetBlock = p.targetBlock diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/FarmingStageData.java b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/FarmingStageData.java index cd5382e6..91fb45bc 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/FarmingStageData.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/FarmingStageData.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.lookup.CodecMapCodec; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.protocol.Rangef; import com.hypixel.hytale.protocol.SoundCategory; @@ -13,8 +14,10 @@ import com.hypixel.hytale.server.core.asset.type.soundevent.config.SoundEvent; import com.hypixel.hytale.server.core.asset.type.soundevent.validator.SoundEventValidators; import com.hypixel.hytale.server.core.codec.ProtocolCodecs; import com.hypixel.hytale.server.core.universe.world.SoundUtil; +import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -44,7 +47,7 @@ public abstract class FarmingStageData { .build(); protected Rangef duration; @Nullable - protected String soundEventId = null; + protected String soundEventId; protected transient int soundEventIndex = 0; @Nullable @@ -65,32 +68,38 @@ public abstract class FarmingStageData { return false; } - public boolean shouldStop(ComponentAccessor commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z) { + public boolean shouldStop( + @Nonnull ComponentAccessor commandBuffer, @Nonnull Ref sectionRef, @Nonnull Ref blockRef, int x, int y, int z + ) { return false; } public void apply( - ComponentAccessor commandBuffer, - Ref sectionRef, - Ref blockRef, + @Nonnull ComponentAccessor commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, int x, int y, int z, @Nullable FarmingStageData previousStage ) { - ChunkSection section = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); - int worldX = ChunkUtil.worldCoordFromLocalCoord(section.getX(), x); - int worldY = ChunkUtil.worldCoordFromLocalCoord(section.getY(), y); - int worldZ = ChunkUtil.worldCoordFromLocalCoord(section.getZ(), z); - SoundUtil.playSoundEvent3d( - this.soundEventIndex, SoundCategory.SFX, worldX, worldY, worldZ, commandBuffer.getExternalData().getWorld().getEntityStore().getStore() - ); - if (previousStage != null) { - previousStage.remove(commandBuffer, sectionRef, blockRef, x, y, z); + ChunkSection chunkSectionComponent = commandBuffer.getComponent(sectionRef, ChunkSection.getComponentType()); + if (chunkSectionComponent != null) { + int worldX = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getX(), x); + int worldY = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getY(), y); + int worldZ = ChunkUtil.worldCoordFromLocalCoord(chunkSectionComponent.getZ(), z); + World world = commandBuffer.getExternalData().getWorld(); + Store entityStore = world.getEntityStore().getStore(); + SoundUtil.playSoundEvent3d(this.soundEventIndex, SoundCategory.SFX, worldX, worldY, worldZ, entityStore); + if (previousStage != null) { + previousStage.remove(commandBuffer, sectionRef, blockRef, x, y, z); + } } } - public void remove(ComponentAccessor commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z) { + public void remove( + @Nonnull ComponentAccessor commandBuffer, @Nonnull Ref sectionRef, @Nonnull Ref blockRef, int x, int y, int z + ) { } @Nonnull diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/GrowthModifierAsset.java b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/GrowthModifierAsset.java index 219ba4fe..9ce0a93e 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/GrowthModifierAsset.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/farming/GrowthModifierAsset.java @@ -64,7 +64,13 @@ public abstract class GrowthModifierAsset implements JsonAssetWithMap commandBuffer, Ref sectionRef, Ref blockRef, int x, int y, int z, boolean initialTick + @Nonnull CommandBuffer commandBuffer, + @Nonnull Ref sectionRef, + @Nonnull Ref blockRef, + int x, + int y, + int z, + boolean initialTick ) { return this.modifier; } diff --git a/src/com/hypixel/hytale/server/core/asset/type/gameplay/WorldMapConfig.java b/src/com/hypixel/hytale/server/core/asset/type/gameplay/WorldMapConfig.java index f78ad33d..ecea9b0f 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/gameplay/WorldMapConfig.java +++ b/src/com/hypixel/hytale/server/core/asset/type/gameplay/WorldMapConfig.java @@ -3,36 +3,73 @@ package com.hypixel.hytale.server.core.asset.type.gameplay; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.server.core.asset.type.gameplay.worldmap.PlayersMapMarkerConfig; +import com.hypixel.hytale.server.core.asset.type.gameplay.worldmap.UserMapMarkerConfig; import javax.annotation.Nonnull; public class WorldMapConfig { @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(WorldMapConfig.class, WorldMapConfig::new) - .addField( + .append( new KeyedCodec<>("DisplaySpawn", Codec.BOOLEAN), (worldMapConfig, o) -> worldMapConfig.displaySpawn = o, worldMapConfig -> worldMapConfig.displaySpawn ) - .addField( + .add() + .append( new KeyedCodec<>("DisplayHome", Codec.BOOLEAN), (worldMapConfig, o) -> worldMapConfig.displayHome = o, worldMapConfig -> worldMapConfig.displayHome ) - .addField( + .add() + .append( new KeyedCodec<>("DisplayWarps", Codec.BOOLEAN), (worldMapConfig, o) -> worldMapConfig.displayWarps = o, worldMapConfig -> worldMapConfig.displayWarps ) - .addField( + .add() + .append( new KeyedCodec<>("DisplayDeathMarker", Codec.BOOLEAN), (worldMapConfig, o) -> worldMapConfig.displayDeathMarker = o, worldMapConfig -> worldMapConfig.displayDeathMarker ) - .addField( + .add() + .append( new KeyedCodec<>("DisplayPlayers", Codec.BOOLEAN), (worldMapConfig, o) -> worldMapConfig.displayPlayers = o, worldMapConfig -> worldMapConfig.displayPlayers ) + .add() + .append( + new KeyedCodec<>("PlayersMarkersConfig", PlayersMapMarkerConfig.CODEC), + (worldMapConfig, o) -> worldMapConfig.playersConfig = o, + worldMapConfig -> worldMapConfig.playersConfig + ) + .add() + .append( + new KeyedCodec<>("CanTrackPlayersInCompass", Codec.BOOLEAN), + (worldMapConfig, o) -> worldMapConfig.canTrackPlayersInCompass = o, + worldMapConfig -> worldMapConfig.canTrackPlayersInCompass + ) + .documentation("Whether the client functionality to toggle tracking other players in compass is enabled") + .add() + .append( + new KeyedCodec<>("CanTogglePlayersInMap", Codec.BOOLEAN), + (worldMapConfig, o) -> worldMapConfig.canTogglePlayersInMap = o, + worldMapConfig -> worldMapConfig.canTogglePlayersInMap + ) + .documentation("Whether the client functionality to toggle other players visibility on the world map is enabled") + .add() + .append( + new KeyedCodec<>("UserMapMarkers", UserMapMarkerConfig.CODEC), + (worldMapConfig, o) -> worldMapConfig.userMapMarkerConfig = o, + worldMapConfig -> worldMapConfig.userMapMarkerConfig + ) + .add() .build(); protected boolean displaySpawn = true; protected boolean displayHome = true; protected boolean displayWarps = true; protected boolean displayDeathMarker = true; protected boolean displayPlayers = true; + protected boolean canTrackPlayersInCompass = true; + protected boolean canTogglePlayersInMap = true; + protected PlayersMapMarkerConfig playersConfig = new PlayersMapMarkerConfig(); + protected UserMapMarkerConfig userMapMarkerConfig = new UserMapMarkerConfig(); public boolean isDisplaySpawn() { return this.displaySpawn; @@ -53,4 +90,20 @@ public class WorldMapConfig { public boolean isDisplayPlayers() { return this.displayPlayers; } + + public PlayersMapMarkerConfig getPlayersConfig() { + return this.playersConfig; + } + + public boolean canTrackPlayersInCompass() { + return this.canTrackPlayersInCompass; + } + + public boolean canTogglePlayersInMap() { + return this.canTogglePlayersInMap; + } + + public UserMapMarkerConfig getUserMapMarkerConfig() { + return this.userMapMarkerConfig; + } } diff --git a/src/com/hypixel/hytale/server/core/asset/type/gameplay/worldmap/PlayersMapMarkerConfig.java b/src/com/hypixel/hytale/server/core/asset/type/gameplay/worldmap/PlayersMapMarkerConfig.java new file mode 100644 index 00000000..f237c5c1 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/asset/type/gameplay/worldmap/PlayersMapMarkerConfig.java @@ -0,0 +1,34 @@ +package com.hypixel.hytale.server.core.asset.type.gameplay.worldmap; + +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; + +public class PlayersMapMarkerConfig { + public static final BuilderCodec CODEC = BuilderCodec.builder(PlayersMapMarkerConfig.class, PlayersMapMarkerConfig::new) + .append(new KeyedCodec<>("IconSwapHeightDelta", Codec.INTEGER), (config, o) -> config.iconSwapHeightDelta = o, config -> config.iconSwapHeightDelta) + .documentation("When seeing other players' icons on the map, what the Y difference between you and them need to be in order to swap their icon.") + .add() + .append(new KeyedCodec<>("BelowIcon", Codec.STRING), (config, o) -> config.belowIcon = o, config -> config.belowIcon) + .documentation("The icon when a player is below you. Find Player.png in the assets for the folder where to see/add available icons.") + .add() + .append(new KeyedCodec<>("AboveIcon", Codec.STRING), (config, o) -> config.aboveIcon = o, config -> config.aboveIcon) + .documentation("The icon when a player is above you. Find Player.png in the assets for the folder where to see/add available icons.") + .add() + .build(); + private int iconSwapHeightDelta = 12; + private String belowIcon = "PlayerBelow.png"; + private String aboveIcon = "PlayerAbove.png"; + + public int getIconSwapHeightDelta() { + return this.iconSwapHeightDelta; + } + + public String getBelowIcon() { + return this.belowIcon; + } + + public String getAboveIcon() { + return this.aboveIcon; + } +} diff --git a/src/com/hypixel/hytale/server/core/asset/type/gameplay/worldmap/UserMapMarkerConfig.java b/src/com/hypixel/hytale/server/core/asset/type/gameplay/worldmap/UserMapMarkerConfig.java new file mode 100644 index 00000000..7837b569 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/asset/type/gameplay/worldmap/UserMapMarkerConfig.java @@ -0,0 +1,52 @@ +package com.hypixel.hytale.server.core.asset.type.gameplay.worldmap; + +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; + +public final class UserMapMarkerConfig { + public static final BuilderCodec CODEC = BuilderCodec.builder(UserMapMarkerConfig.class, UserMapMarkerConfig::new) + .append(new KeyedCodec<>("AllowCreatingMarkers", Codec.BOOLEAN), (config, o) -> config.allowCreatingMarkers = o, config -> config.allowCreatingMarkers) + .documentation("Whether players can create new map markers. This will also make the option invisible from the client.") + .add() + .append( + new KeyedCodec<>("MaxPersonalMarkersPerPlayer", Codec.INTEGER), + (config, o) -> config.maxPersonalMarkersPerPlayer = o, + config -> config.maxPersonalMarkersPerPlayer + ) + .add() + .append( + new KeyedCodec<>("MaxSharedMarkersPerPlayer", Codec.INTEGER), + (config, o) -> config.maxSharedMarkersPerPlayer = o, + config -> config.maxSharedMarkersPerPlayer + ) + .add() + .append( + new KeyedCodec<>("AllowDeletingOtherPlayersSharedMarkers", Codec.BOOLEAN), + (config, o) -> config.allowDeleteOtherPlayersSharedMarkers = o, + config -> config.allowDeleteOtherPlayersSharedMarkers + ) + .documentation("Whether a player can delete another player's shared marker. Beware of marker pvp.") + .add() + .build(); + private boolean allowCreatingMarkers = true; + private int maxPersonalMarkersPerPlayer = 12; + private int maxSharedMarkersPerPlayer = 12; + private boolean allowDeleteOtherPlayersSharedMarkers = true; + + public boolean isAllowCreatingMarkers() { + return this.allowCreatingMarkers; + } + + public int getMaxPersonalMarkersPerPlayer() { + return this.maxPersonalMarkersPerPlayer; + } + + public int getMaxSharedMarkersPerPlayer() { + return this.maxSharedMarkersPerPlayer; + } + + public boolean isAllowDeleteOtherPlayersSharedMarkers() { + return this.allowDeleteOtherPlayersSharedMarkers; + } +} diff --git a/src/com/hypixel/hytale/server/core/asset/type/portalworld/PortalSpawn.java b/src/com/hypixel/hytale/server/core/asset/type/portalworld/PortalSpawn.java index 4133885f..08bad275 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/portalworld/PortalSpawn.java +++ b/src/com/hypixel/hytale/server/core/asset/type/portalworld/PortalSpawn.java @@ -4,8 +4,10 @@ import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.math.vector.Vector3i; +import javax.annotation.Nonnull; public class PortalSpawn { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PortalSpawn.class, PortalSpawn::new) .append(new KeyedCodec<>("Y", Codec.INTEGER), (spawn, o) -> spawn.checkSpawnY = o, spawn -> spawn.checkSpawnY) .documentation("The Y height where to start looking for X,Z candidate.") diff --git a/src/com/hypixel/hytale/server/core/codec/ProtocolCodecs.java b/src/com/hypixel/hytale/server/core/codec/ProtocolCodecs.java index b9d92dd9..519d6605 100644 --- a/src/com/hypixel/hytale/server/core/codec/ProtocolCodecs.java +++ b/src/com/hypixel/hytale/server/core/codec/ProtocolCodecs.java @@ -8,7 +8,6 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import com.hypixel.hytale.codec.schema.metadata.HytaleType; import com.hypixel.hytale.codec.schema.metadata.ui.UIDisplayMode; import com.hypixel.hytale.codec.validation.Validators; -import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.protocol.AccumulationMode; import com.hypixel.hytale.protocol.ChangeStatBehaviour; import com.hypixel.hytale.protocol.ChangeVelocityType; @@ -33,14 +32,11 @@ import com.hypixel.hytale.protocol.UVMotion; import com.hypixel.hytale.protocol.UVMotionCurveType; import com.hypixel.hytale.protocol.Vector2f; import com.hypixel.hytale.protocol.Vector3f; -import com.hypixel.hytale.protocol.packets.worldmap.ContextMenuItem; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.server.core.asset.common.BlockyAnimationCache; import com.hypixel.hytale.server.core.asset.common.CommonAssetValidator; import com.hypixel.hytale.server.core.asset.util.ColorParseUtil; import com.hypixel.hytale.server.core.codec.protocol.ColorAlphaCodec; import com.hypixel.hytale.server.core.codec.protocol.ColorCodec; -import com.hypixel.hytale.server.core.util.PositionUtil; public final class ProtocolCodecs { public static final BuilderCodec DIRECTION = BuilderCodec.builder(Direction.class, Direction::new) @@ -164,27 +160,6 @@ public final class ProtocolCodecs { public static final BuilderCodec SAVED_MOVEMENT_STATES = BuilderCodec.builder(SavedMovementStates.class, SavedMovementStates::new) .addField(new KeyedCodec<>("Flying", Codec.BOOLEAN), (movementStates, flying) -> movementStates.flying = flying, movementStates -> movementStates.flying) .build(); - public static final BuilderCodec CONTEXT_MENU_ITEM = BuilderCodec.builder(ContextMenuItem.class, ContextMenuItem::new) - .addField(new KeyedCodec<>("Name", Codec.STRING), (item, s) -> item.name = s, item -> item.name) - .addField(new KeyedCodec<>("Command", Codec.STRING), (item, s) -> item.command = s, item -> item.command) - .build(); - public static final ArrayCodec CONTEXT_MENU_ITEM_ARRAY = new ArrayCodec<>(CONTEXT_MENU_ITEM, ContextMenuItem[]::new); - public static final BuilderCodec MARKER = BuilderCodec.builder(MapMarker.class, MapMarker::new) - .addField(new KeyedCodec<>("Id", Codec.STRING), (marker, s) -> marker.id = s, marker -> marker.id) - .addField(new KeyedCodec<>("Name", Codec.STRING), (marker, s) -> marker.name = s, marker -> marker.name) - .addField(new KeyedCodec<>("Image", Codec.STRING), (marker, s) -> marker.markerImage = s, marker -> marker.markerImage) - .append( - new KeyedCodec<>("Transform", Transform.CODEC), - (marker, s) -> marker.transform = PositionUtil.toTransformPacket(s), - marker -> PositionUtil.toTransform(marker.transform) - ) - .addValidator(Validators.nonNull()) - .add() - .addField( - new KeyedCodec<>("ContextMenuItems", CONTEXT_MENU_ITEM_ARRAY), (marker, items) -> marker.contextMenuItems = items, marker -> marker.contextMenuItems - ) - .build(); - public static final ArrayCodec MARKER_ARRAY = new ArrayCodec<>(MARKER, MapMarker[]::new); public static final BuilderCodec ITEM_ANIMATION_CODEC = BuilderCodec.builder(ItemAnimation.class, ItemAnimation::new) .append(new KeyedCodec<>("ThirdPerson", Codec.STRING), (itemAnimation, s) -> itemAnimation.thirdPerson = s, itemAnimation -> itemAnimation.thirdPerson) .addValidator(CommonAssetValidator.ANIMATION_ITEM_CHARACTER) diff --git a/src/com/hypixel/hytale/server/core/command/commands/debug/MessageTranslationTestCommand.java b/src/com/hypixel/hytale/server/core/command/commands/debug/MessageTranslationTestCommand.java index 914faa9c..fb8c1e14 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/MessageTranslationTestCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/MessageTranslationTestCommand.java @@ -7,7 +7,7 @@ import javax.annotation.Nonnull; public class MessageTranslationTestCommand extends CommandBase { public MessageTranslationTestCommand() { - super("messagetest", "Test sending messages with nested translated parameter messages"); + super("messagetest", "server.commands.messagetest.desc"); this.addAliases("msgtest"); } diff --git a/src/com/hypixel/hytale/server/core/command/commands/debug/StopNetworkChunkSendingCommand.java b/src/com/hypixel/hytale/server/core/command/commands/debug/StopNetworkChunkSendingCommand.java index e6104edb..7a16d300 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/StopNetworkChunkSendingCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/StopNetworkChunkSendingCommand.java @@ -16,11 +16,11 @@ import javax.annotation.Nonnull; public class StopNetworkChunkSendingCommand extends AbstractPlayerCommand { @Nonnull private final RequiredArg sendNetworkChunksArg = this.withRequiredArg( - "sendNetworkChunks", "Whether chunks should be sent over the network to yourself", ArgTypes.BOOLEAN + "sendNetworkChunks", "server.commands.networkChunkSending.sendNetworkChunks.desc", ArgTypes.BOOLEAN ); public StopNetworkChunkSendingCommand() { - super("networkChunkSending", "Stop sending chunks over the network"); + super("networkChunkSending", "server.commands.networkChunkSending.desc"); } @Override diff --git a/src/com/hypixel/hytale/server/core/command/commands/debug/VersionCommand.java b/src/com/hypixel/hytale/server/core/command/commands/debug/VersionCommand.java index 6303af5e..388aabf5 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/VersionCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/VersionCommand.java @@ -8,7 +8,7 @@ import javax.annotation.Nonnull; public class VersionCommand extends CommandBase { public VersionCommand() { - super("version", "Displays version information about the currently running server"); + super("version", "server.commands.version.desc"); } @Override diff --git a/src/com/hypixel/hytale/server/core/command/commands/debug/stresstest/Bot.java b/src/com/hypixel/hytale/server/core/command/commands/debug/stresstest/Bot.java index 64202826..bd9a4814 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/stresstest/Bot.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/stresstest/Bot.java @@ -170,7 +170,7 @@ public class Bot extends SimpleChannelInboundHandler { @Override public void channelActive(@Nonnull ChannelHandlerContext ctx) { UUID uuid = UUID.nameUUIDFromBytes(("BOT|" + this.name).getBytes(StandardCharsets.UTF_8)); - ctx.writeAndFlush(new Connect(1789265863, 2, "bot", ClientType.Game, uuid, this.name, null, "en", null, null)); + ctx.writeAndFlush(new Connect(701662755, 5, "bot", ClientType.Game, uuid, this.name, null, "en", null, null)); this.logger.at(Level.INFO).log("Connected!"); } diff --git a/src/com/hypixel/hytale/server/core/command/commands/player/ReferCommand.java b/src/com/hypixel/hytale/server/core/command/commands/player/ReferCommand.java index f1df02d8..c9df3e8a 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/player/ReferCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/player/ReferCommand.java @@ -17,12 +17,12 @@ import javax.annotation.Nullable; public class ReferCommand extends AbstractTargetPlayerCommand { @Nonnull - private final RequiredArg hostArg = this.withRequiredArg("host", "Target server hostname or IP", ArgTypes.STRING); + private final RequiredArg hostArg = this.withRequiredArg("host", "server.commands.refer.host.desc", ArgTypes.STRING); @Nonnull - private final RequiredArg portArg = this.withRequiredArg("port", "Target server port", ArgTypes.INTEGER); + private final RequiredArg portArg = this.withRequiredArg("port", "server.commands.refer.port.desc", ArgTypes.INTEGER); public ReferCommand() { - super("refer", "Refer a player to another server for testing"); + super("refer", "server.commands.refer.desc"); this.addAliases("transfer"); } diff --git a/src/com/hypixel/hytale/server/core/command/commands/utility/worldmap/WorldMapClearMarkersCommand.java b/src/com/hypixel/hytale/server/core/command/commands/utility/worldmap/WorldMapClearMarkersCommand.java index e7c2593e..7ec5d9d1 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/utility/worldmap/WorldMapClearMarkersCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/utility/worldmap/WorldMapClearMarkersCommand.java @@ -29,7 +29,7 @@ public class WorldMapClearMarkersCommand extends AbstractPlayerCommand { assert playerComponent != null; PlayerWorldData perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(world.getName()); - perWorldData.setWorldMapMarkers(null); + perWorldData.setUserMapMarkers(null); context.sendMessage(MESSAGE_COMMANDS_WORLD_MAP_MARKERS_CLEARED); } } diff --git a/src/com/hypixel/hytale/server/core/command/system/AbstractCommand.java b/src/com/hypixel/hytale/server/core/command/system/AbstractCommand.java index 5284916e..83d15210 100644 --- a/src/com/hypixel/hytale/server/core/command/system/AbstractCommand.java +++ b/src/com/hypixel/hytale/server/core/command/system/AbstractCommand.java @@ -62,6 +62,7 @@ public abstract class AbstractCommand { private final String name; @Nonnull private final Set aliases = new HashSet<>(); + @Nullable private final String description; @Nonnull private final List> requiredArguments = new ObjectArrayList<>(); @@ -713,7 +714,7 @@ public abstract class AbstractCommand { return Message.translation("server.commands.parsing.usage.header") .param("fullyQualifiedName", this.getFullyQualifiedName()) - .param("description", Message.translation(this.description)) + .param("description", this.description != null ? Message.translation(this.description) : Message.empty()) .param("listOfRequiredArgs", requiredArgsMessage) .param("requiresConfirmation", requiresConfirmationMessage) .param("requiredArgs", requiredArgs) @@ -861,6 +862,7 @@ public abstract class AbstractCommand { return this.aliases; } + @Nullable public String getDescription() { return this.description; } diff --git a/src/com/hypixel/hytale/server/core/command/system/pages/CommandListPage.java b/src/com/hypixel/hytale/server/core/command/system/pages/CommandListPage.java index c070f48a..cb17c5e0 100644 --- a/src/com/hypixel/hytale/server/core/command/system/pages/CommandListPage.java +++ b/src/com/hypixel/hytale/server/core/command/system/pages/CommandListPage.java @@ -48,7 +48,9 @@ public class CommandListPage extends InteractiveCustomUIPage subcommandBreadcrumb = new ObjectArrayList<>(); @Nullable @@ -235,8 +237,9 @@ public class CommandListPage extends InteractiveCustomUIPage subcommands = currentContext.getSubCommands(); - AbstractCommand subcommand = subcommands.get(subcommandName); - if (subcommand != null) { - this.subcommandBreadcrumb.add(subcommandName); - this.selectedSubcommand = subcommandName; - this.selectedVariantIndex = null; - this.updateTitleWithBreadcrumb(commandBuilder); - commandBuilder.set("#CommandDescription.TextSpans", Message.translation(subcommand.getDescription())); - this.buildSubcommandTabs(subcommand, playerComponent, commandBuilder, eventBuilder); - commandBuilder.set("#BackButton.Visible", true); - this.displayCommandInfo(subcommand, playerComponent, commandBuilder, eventBuilder); + if (playerComponent != null) { + Map subcommands = currentContext.getSubCommands(); + AbstractCommand subcommand = subcommands.get(subcommandName); + if (subcommand != null) { + this.subcommandBreadcrumb.add(subcommandName); + this.selectedSubcommand = subcommandName; + this.selectedVariantIndex = null; + this.updateTitleWithBreadcrumb(commandBuilder); + String description = subcommand.getDescription(); + commandBuilder.set("#CommandDescription.TextSpans", description != null ? Message.translation(description) : Message.empty()); + this.buildSubcommandTabs(subcommand, playerComponent, commandBuilder, eventBuilder); + commandBuilder.set("#BackButton.Visible", true); + this.displayCommandInfo(subcommand, playerComponent, commandBuilder, eventBuilder); + } } } } @@ -389,6 +395,7 @@ public class CommandListPage extends InteractiveCustomUIPage { int highestChainId = -1; boolean changed = false; - label114: + label116: while (it.hasNext()) { SyncInteractionChain packet = it.next(); if (packet.desync) { @@ -226,7 +226,7 @@ public class InteractionManager implements Component { it.remove(); this.packetQueueTime = 0L; } - continue label114; + continue label116; } chain = subChain; @@ -235,50 +235,50 @@ public class InteractionManager implements Component { highestChainId = Math.max(highestChainId, packet.chainId); boolean isProxy = packet.data != null && !UUIDUtil.isEmptyOrNull(packet.data.proxyId); - if ((chain != null || finished) && !isProxy) { - if (chain != null) { - this.sync(ref, chain, packet); + if (chain == null && (!finished || isProxy)) { + if (this.syncStart(ref, packet)) { changed = true; it.remove(); this.packetQueueTime = 0L; - } else if (desynced) { - this.sendCancelPacket(packet.chainId, packet.forkedId); - it.remove(); - HytaleLogger.Api ctx = LOGGER.at(Level.FINE); - ctx.log("Discarding packet due to desync: %s", packet); + } else { + if (!this.waitingForClient(ref)) { + long queuedTime; + if (this.packetQueueTime == 0L) { + this.packetQueueTime = this.currentTime; + queuedTime = 0L; + } else { + queuedTime = this.currentTime - this.packetQueueTime; + } + + HytaleLogger.Api context = LOGGER.at(Level.FINE); + if (context.isEnabled()) { + context.log("Queued chain %d for %s", packet.chainId, FormatUtil.nanosToString(queuedTime)); + } + + if (queuedTime > TimeUnit.MILLISECONDS.toNanos(this.getOperationTimeoutThreshold())) { + this.sendCancelPacket(packet.chainId, packet.forkedId); + it.remove(); + context = LOGGER.at(Level.FINE); + if (context.isEnabled()) { + context.log("Discarding packet due to queuing for too long: %s", packet); + } + } + } + + if (!desynced && !isProxy) { + finished = true; + } } - } else if (this.syncStart(ref, packet)) { + } else if (chain != null) { + this.sync(ref, chain, packet); changed = true; it.remove(); this.packetQueueTime = 0L; - } else { - if (!this.waitingForClient(ref)) { - long queuedTime; - if (this.packetQueueTime == 0L) { - this.packetQueueTime = this.currentTime; - queuedTime = 0L; - } else { - queuedTime = this.currentTime - this.packetQueueTime; - } - - HytaleLogger.Api context = LOGGER.at(Level.FINE); - if (context.isEnabled()) { - context.log("Queued chain %d for %s", packet.chainId, FormatUtil.nanosToString(queuedTime)); - } - - if (queuedTime > TimeUnit.MILLISECONDS.toNanos(this.getOperationTimeoutThreshold())) { - this.sendCancelPacket(packet.chainId, packet.forkedId); - it.remove(); - context = LOGGER.at(Level.FINE); - if (context.isEnabled()) { - context.log("Discarding packet due to queuing for too long: %s", packet); - } - } - } - - if (!desynced && !isProxy) { - finished = true; - } + } else if (desynced) { + this.sendCancelPacket(packet.chainId, packet.forkedId); + it.remove(); + HytaleLogger.Api ctx = LOGGER.at(Level.FINE); + ctx.log("Discarding packet due to desync: %s", packet); } } diff --git a/src/com/hypixel/hytale/server/core/entity/entities/player/data/PlayerWorldData.java b/src/com/hypixel/hytale/server/core/entity/entities/player/data/PlayerWorldData.java index c77fad43..27ce99e1 100644 --- a/src/com/hypixel/hytale/server/core/entity/entities/player/data/PlayerWorldData.java +++ b/src/com/hypixel/hytale/server/core/entity/entities/player/data/PlayerWorldData.java @@ -7,14 +7,22 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.protocol.MovementStates; import com.hypixel.hytale.protocol.SavedMovementStates; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.server.core.codec.ProtocolCodecs; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarkersStore; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; -public final class PlayerWorldData { +public final class PlayerWorldData implements UserMapMarkersStore { @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PlayerWorldData.class, PlayerWorldData::new) .append( @@ -31,13 +39,6 @@ public final class PlayerWorldData { ) .documentation("The last known movement states of the player.") .add() - .append( - new KeyedCodec<>("WorldMapMarkers", ProtocolCodecs.MARKER_ARRAY), - (playerConfigData, objectives) -> playerConfigData.worldMapMarkers = objectives, - playerConfigData -> playerConfigData.worldMapMarkers - ) - .documentation("The world map markers of the player.") - .add() .append( new KeyedCodec<>("FirstSpawn", Codec.BOOLEAN), (playerWorldData, value) -> playerWorldData.firstSpawn = value, @@ -59,12 +60,20 @@ public final class PlayerWorldData { ) .documentation("The death positions of the player in this world.") .add() + .append( + new KeyedCodec<>("UserMarkers", UserMapMarker.ARRAY_CODEC), + (playerWorldData, value) -> playerWorldData.mapMarkersById = Arrays.stream(value) + .collect(Collectors.toConcurrentMap(UserMapMarker::getId, m -> (UserMapMarker)m)), + playerWorldData -> playerWorldData.getUserMapMarkers().toArray(new UserMapMarker[0]) + ) + .documentation("The stored map markers submitted by this player.") + .add() .build(); private static final int DEATH_POSITIONS_COUNT_MAX = 5; private transient PlayerConfigData playerConfigData; private Transform lastPosition; private SavedMovementStates lastMovementStates; - private MapMarker[] worldMapMarkers; + private Map mapMarkersById = new ConcurrentHashMap<>(); private boolean firstSpawn = true; @Nullable private PlayerRespawnPointData[] respawnPoints; @@ -106,16 +115,32 @@ public final class PlayerWorldData { this.lastMovementStates = new SavedMovementStates(lastMovementStates.flying); } - @Nullable - public MapMarker[] getWorldMapMarkers() { - return this.worldMapMarkers; + @Nonnull + @Override + public Collection getUserMapMarkers() { + return this.mapMarkersById.values(); } - public void setWorldMapMarkers(MapMarker[] worldMapMarkers) { - this.worldMapMarkers = worldMapMarkers; + @NonNullDecl + @Override + public Collection getUserMapMarkers(UUID placedByUuid) { + return this.getUserMapMarkers(); + } + + @Override + public void setUserMapMarkers(@Nullable Collection markers) { + this.mapMarkersById = (Map)(markers == null + ? new ConcurrentHashMap<>() + : markers.stream().collect(Collectors.toConcurrentMap(UserMapMarker::getId, x -> (UserMapMarker)x))); this.playerConfigData.markChanged(); } + @Nullable + @Override + public UserMapMarker getUserMapMarker(String markerId) { + return this.mapMarkersById.get(markerId); + } + public boolean isFirstSpawn() { return this.firstSpawn; } @@ -149,8 +174,12 @@ public final class PlayerWorldData { this.playerConfigData.markChanged(); } - public void removeLastDeath(@Nonnull String markerId) { - this.deathPositions.removeIf(deathPosition -> deathPosition.getMarkerId().equalsIgnoreCase(markerId)); - this.playerConfigData.markChanged(); + public boolean removeLastDeath(@Nonnull String markerId) { + boolean removed = this.deathPositions.removeIf(deathPosition -> deathPosition.getMarkerId().equalsIgnoreCase(markerId)); + if (removed) { + this.playerConfigData.markChanged(); + } + + return removed; } } diff --git a/src/com/hypixel/hytale/server/core/entity/entities/player/pages/itemrepair/ItemRepairPage.java b/src/com/hypixel/hytale/server/core/entity/entities/player/pages/itemrepair/ItemRepairPage.java index 00095547..c7ec71a3 100644 --- a/src/com/hypixel/hytale/server/core/entity/entities/player/pages/itemrepair/ItemRepairPage.java +++ b/src/com/hypixel/hytale/server/core/entity/entities/player/pages/itemrepair/ItemRepairPage.java @@ -29,7 +29,7 @@ public class ItemRepairPage extends ChoiceBasePage { } else { commandBuilder.append(this.getPageLayout()); commandBuilder.clear("#ElementList"); - commandBuilder.appendInline("#ElementList", "Label { Text: %customUI.itemRepairPage.noItems; Style: (Alignment: Center); }"); + commandBuilder.appendInline("#ElementList", "Label { Text: %server.customUI.itemRepairPage.noItems; Style: (Alignment: Center); }"); } } diff --git a/src/com/hypixel/hytale/server/core/io/PacketHandler.java b/src/com/hypixel/hytale/server/core/io/PacketHandler.java index 102e5cc1..7b9c0802 100644 --- a/src/com/hypixel/hytale/server/core/io/PacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/PacketHandler.java @@ -23,6 +23,7 @@ import com.hypixel.hytale.server.core.io.adapter.PacketAdapters; import com.hypixel.hytale.server.core.io.handlers.login.AuthenticationPacketHandler; import com.hypixel.hytale.server.core.io.handlers.login.PasswordPacketHandler; import com.hypixel.hytale.server.core.io.netty.NettyUtil; +import com.hypixel.hytale.server.core.io.transport.QUICTransport; import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; import com.hypixel.hytale.server.core.receiver.IPacketReceiver; import io.netty.channel.Channel; @@ -219,7 +220,8 @@ public abstract class PacketHandler implements IPacketReceiver { public void disconnect(@Nonnull String message) { this.disconnectReason.setServerDisconnectReason(message); - HytaleLogger.getLogger().at(Level.INFO).log("Disconnecting %s with the message: %s", NettyUtil.formatRemoteAddress(this.channel), message); + String sni = this.getSniHostname(); + HytaleLogger.getLogger().at(Level.INFO).log("Disconnecting %s (SNI: %s) with the message: %s", NettyUtil.formatRemoteAddress(this.channel), sni, message); this.disconnect0(message); } @@ -386,6 +388,11 @@ public abstract class PacketHandler implements IPacketReceiver { } } + @Nullable + public String getSniHostname() { + return this.channel instanceof QuicStreamChannel quicStreamChannel ? quicStreamChannel.parent().attr(QUICTransport.SNI_HOSTNAME_ATTR).get() : null; + } + @Nonnull public PacketHandler.DisconnectReason getDisconnectReason() { return this.disconnectReason; diff --git a/src/com/hypixel/hytale/server/core/io/commands/BindingsCommand.java b/src/com/hypixel/hytale/server/core/io/commands/BindingsCommand.java index 9a29d3b8..14d1db6e 100644 --- a/src/com/hypixel/hytale/server/core/io/commands/BindingsCommand.java +++ b/src/com/hypixel/hytale/server/core/io/commands/BindingsCommand.java @@ -15,7 +15,7 @@ public class BindingsCommand extends CommandBase { private static final Message MESSAGE_IO_SERVER_MANAGER_BINDINGS = Message.translation("server.io.servermanager.bindings"); public BindingsCommand() { - super("bindings", "server.io.servermanager.bindings"); + super("bindings", "server.io.servermanager.bindings.description"); } @Override diff --git a/src/com/hypixel/hytale/server/core/io/handlers/InitialPacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/InitialPacketHandler.java index deab77a1..fca09f7c 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/InitialPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/InitialPacketHandler.java @@ -75,9 +75,9 @@ public class InitialPacketHandler extends PacketHandler { this.receivedConnect = true; this.clearTimeout(); PacketHandler.logConnectionTimings(this.channel, "Connect", Level.FINE); - if (packet.protocolCrc != 1789265863) { + if (packet.protocolCrc != 701662755) { int clientBuild = packet.protocolBuildNumber; - int serverBuild = 2; + int serverBuild = 5; int errorCode; if (clientBuild < serverBuild) { errorCode = 5; diff --git a/src/com/hypixel/hytale/server/core/io/handlers/SetupPacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/SetupPacketHandler.java index 88b0fc42..10c4d4fc 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/SetupPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/SetupPacketHandler.java @@ -243,7 +243,7 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { AssetRegistryLoader.sendAssets(this); I18nModule.get().sendTranslations(this, this.language); PacketHandler.logConnectionTimings(this.channel, "Send Config Assets", Level.FINE); - this.write(new WorldLoadProgress("Loading world...", 0, 0)); + this.write(new WorldLoadProgress(Message.translation("client.general.worldLoad.loadingWorld").getFormattedMessage(), 0, 0)); this.write(new WorldLoadFinished()); } }) diff --git a/src/com/hypixel/hytale/server/core/io/handlers/game/GamePacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/game/GamePacketHandler.java index 7a399304..c8eb4f7f 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/game/GamePacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/game/GamePacketHandler.java @@ -44,6 +44,7 @@ import com.hypixel.hytale.protocol.packets.window.CloseWindow; import com.hypixel.hytale.protocol.packets.window.SendWindowAction; import com.hypixel.hytale.protocol.packets.window.UpdateWindow; import com.hypixel.hytale.protocol.packets.world.SetPaused; +import com.hypixel.hytale.protocol.packets.worldmap.CreateUserMarker; import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.protocol.packets.worldmap.TeleportToWorldMapMarker; import com.hypixel.hytale.protocol.packets.worldmap.TeleportToWorldMapPosition; @@ -61,7 +62,6 @@ import com.hypixel.hytale.server.core.auth.PlayerAuthentication; import com.hypixel.hytale.server.core.command.system.CommandManager; import com.hypixel.hytale.server.core.console.ConsoleModule; import com.hypixel.hytale.server.core.entity.entities.Player; -import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerWorldData; import com.hypixel.hytale.server.core.entity.entities.player.pages.PageManager; import com.hypixel.hytale.server.core.entity.entities.player.windows.ValidatedWindow; import com.hypixel.hytale.server.core.entity.entities.player.windows.Window; @@ -93,9 +93,12 @@ import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.WorldMapTracker; import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk; +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.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.utils.MapMarkerUtils; import com.hypixel.hytale.server.core.util.MessageUtil; import com.hypixel.hytale.server.core.util.PositionUtil; import com.hypixel.hytale.server.core.util.ValidateUtil; @@ -187,6 +190,7 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa this.registerHandler(243, p -> this.handle((UpdateWorldMapVisible)p)); this.registerHandler(244, p -> this.handle((TeleportToWorldMapMarker)p)); this.registerHandler(245, p -> this.handle((TeleportToWorldMapPosition)p)); + this.registerHandler(246, p -> this.handle((CreateUserMarker)p)); this.registerHandler(290, p -> this.handle((SyncInteractionChains)p)); this.registerHandler(158, p -> this.handle((SetPaused)p)); this.registerHandler(282, p -> this.handle((RequestFlyCameraMode)p)); @@ -205,7 +209,13 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa if (this.playerRef != null) { HytaleLogger.getLogger() .at(Level.INFO) - .log("Disconnecting %s at %s with the message: %s", this.playerRef.getUsername(), NettyUtil.formatRemoteAddress(this.channel), message); + .log( + "Disconnecting %s at %s (SNI: %s) with the message: %s", + this.playerRef.getUsername(), + NettyUtil.formatRemoteAddress(this.channel), + this.getSniHostname(), + message + ); this.disconnect0(message); Universe.get().removePlayer(this.playerRef); } else { @@ -530,14 +540,6 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa Vector3i targetBlock = new Vector3i(packet.position.x, packet.position.y, packet.position.z); BlockRotation blockRotation = new BlockRotation(packet.rotation.rotationYaw, packet.rotation.rotationPitch, packet.rotation.rotationRoll); TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); - if (transformComponent != null && playerComponent.getGameMode() != GameMode.Creative) { - Vector3d position = transformComponent.getPosition(); - Vector3d blockCenter = new Vector3d(targetBlock.x + 0.5, targetBlock.y + 0.5, targetBlock.z + 0.5); - if (position.distanceSquaredTo(blockCenter) > 36.0) { - return; - } - } - Store chunkStore = world.getChunkStore().getStore(); long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); Ref chunkReference = chunkStore.getExternalData().getChunkReference(chunkIndex); @@ -546,6 +548,15 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa if (blockChunk != null) { BlockSection section = blockChunk.getSectionAtBlockY(targetBlock.y); if (section != null) { + if (transformComponent != null && playerComponent.getGameMode() != GameMode.Creative) { + Vector3d position = transformComponent.getPosition(); + Vector3d blockCenter = new Vector3d(targetBlock.x + 0.5, targetBlock.y + 0.5, targetBlock.z + 0.5); + if (position.distanceSquaredTo(blockCenter) > 49.0) { + section.invalidateBlock(targetBlock.x, targetBlock.y, targetBlock.z); + return; + } + } + ItemStack itemInHand = playerComponent.getInventory().getItemInHand(); if (itemInHand == null) { section.invalidateBlock(targetBlock.x, targetBlock.y, targetBlock.z); @@ -592,14 +603,7 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa if (ref != null && ref.isValid()) { Store store = ref.getStore(); World world = store.getExternalData().getWorld(); - world.execute(() -> { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); - - assert playerComponent != null; - - PlayerWorldData perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(world.getName()); - perWorldData.removeLastDeath(packet.markerId); - }); + world.execute(() -> world.getWorldMapManager().handleUserRemoveMarker(this.playerRef, packet)); } } @@ -748,6 +752,14 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa MapMarker marker = worldMapTracker.getSentMarkers().get(packet.id); if (marker != null) { Transform transform = PositionUtil.toTransform(marker.transform); + if (MapMarkerUtils.isUserMarker(marker)) { + int blockX = (int)transform.getPosition().getX(); + int blockZ = (int)transform.getPosition().getZ(); + WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(blockX, blockZ)); + int height = chunk == null ? 319 : chunk.getHeight(blockX, blockZ); + transform.getPosition().setY(height); + } + Teleport teleportComponent = Teleport.createForPlayer(transform); world.getEntityStore().getStore().addComponent(this.playerRef.getReference(), Teleport.getComponentType(), teleportComponent); } @@ -784,6 +796,18 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa } } + public void handle(@Nonnull CreateUserMarker packet) { + Ref ref = this.playerRef.getReference(); + if (ref != null && ref.isValid()) { + Store store = ref.getStore(); + World world = store.getExternalData().getWorld(); + world.execute(() -> { + WorldMapManager worldMapManager = world.getWorldMapManager(); + worldMapManager.handleUserCreateMarker(this.playerRef, packet); + }); + } + } + public void handle(@Nonnull SyncInteractionChains packet) { Collections.addAll(this.interactionPacketQueue, packet.updates); } diff --git a/src/com/hypixel/hytale/server/core/io/handlers/game/InventoryPacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/game/InventoryPacketHandler.java index 9b72fb6b..40a60d1d 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/game/InventoryPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/game/InventoryPacketHandler.java @@ -15,6 +15,7 @@ import com.hypixel.hytale.protocol.packets.inventory.SetCreativeItem; import com.hypixel.hytale.protocol.packets.inventory.SmartGiveCreativeItem; import com.hypixel.hytale.protocol.packets.inventory.SmartMoveItemStack; import com.hypixel.hytale.protocol.packets.inventory.SwitchHotbarBlockSet; +import com.hypixel.hytale.protocol.packets.window.WindowType; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.asset.type.item.config.BlockGroup; import com.hypixel.hytale.server.core.asset.type.item.config.BlockSelectorToolData; @@ -428,62 +429,72 @@ public class InventoryPacketHandler implements SubPacketHandler { if (packet.inventorySectionId >= 0 || packet.inventorySectionId == -9) { Store store = ref.getStore(); World world = store.getExternalData().getWorld(); - world.execute(() -> { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); + world.execute( + () -> { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - Inventory inventory = playerComponent.getInventory(); - switch (packet.inventoryActionType) { - case TakeAll: - if (packet.inventorySectionId == -9) { - inventory.takeAll(packet.inventorySectionId); - return; - } - - Window window = playerComponent.getWindowManager().getWindow(packet.inventorySectionId); - if (window instanceof ItemContainerWindow) { - inventory.takeAll(packet.inventorySectionId); - } - break; - case PutAll: - if (packet.inventorySectionId == -9) { - inventory.putAll(packet.inventorySectionId); - return; - } - - Window window = playerComponent.getWindowManager().getWindow(packet.inventorySectionId); - if (window instanceof ItemContainerWindow) { - inventory.putAll(packet.inventorySectionId); - } - break; - case QuickStack: - if (packet.inventorySectionId == -9) { - inventory.quickStack(packet.inventorySectionId); - return; - } - - Window window = playerComponent.getWindowManager().getWindow(packet.inventorySectionId); - if (window instanceof ItemContainerWindow) { - inventory.quickStack(packet.inventorySectionId); - } - break; - case Sort: - SortType sortType = SortType.VALUES[packet.actionData]; - if (packet.inventorySectionId == 0) { - inventory.sortStorage(sortType); - } else { - if (packet.inventorySectionId == -9 && inventory.getBackpack() != null) { - inventory.getBackpack().sortItems(sortType); + Inventory inventory = playerComponent.getInventory(); + switch (packet.inventoryActionType) { + case TakeAll: + if (packet.inventorySectionId == -9) { + inventory.takeAll(packet.inventorySectionId); return; } - if (playerComponent.getWindowManager().getWindow(packet.inventorySectionId) instanceof ItemContainerWindow itemContainerWindow) { - itemContainerWindow.getItemContainer().sortItems(sortType); + Window window = playerComponent.getWindowManager().getWindow(packet.inventorySectionId); + if (window instanceof ItemContainerWindow itemContainerWindow) { + if (window.getType() == WindowType.Processing) { + if (itemContainerWindow.getItemContainer() instanceof CombinedItemContainer combinedItemContainer + && combinedItemContainer.getContainersSize() >= 3) { + ItemContainer outputContainer = combinedItemContainer.getContainer(2); + outputContainer.moveAllItemStacksTo(inventory.getCombinedHotbarFirst()); + } + } else { + inventory.takeAll(packet.inventorySectionId); + } } - } + break; + case PutAll: + if (packet.inventorySectionId == -9) { + inventory.putAll(packet.inventorySectionId); + return; + } + + Window window = playerComponent.getWindowManager().getWindow(packet.inventorySectionId); + if (window instanceof ItemContainerWindow) { + inventory.putAll(packet.inventorySectionId); + } + break; + case QuickStack: + if (packet.inventorySectionId == -9) { + inventory.quickStack(packet.inventorySectionId); + return; + } + + Window window = playerComponent.getWindowManager().getWindow(packet.inventorySectionId); + if (window instanceof ItemContainerWindow) { + inventory.quickStack(packet.inventorySectionId); + } + break; + case Sort: + SortType sortType = SortType.VALUES[packet.actionData]; + if (packet.inventorySectionId == 0) { + inventory.sortStorage(sortType); + } else { + if (packet.inventorySectionId == -9 && inventory.getBackpack() != null) { + inventory.getBackpack().sortItems(sortType); + return; + } + + if (playerComponent.getWindowManager().getWindow(packet.inventorySectionId) instanceof ItemContainerWindow itemContainerWindow) { + itemContainerWindow.getItemContainer().sortItems(sortType); + } + } + } } - }); + ); } } } diff --git a/src/com/hypixel/hytale/server/core/io/handlers/login/PasswordPacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/login/PasswordPacketHandler.java index f1c25f1f..bcde9561 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/login/PasswordPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/login/PasswordPacketHandler.java @@ -166,7 +166,7 @@ public class PasswordPacketHandler extends GenericConnectionPacketHandler { this.auth.setReferralSource(this.referralSource); } - LOGGER.at(Level.INFO).log("Connection complete for %s (%s), transitioning to setup", this.username, this.playerUuid); + LOGGER.at(Level.INFO).log("Connection complete for %s (%s) (SNI: %s), transitioning to setup", this.username, this.playerUuid, this.getSniHostname()); NettyUtil.setChannelHandler(this.channel, this.setupHandlerSupplier.create(this.channel, this.protocolVersion, this.language, this.auth)); } diff --git a/src/com/hypixel/hytale/server/core/io/transport/QUICTransport.java b/src/com/hypixel/hytale/server/core/io/transport/QUICTransport.java index aa9c8a57..25cf605b 100644 --- a/src/com/hypixel/hytale/server/core/io/transport/QUICTransport.java +++ b/src/com/hypixel/hytale/server/core/io/transport/QUICTransport.java @@ -27,9 +27,12 @@ import io.netty.handler.codec.quic.QuicServerCodecBuilder; import io.netty.handler.codec.quic.QuicSslContext; import io.netty.handler.codec.quic.QuicSslContextBuilder; import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.SniCompletionEvent; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.SelfSignedCertificate; import io.netty.util.AttributeKey; +import io.netty.util.Mapping; +import java.lang.reflect.Field; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetSocketAddress; @@ -48,6 +51,7 @@ public class QUICTransport implements Transport { private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static final AttributeKey CLIENT_CERTIFICATE_ATTR = AttributeKey.valueOf("CLIENT_CERTIFICATE"); public static final AttributeKey ALPN_REJECT_ERROR_CODE_ATTR = AttributeKey.valueOf("ALPN_REJECT_ERROR_CODE"); + public static final AttributeKey SNI_HOSTNAME_ATTR = AttributeKey.valueOf("SNI_HOSTNAME"); @Nonnull private final EventLoopGroup workerGroup = NettyUtil.getEventLoopGroup("ServerWorkerGroup"); private final Bootstrap bootstrapIpv4; @@ -58,18 +62,31 @@ public class QUICTransport implements Transport { try { ssc = new SelfSignedCertificate("localhost"); - } catch (CertificateException var5) { - throw new RuntimeException(var5); + } catch (CertificateException var7) { + throw new RuntimeException(var7); } ServerAuthManager.getInstance().setServerCertificate(ssc.cert()); LOGGER.at(Level.INFO).log("Server certificate registered for mutual auth, fingerprint: %s", CertificateUtil.computeCertificateFingerprint(ssc.cert())); - QuicSslContext sslContext = QuicSslContextBuilder.forServer(ssc.key(), null, ssc.cert()) + QuicSslContext baseSslContext = QuicSslContextBuilder.forServer(ssc.key(), null, ssc.cert()) .applicationProtocols("hytale/2", "hytale/1") .earlyData(false) .clientAuth(ClientAuth.REQUIRE) .trustManager(InsecureTrustManagerFactory.INSTANCE) .build(); + + QuicSslContext sslContext; + try { + QuicSslContextBuilder builder = QuicSslContextBuilder.forServer(ssc.key(), null, ssc.cert()).earlyData(false).clientAuth(ClientAuth.REQUIRE); + Field field = builder.getClass().getDeclaredField("mapping"); + field.setAccessible(true); + field.set(builder, (Mapping)sni -> baseSslContext); + sslContext = builder.build(); + } catch (IllegalAccessException | NoSuchFieldException var6) { + LOGGER.at(Level.WARNING).withCause(var6).log("Failed to set SNI mapping via reflection, SNI support disabled"); + sslContext = baseSslContext; + } + NettyUtil.ReflectiveChannelFactory channelFactoryIpv4 = NettyUtil.getDatagramChannelFactory(SocketProtocolFamily.INET); LOGGER.at(Level.INFO).log("Using IPv4 Datagram Channel: %s...", channelFactoryIpv4.getSimpleName()); this.bootstrapIpv4 = new Bootstrap() @@ -156,18 +173,34 @@ public class QUICTransport implements Transport { return true; } + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof SniCompletionEvent sniEvent) { + ctx.channel().attr(QUICTransport.SNI_HOSTNAME_ATTR).set(sniEvent.hostname()); + } + + super.userEventTriggered(ctx, evt); + } + @Override public void channelActive(@Nonnull ChannelHandlerContext ctx) throws Exception { QuicChannel channel = (QuicChannel)ctx.channel(); + String sni = channel.attr(QUICTransport.SNI_HOSTNAME_ATTR).get(); QUICTransport.LOGGER .at(Level.INFO) - .log("Received connection from %s to %s", NettyUtil.formatRemoteAddress(channel), NettyUtil.formatLocalAddress(channel)); + .log("Received connection from %s to %s (SNI: %s)", NettyUtil.formatRemoteAddress(channel), NettyUtil.formatLocalAddress(channel), sni); String negotiatedAlpn = channel.sslEngine().getApplicationProtocol(); int negotiatedVersion = this.parseProtocolVersion(negotiatedAlpn); if (negotiatedVersion < 2) { QUICTransport.LOGGER .at(Level.INFO) - .log("Marking connection from %s for rejection: ALPN %s < required %d", NettyUtil.formatRemoteAddress(channel), negotiatedAlpn, 2); + .log( + "Marking connection from %s (SNI: %s) for rejection: ALPN %s < required %d", + NettyUtil.formatRemoteAddress(channel), + sni, + negotiatedAlpn, + 2 + ); channel.attr(QUICTransport.ALPN_REJECT_ERROR_CODE_ATTR).set(5); } @@ -175,7 +208,7 @@ public class QUICTransport implements Transport { if (clientCert == null) { QUICTransport.LOGGER .at(Level.WARNING) - .log("Connection rejected: no client certificate from %s", NettyUtil.formatRemoteAddress(channel)); + .log("Connection rejected: no client certificate from %s (SNI: %s)", NettyUtil.formatRemoteAddress(channel), sni); ProtocolUtil.closeConnection(channel); } else { channel.attr(QUICTransport.CLIENT_CERTIFICATE_ATTR).set(clientCert); diff --git a/src/com/hypixel/hytale/server/core/modules/LegacyModule.java b/src/com/hypixel/hytale/server/core/modules/LegacyModule.java index 6c2f5f9d..49ae1edf 100644 --- a/src/com/hypixel/hytale/server/core/modules/LegacyModule.java +++ b/src/com/hypixel/hytale/server/core/modules/LegacyModule.java @@ -1,5 +1,6 @@ package com.hypixel.hytale.server.core.modules; +import com.hypixel.hytale.assetstore.event.LoadedAssetsEvent; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.codecs.array.ArrayCodec; @@ -19,6 +20,7 @@ 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.asset.type.gameplay.GameplayConfig; 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; @@ -35,6 +37,7 @@ import com.hypixel.hytale.server.core.universe.world.chunk.section.blockposition 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 com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.util.Set; import java.util.logging.Level; @@ -94,6 +97,7 @@ public class LegacyModule extends JavaPlugin { .registerComponent(LegacyModule.LegacyBlockStateChunk.class, "BlockStateChunk", LegacyModule.LegacyBlockStateChunk.CODEC, true); this.getChunkStoreRegistry() .registerSystem(new LegacyModule.MigrateLegacyBlockStateChunkSystem(legacyBlockStateComponentType, this.blockComponentChunkComponentType)); + this.getEventRegistry().register(LoadedAssetsEvent.class, GameplayConfig.class, event -> WorldMapManager.sendSettingsToAllWorlds()); } public ComponentType getWorldChunkComponentType() { diff --git a/src/com/hypixel/hytale/server/core/modules/block/BlockModule.java b/src/com/hypixel/hytale/server/core/modules/block/BlockModule.java index 100bede5..6263c4bc 100644 --- a/src/com/hypixel/hytale/server/core/modules/block/BlockModule.java +++ b/src/com/hypixel/hytale/server/core/modules/block/BlockModule.java @@ -5,6 +5,7 @@ import com.hypixel.hytale.common.plugin.PluginManifest; import com.hypixel.hytale.component.AddReason; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.Component; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.Ref; @@ -65,31 +66,33 @@ public class BlockModule extends JavaPlugin { @Override protected void setup() { - this.migrationSystemType = this.getChunkStoreRegistry().registerSystemType(BlockModule.MigrationSystem.class); - this.blockStateInfoComponentType = this.getChunkStoreRegistry().registerComponent(BlockModule.BlockStateInfo.class, () -> { + ComponentRegistryProxy chunkStoreRegistry = this.getChunkStoreRegistry(); + this.migrationSystemType = chunkStoreRegistry.registerSystemType(BlockModule.MigrationSystem.class); + this.blockStateInfoComponentType = chunkStoreRegistry.registerComponent(BlockModule.BlockStateInfo.class, () -> { throw new UnsupportedOperationException(); }); - this.getChunkStoreRegistry().registerSystem(new BlockModule.BlockStateInfoRefSystem(this.blockStateInfoComponentType)); - this.launchPadComponentType = this.getChunkStoreRegistry().registerComponent(LaunchPad.class, "LaunchPad", LaunchPad.CODEC); - this.getChunkStoreRegistry().registerSystem(new BlockModule.MigrateLaunchPad()); - this.respawnBlockComponentType = this.getChunkStoreRegistry().registerComponent(RespawnBlock.class, "RespawnBlock", RespawnBlock.CODEC); - this.getChunkStoreRegistry().registerSystem(new RespawnBlock.OnRemove()); - this.blockMapMarkerComponentType = this.getChunkStoreRegistry().registerComponent(BlockMapMarker.class, "BlockMapMarker", BlockMapMarker.CODEC); - this.blockMapMarkersResourceType = this.getChunkStoreRegistry() - .registerResource(BlockMapMarkersResource.class, "BlockMapMarkers", BlockMapMarkersResource.CODEC); - this.getChunkStoreRegistry().registerSystem(new BlockMapMarker.OnAddRemove()); + chunkStoreRegistry.registerSystem(new BlockModule.BlockStateInfoRefSystem(this.blockStateInfoComponentType)); + this.launchPadComponentType = chunkStoreRegistry.registerComponent(LaunchPad.class, "LaunchPad", LaunchPad.CODEC); + chunkStoreRegistry.registerSystem(new BlockModule.MigrateLaunchPad()); + this.respawnBlockComponentType = chunkStoreRegistry.registerComponent(RespawnBlock.class, "RespawnBlock", RespawnBlock.CODEC); + chunkStoreRegistry.registerSystem(new RespawnBlock.OnRemove()); + this.blockMapMarkerComponentType = chunkStoreRegistry.registerComponent(BlockMapMarker.class, "BlockMapMarker", BlockMapMarker.CODEC); + this.blockMapMarkersResourceType = chunkStoreRegistry.registerResource(BlockMapMarkersResource.class, "BlockMapMarkers", BlockMapMarkersResource.CODEC); + chunkStoreRegistry.registerSystem(new BlockMapMarker.OnAddRemove()); this.getEventRegistry() .registerGlobal( AddWorldEvent.class, event -> event.getWorld().getWorldMapManager().getMarkerProviders().put("blockMapMarkers", BlockMapMarker.MarkerProvider.INSTANCE) ); - this.blockStateInfoNeedRebuildResourceType = this.getChunkStoreRegistry() - .registerResource(BlockModule.BlockStateInfoNeedRebuild.class, BlockModule.BlockStateInfoNeedRebuild::new); + this.blockStateInfoNeedRebuildResourceType = chunkStoreRegistry.registerResource( + BlockModule.BlockStateInfoNeedRebuild.class, BlockModule.BlockStateInfoNeedRebuild::new + ); this.getEventRegistry().registerGlobal(EventPriority.EARLY, ChunkPreLoadProcessEvent.class, BlockModule::onChunkPreLoadProcessEnsureBlockEntity); } @Deprecated - public static Ref ensureBlockEntity(WorldChunk chunk, int x, int y, int z) { + @Nullable + public static Ref ensureBlockEntity(@Nonnull WorldChunk chunk, int x, int y, int z) { Ref blockRef = chunk.getBlockComponentEntity(x, y, z); if (blockRef != null) { return blockRef; @@ -115,40 +118,41 @@ public class BlockModule extends JavaPlugin { BlockTypeAssetMap blockTypeAssetMap = BlockType.getAssetMap(); Holder holder = event.getHolder(); WorldChunk chunk = event.getChunk(); - ChunkColumn column = holder.getComponent(ChunkColumn.getComponentType()); - if (column != null) { - Holder[] sections = column.getSectionHolders(); - if (sections != null) { + ChunkColumn chunkColumnComponent = holder.getComponent(ChunkColumn.getComponentType()); + if (chunkColumnComponent != null) { + Holder[] sectionHolders = chunkColumnComponent.getSectionHolders(); + if (sectionHolders != null) { BlockComponentChunk blockComponentModule = holder.getComponent(BlockComponentChunk.getComponentType()); + if (blockComponentModule != null) { + for (int sectionIndex = 0; sectionIndex < 10; sectionIndex++) { + BlockSection section = sectionHolders[sectionIndex].ensureAndGetComponent(BlockSection.getComponentType()); + if (!section.isSolidAir()) { + int sectionYBlock = sectionIndex << 5; - for (int sectionIndex = 0; sectionIndex < 10; sectionIndex++) { - BlockSection section = sections[sectionIndex].ensureAndGetComponent(BlockSection.getComponentType()); - if (!section.isSolidAir()) { - int sectionYBlock = sectionIndex << 5; + for (int sectionY = 0; sectionY < 32; sectionY++) { + int y = sectionYBlock | sectionY; - for (int sectionY = 0; sectionY < 32; sectionY++) { - int y = sectionYBlock | sectionY; + for (int z = 0; z < 32; z++) { + for (int x = 0; x < 32; x++) { + int blockId = section.get(x, y, z); + BlockType blockType = blockTypeAssetMap.getAsset(blockId); + if (blockType != null && !blockType.isUnknown() && section.getFiller(x, y, z) == 0) { + int index = ChunkUtil.indexBlockInColumn(x, y, z); + if (blockType.getBlockEntity() != null) { + if (blockComponentModule.getEntityHolder(index) != null) { + continue; + } - for (int z = 0; z < 32; z++) { - for (int x = 0; x < 32; x++) { - int blockId = section.get(x, y, z); - BlockType blockType = blockTypeAssetMap.getAsset(blockId); - if (blockType != null && !blockType.isUnknown() && section.getFiller(x, y, z) == 0) { - int index = ChunkUtil.indexBlockInColumn(x, y, z); - if (blockType.getBlockEntity() != null) { - if (blockComponentModule.getEntityHolder(index) != null) { - continue; + blockComponentModule.addEntityHolder(index, blockType.getBlockEntity().clone()); } - blockComponentModule.addEntityHolder(index, blockType.getBlockEntity().clone()); - } - - StateData state = blockType.getState(); - if (state != null && state.getId() != null && blockComponentModule.getEntityHolder(index) == null) { - Vector3i position = new Vector3i(x, y, z); - BlockState blockState = BlockStateModule.get().createBlockState(state.getId(), chunk, position, blockType); - if (blockState != null) { - blockComponentModule.addEntityHolder(index, blockState.toHolder()); + StateData state = blockType.getState(); + if (state != null && state.getId() != null && blockComponentModule.getEntityHolder(index) == null) { + Vector3i position = new Vector3i(x, y, z); + BlockState blockState = BlockStateModule.get().createBlockState(state.getId(), chunk, position, blockType); + if (blockState != null) { + blockComponentModule.addEntityHolder(index, blockState.toHolder()); + } } } } @@ -209,16 +213,20 @@ public class BlockModule extends JavaPlugin { } @Nullable - public > T getComponent(ComponentType componentType, World world, int x, int y, int z) { + public static > T getComponent(ComponentType componentType, World world, int x, int y, int z) { Store chunkStore = world.getChunkStore().getStore(); Ref chunkRef = world.getChunkStore().getChunkReference(ChunkUtil.indexChunkFromBlock(x, z)); - BlockComponentChunk blockComponentChunk = chunkStore.getComponent(chunkRef, BlockComponentChunk.getComponentType()); - if (blockComponentChunk == null) { - return null; + if (chunkRef != null && chunkRef.isValid()) { + BlockComponentChunk blockComponentChunk = chunkStore.getComponent(chunkRef, BlockComponentChunk.getComponentType()); + if (blockComponentChunk == null) { + return null; + } else { + int blockIndex = ChunkUtil.indexBlockInColumn(x, y, z); + Ref blockRef = blockComponentChunk.getEntityReference(blockIndex); + return blockRef != null && blockRef.isValid() ? chunkStore.getComponent(blockRef, componentType) : null; + } } else { - int blockIndex = ChunkUtil.indexBlockInColumn(x, y, z); - Ref blockRef = blockComponentChunk.getEntityReference(blockIndex); - return blockRef != null && blockRef.isValid() ? chunkStore.getComponent(blockRef, componentType) : null; + return null; } } @@ -247,7 +255,7 @@ public class BlockModule extends JavaPlugin { } public void markNeedsSaving() { - if (this.chunkRef != null && this.chunkRef.isValid()) { + if (this.chunkRef.isValid()) { BlockComponentChunk blockComponentChunk = this.chunkRef.getStore().getComponent(this.chunkRef, BlockComponentChunk.getComponentType()); if (blockComponentChunk != null) { blockComponentChunk.markNeedsSaving(); @@ -297,31 +305,37 @@ public class BlockModule extends JavaPlugin { } public static class BlockStateInfoRefSystem extends RefSystem { - private final ComponentType componentType; + @Nonnull + private final ComponentType blockStateInfoComponentType; - public BlockStateInfoRefSystem(ComponentType componentType) { - this.componentType = componentType; + public BlockStateInfoRefSystem(@Nonnull ComponentType blockStateInfoComponentType) { + this.blockStateInfoComponentType = blockStateInfoComponentType; } @Override public Query getQuery() { - return this.componentType; + return this.blockStateInfoComponentType; } @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - BlockModule.BlockStateInfo blockState = commandBuffer.getComponent(ref, this.componentType); - Ref chunk = blockState.chunkRef; - if (chunk != null) { - BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunk, BlockComponentChunk.getComponentType()); - switch (reason) { - case SPAWN: - blockComponentChunk.addEntityReference(blockState.getIndex(), ref); - break; - case LOAD: - blockComponentChunk.loadEntityReference(blockState.getIndex(), ref); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, this.blockStateInfoComponentType); + + assert blockStateInfoComponent != null; + + Ref chunkRef = blockStateInfoComponent.chunkRef; + if (chunkRef.isValid()) { + BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunkRef, BlockComponentChunk.getComponentType()); + if (blockComponentChunk != null) { + switch (reason) { + case SPAWN: + blockComponentChunk.addEntityReference(blockStateInfoComponent.getIndex(), ref); + break; + case LOAD: + blockComponentChunk.loadEntityReference(blockStateInfoComponent.getIndex(), ref); + } } } } @@ -330,16 +344,21 @@ public class BlockModule extends JavaPlugin { public void onEntityRemove( @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - BlockModule.BlockStateInfo blockState = commandBuffer.getComponent(ref, this.componentType); - Ref chunk = blockState.chunkRef; - if (chunk != null) { - BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunk, BlockComponentChunk.getComponentType()); - switch (reason) { - case REMOVE: - blockComponentChunk.removeEntityReference(blockState.getIndex(), ref); - break; - case UNLOAD: - blockComponentChunk.unloadEntityReference(blockState.getIndex(), ref); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, this.blockStateInfoComponentType); + + assert blockStateInfoComponent != null; + + Ref chunkRef = blockStateInfoComponent.chunkRef; + if (chunkRef.isValid()) { + BlockComponentChunk blockComponentChunk = commandBuffer.getComponent(chunkRef, BlockComponentChunk.getComponentType()); + if (blockComponentChunk != null) { + switch (reason) { + case REMOVE: + blockComponentChunk.removeEntityReference(blockStateInfoComponent.getIndex(), ref); + break; + case UNLOAD: + blockComponentChunk.unloadEntityReference(blockStateInfoComponent.getIndex(), ref); + } } } } @@ -347,7 +366,7 @@ public class BlockModule extends JavaPlugin { @Nonnull @Override public String toString() { - return "BlockStateInfoRefSystem{componentType=" + this.componentType + "}"; + return "BlockStateInfoRefSystem{componentType=" + this.blockStateInfoComponentType + "}"; } } @@ -355,13 +374,13 @@ public class BlockModule extends JavaPlugin { public static class MigrateLaunchPad extends BlockModule.MigrationSystem { @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - UnknownComponents unknown = holder.getComponent(ChunkStore.REGISTRY.getUnknownComponentType()); + UnknownComponents unknownComponents = holder.getComponent(ChunkStore.REGISTRY.getUnknownComponentType()); - assert unknown != null; + assert unknownComponents != null; - LaunchPad launchPad = unknown.removeComponent("launchPad", LaunchPad.CODEC); - if (launchPad != null) { - holder.putComponent(LaunchPad.getComponentType(), launchPad); + LaunchPad launchPadComponent = unknownComponents.removeComponent("launchPad", LaunchPad.CODEC); + if (launchPadComponent != null) { + holder.putComponent(LaunchPad.getComponentType(), launchPadComponent); } } diff --git a/src/com/hypixel/hytale/server/core/modules/collision/CollisionDataArray.java b/src/com/hypixel/hytale/server/core/modules/collision/CollisionDataArray.java index 65c25c51..1b7b5c2c 100644 --- a/src/com/hypixel/hytale/server/core/modules/collision/CollisionDataArray.java +++ b/src/com/hypixel/hytale/server/core/modules/collision/CollisionDataArray.java @@ -13,11 +13,12 @@ public class CollisionDataArray { @Nonnull private final List array = new ObjectArrayList<>(); private final Supplier supplier; + @Nullable private final Consumer dispose; private final List freeList; private int head; - public CollisionDataArray(Supplier supplier, Consumer dispose, List freeList) { + public CollisionDataArray(Supplier supplier, @Nullable Consumer dispose, List freeList) { Objects.requireNonNull(supplier, "Must provide supplier for CollisionDataArray"); this.supplier = supplier; this.dispose = dispose; diff --git a/src/com/hypixel/hytale/server/core/modules/collision/CollisionModule.java b/src/com/hypixel/hytale/server/core/modules/collision/CollisionModule.java index 413d047c..7dddd400 100644 --- a/src/com/hypixel/hytale/server/core/modules/collision/CollisionModule.java +++ b/src/com/hypixel/hytale/server/core/modules/collision/CollisionModule.java @@ -31,17 +31,20 @@ import java.util.List; import java.util.function.Predicate; import java.util.logging.Level; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class CollisionModule extends JavaPlugin { + @Nonnull public static final PluginManifest MANIFEST = PluginManifest.corePlugin(CollisionModule.class).build(); public static final int VALIDATE_INVALID = -1; public static final int VALIDATE_OK = 0; public static final int VALIDATE_ON_GROUND = 1; public static final int VALIDATE_TOUCH_CEIL = 2; private static CollisionModule instance; - private ResourceType, EntityStore>> tangiableEntitySpatialComponent; + private ResourceType, EntityStore>> tangibleEntitySpatialResourceType; private double extentMax; private double minimumThickness; + @Nonnull private final Config config = this.withConfig("CollisionModule", CollisionModuleConfig.CODEC); public static CollisionModule get() { @@ -53,6 +56,7 @@ public class CollisionModule extends JavaPlugin { instance = this; } + @Nonnull public CollisionModuleConfig getConfig() { return this.config.get(); } @@ -61,11 +65,11 @@ public class CollisionModule extends JavaPlugin { protected void setup() { this.getCommandRegistry().registerCommand(new HitboxCommand()); this.getEventRegistry().register(LoadedAssetsEvent.class, BlockBoundingBoxes.class, this::onLoadedAssetsEvent); - this.tangiableEntitySpatialComponent = this.getEntityStoreRegistry().registerSpatialResource(() -> new KDTree<>(Ref::isValid)); + this.tangibleEntitySpatialResourceType = this.getEntityStoreRegistry().registerSpatialResource(() -> new KDTree<>(Ref::isValid)); } - public ResourceType, EntityStore>> getTangiableEntitySpatialComponent() { - return this.tangiableEntitySpatialComponent; + public ResourceType, EntityStore>> getTangibleEntitySpatialResourceType() { + return this.tangibleEntitySpatialResourceType; } private void onLoadedAssetsEvent(@Nonnull LoadedAssetsEvent> event) { @@ -209,18 +213,17 @@ public class CollisionModule extends JavaPlugin { } TransformComponent entityTransformComponent = componentAccessor.getComponent(ref, TransformComponent.getComponentType()); - - assert entityTransformComponent != null; - - BoundingBox entityBoundingBoxComponent = componentAccessor.getComponent(ref, BoundingBox.getComponentType()); - - assert entityBoundingBoxComponent != null; - - Vector3d position = entityTransformComponent.getPosition(); - Box boundingBox = entityBoundingBoxComponent.getBoundingBox(); - if (boundingBox != null && CollisionMath.intersectVectorAABB(pos, v, position.getX(), position.getY(), position.getZ(), boundingBox, minMax)) { - coll.assign(pos).addScaled(v, minMax.x); - result.allocCharacterCollision().assign(coll, minMax.x, entity.getReference(), entity instanceof Player); + if (entityTransformComponent != null) { + BoundingBox entityBoundingBoxComponent = componentAccessor.getComponent(ref, BoundingBox.getComponentType()); + if (entityBoundingBoxComponent != null) { + Vector3d position = entityTransformComponent.getPosition(); + Box boundingBox = entityBoundingBoxComponent.getBoundingBox(); + if (boundingBox != null + && CollisionMath.intersectVectorAABB(pos, v, position.getX(), position.getY(), position.getZ(), boundingBox, minMax)) { + coll.assign(pos).addScaled(v, minMax.x); + result.allocCharacterCollision().assign(coll, minMax.x, entity.getReference(), entity instanceof Player); + } + } } } } @@ -452,7 +455,7 @@ public class CollisionModule extends JavaPlugin { @Nonnull Box collider, @Nonnull Vector3d pos, int invalidBlockMaterials, - T t, + @Nullable T t, @Nonnull CollisionFilter predicate, @Nonnull CollisionResult result ) { @@ -471,8 +474,8 @@ public class CollisionModule extends JavaPlugin { @Nonnull World world, @Nonnull Box collider, @Nonnull Vector3d pos, - T t, - @Nonnull CollisionFilter predicate, + @Nullable T t, + @Nullable CollisionFilter predicate, boolean disableDamageBlocks, @Nonnull CollisionResult result ) { @@ -576,11 +579,11 @@ public class CollisionModule extends JavaPlugin { return result.validate; } - private static void addImmediateCollision(@Nonnull Vector3d pos, @Nonnull CollisionResult result, @Nonnull CollisionConfig coll, int i) { + private static void addImmediateCollision(@Nonnull Vector3d pos, @Nonnull CollisionResult result, @Nonnull CollisionConfig config, int i) { BlockCollisionData data = result.newCollision(); data.setStart(pos, 0.0); data.setEnd(1.0, result.getBoxBlockIntersection().getCollisionNormal()); - data.setBlockData(coll); + data.setBlockData(config); data.setDetailBoxIndex(i); data.setTouchingOverlapping(false, true); } @@ -590,7 +593,7 @@ public class CollisionModule extends JavaPlugin { } private static void logOverlap( - @Nonnull Vector3d pos, @Nonnull Box collider, @Nonnull CollisionConfig coll, @Nonnull Box hitBox, int x, int y, int z, int index, int intersectType + @Nonnull Vector3d pos, @Nonnull Box collider, @Nonnull CollisionConfig config, @Nonnull Box hitBox, int x, int y, int z, int index, int intersectType ) { get() .getLogger() @@ -602,12 +605,12 @@ public class CollisionModule extends JavaPlugin { (intersectType & 32) != 0 ? "Z" : "", index, Vector3d.formatShortString(pos), - x + coll.getBoundingBoxOffsetX(), - y + coll.getBoundingBoxOffsetY(), - z + coll.getBoundingBoxOffsetZ(), - coll.blockId, - coll.blockMaterial != null ? coll.blockMaterial.name() : "none", - coll.blockType != null ? coll.blockType.getId() : "none", + x + config.getBoundingBoxOffsetX(), + y + config.getBoundingBoxOffsetY(), + z + config.getBoundingBoxOffsetZ(), + config.blockId, + config.blockMaterial != null ? config.blockMaterial.name() : "none", + config.blockType != null ? config.blockType.getId() : "none", collider, Vector3d.formatShortString(hitBox.min), Vector3d.formatShortString(hitBox.max) diff --git a/src/com/hypixel/hytale/server/core/modules/collision/EntityRefCollisionProvider.java b/src/com/hypixel/hytale/server/core/modules/collision/EntityRefCollisionProvider.java index 39e26a03..cd63093a 100644 --- a/src/com/hypixel/hytale/server/core/modules/collision/EntityRefCollisionProvider.java +++ b/src/com/hypixel/hytale/server/core/modules/collision/EntityRefCollisionProvider.java @@ -127,9 +127,11 @@ public class EntityRefCollisionProvider { this.position = pos; this.direction = dir; this.boundingBox = boundingBox; - SpatialResource, EntityStore> spatial = commandBuffer.getResource(CollisionModule.get().getTangiableEntitySpatialComponent()); + SpatialResource, EntityStore> tangibleEntitySpatialResourceType = commandBuffer.getResource( + CollisionModule.get().getTangibleEntitySpatialResourceType() + ); this.tmpResults.clear(); - spatial.getSpatialStructure().collect(pos, radius, this.tmpResults); + tangibleEntitySpatialResourceType.getSpatialStructure().collect(pos, radius, this.tmpResults); for (Ref result : this.tmpResults) { consumer.accept(this, result, commandBuffer); @@ -144,36 +146,38 @@ public class EntityRefCollisionProvider { protected boolean isColliding(@Nonnull Ref ref, @Nonnull Vector2d minMax, @Nonnull CommandBuffer commandBuffer) { BoundingBox boundingBoxComponent = commandBuffer.getComponent(ref, BoundingBox.getComponentType()); - - assert boundingBoxComponent != null; - - TransformComponent transformComponent = commandBuffer.getComponent(ref, TransformComponent.getComponentType()); - - assert transformComponent != null; - - Box entityBoundingBox = boundingBoxComponent.getBoundingBox(); - if (boundingBoxComponent.getDetailBoxes() != null && !boundingBoxComponent.getDetailBoxes().isEmpty()) { - for (Entry e : boundingBoxComponent.getDetailBoxes().entrySet()) { - for (DetailBox v : e.getValue()) { - this.tmpVector.assign(v.getOffset()); - this.tmpVector.rotateY(transformComponent.getRotation().getYaw()); - this.tmpVector.add(transformComponent.getPosition()); - if (CollisionMath.intersectSweptAABBs(this.position, this.direction, this.boundingBox, this.tmpVector, v.getBox(), minMax, this.tempBox) - && minMax.x <= 1.0) { - this.hitDetail = e.getKey(); - return true; - } - } - } - - this.hitDetail = null; + if (boundingBoxComponent == null) { return false; } else { - this.hitDetail = null; - return CollisionMath.intersectSweptAABBs( - this.position, this.direction, this.boundingBox, transformComponent.getPosition(), entityBoundingBox, minMax, this.tempBox - ) - && minMax.x <= 1.0; + TransformComponent transformComponent = commandBuffer.getComponent(ref, TransformComponent.getComponentType()); + if (transformComponent == null) { + return false; + } else { + Box entityBoundingBox = boundingBoxComponent.getBoundingBox(); + if (boundingBoxComponent.getDetailBoxes() != null && !boundingBoxComponent.getDetailBoxes().isEmpty()) { + for (Entry e : boundingBoxComponent.getDetailBoxes().entrySet()) { + for (DetailBox v : e.getValue()) { + this.tmpVector.assign(v.getOffset()); + this.tmpVector.rotateY(transformComponent.getRotation().getYaw()); + this.tmpVector.add(transformComponent.getPosition()); + if (CollisionMath.intersectSweptAABBs(this.position, this.direction, this.boundingBox, this.tmpVector, v.getBox(), minMax, this.tempBox) + && minMax.x <= 1.0) { + this.hitDetail = e.getKey(); + return true; + } + } + } + + this.hitDetail = null; + return false; + } else { + this.hitDetail = null; + return CollisionMath.intersectSweptAABBs( + this.position, this.direction, this.boundingBox, transformComponent.getPosition(), entityBoundingBox, minMax, this.tempBox + ) + && minMax.x <= 1.0; + } + } } } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/EntityModule.java b/src/com/hypixel/hytale/server/core/modules/entity/EntityModule.java index 152f2af2..15e7a76b 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/EntityModule.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/EntityModule.java @@ -77,6 +77,7 @@ import com.hypixel.hytale.server.core.modules.entity.component.Interactable; import com.hypixel.hytale.server.core.modules.entity.component.Invulnerable; import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; import com.hypixel.hytale.server.core.modules.entity.component.MovementAudioComponent; +import com.hypixel.hytale.server.core.modules.entity.component.NPCMarkerComponent; import com.hypixel.hytale.server.core.modules.entity.component.NewSpawnComponent; import com.hypixel.hytale.server.core.modules.entity.component.PersistentDynamicLight; import com.hypixel.hytale.server.core.modules.entity.component.PersistentModel; @@ -206,6 +207,7 @@ public class EntityModule extends JavaPlugin { private ComponentType modelComponentType; private ComponentType persistentModelComponentType; private ComponentType propComponentType; + private ComponentType npcMarkerComponentType; private ComponentType boundingBoxComponentType; private ComponentType playerSkinComponentType; private ResourceType, EntityStore>> playerSpatialResourceType; @@ -334,7 +336,7 @@ public class EntityModule extends JavaPlugin { entityStoreRegistry.registerSystem(new EntityStore.NetworkIdSystem()); entityStoreRegistry.registerSystem(new EntityStore.UUIDSystem()); entityStoreRegistry.registerSystem(new VelocitySystems.AddSystem(this.velocityComponentType)); - entityStoreRegistry.registerSystem(new TangiableEntitySpatialSystem(CollisionModule.get().getTangiableEntitySpatialComponent())); + entityStoreRegistry.registerSystem(new TangiableEntitySpatialSystem(CollisionModule.get().getTangibleEntitySpatialResourceType())); SystemGroup _trackerGroup = EntityTrackerSystems.FIND_VISIBLE_ENTITIES_GROUP; this.visibleComponentType = entityStoreRegistry.registerComponent(EntityTrackerSystems.Visible.class, EntityTrackerSystems.Visible::new); entityStoreRegistry.registerSystem(new TransformSystems.EntityTrackerUpdate()); @@ -380,6 +382,7 @@ public class EntityModule extends JavaPlugin { }); this.persistentModelComponentType = entityStoreRegistry.registerComponent(PersistentModel.class, "Model", PersistentModel.CODEC); this.propComponentType = entityStoreRegistry.registerComponent(PropComponent.class, "Prop", PropComponent.CODEC); + this.npcMarkerComponentType = entityStoreRegistry.registerComponent(NPCMarkerComponent.class, NPCMarkerComponent::get); entityStoreRegistry.registerSystem(new EntityModule.LegacyEntityHolderSystem<>(this.playerComponentType), true); entityStoreRegistry.registerSystem(new EntityModule.LegacyEntityRefSystem<>(this.playerComponentType), true); this.playerInputComponentType = entityStoreRegistry.registerComponent(PlayerInput.class, PlayerInput::new); @@ -831,6 +834,10 @@ public class EntityModule extends JavaPlugin { return this.propComponentType; } + public ComponentType getNPCMarkerComponentType() { + return this.npcMarkerComponentType; + } + public ComponentType getBoundingBoxComponentType() { return this.boundingBoxComponentType; } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/component/NPCMarkerComponent.java b/src/com/hypixel/hytale/server/core/modules/entity/component/NPCMarkerComponent.java new file mode 100644 index 00000000..75546ae0 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/modules/entity/component/NPCMarkerComponent.java @@ -0,0 +1,26 @@ +package com.hypixel.hytale.server.core.modules.entity.component; + +import com.hypixel.hytale.component.Component; +import com.hypixel.hytale.component.ComponentType; +import com.hypixel.hytale.server.core.modules.entity.EntityModule; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; + +@Deprecated(forRemoval = true) +public class NPCMarkerComponent implements Component { + private static final NPCMarkerComponent INSTANCE = new NPCMarkerComponent(); + + public static ComponentType getComponentType() { + return EntityModule.get().getNPCMarkerComponentType(); + } + + public static NPCMarkerComponent get() { + return INSTANCE; + } + + @Nonnull + @Override + public Component clone() { + return this; + } +} diff --git a/src/com/hypixel/hytale/server/core/modules/entity/tracker/LegacyEntityTrackerSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/tracker/LegacyEntityTrackerSystems.java index 2932d4dd..c565d5c5 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/tracker/LegacyEntityTrackerSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/tracker/LegacyEntityTrackerSystems.java @@ -30,6 +30,7 @@ import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox; import com.hypixel.hytale.server.core.modules.entity.component.EntityScaleComponent; import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; +import com.hypixel.hytale.server.core.modules.entity.component.PropComponent; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entity.player.PlayerSettings; import com.hypixel.hytale.server.core.modules.entity.player.PlayerSkinComponent; @@ -115,15 +116,21 @@ public class LegacyEntityTrackerSystems { } boolean modelOutdated = modelComponent.consumeNetworkOutdated(); + Ref ref = archetypeChunk.getReferenceTo(index); + boolean isProp = store.getComponent(ref, PropComponent.getComponentType()) != null; if (modelOutdated || scaleOutdated) { - queueUpdatesFor(archetypeChunk.getReferenceTo(index), modelComponent, entityScale, visibleComponent.visibleTo); + queueUpdatesFor(ref, modelComponent, entityScale, isProp, visibleComponent.visibleTo); } else if (!visibleComponent.newlyVisibleTo.isEmpty()) { - queueUpdatesFor(archetypeChunk.getReferenceTo(index), modelComponent, entityScale, visibleComponent.newlyVisibleTo); + queueUpdatesFor(ref, modelComponent, entityScale, isProp, visibleComponent.newlyVisibleTo); } } private static void queueUpdatesFor( - Ref ref, @Nullable ModelComponent model, float entityScale, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo + Ref ref, + @Nullable ModelComponent model, + float entityScale, + boolean isProp, + @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { ComponentUpdate update = new ComponentUpdate(); update.type = ComponentUpdateType.Model; @@ -133,6 +140,16 @@ public class LegacyEntityTrackerSystems { for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); } + + if (isProp) { + ComponentUpdate propUpdate = new ComponentUpdate(); + propUpdate.type = ComponentUpdateType.Prop; + propUpdate.isProp = true; + + for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { + viewer.queueUpdate(ref, propUpdate); + } + } } } diff --git a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/client/PlaceBlockInteraction.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/client/PlaceBlockInteraction.java index 42a1d7ef..aeb853e2 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/client/PlaceBlockInteraction.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/client/PlaceBlockInteraction.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.BlockPosition; import com.hypixel.hytale.protocol.BlockRotation; import com.hypixel.hytale.protocol.GameMode; +import com.hypixel.hytale.protocol.InteractionState; import com.hypixel.hytale.protocol.InteractionSyncData; import com.hypixel.hytale.protocol.InteractionType; import com.hypixel.hytale.protocol.Rotation; @@ -40,7 +41,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PlaceBlockInteraction extends SimpleInteraction { - public static final int MAX_ADVENTURE_PLACEMENT_RANGE_SQUARED = 36; + public static final int TEMP_MAX_ADVENTURE_PLACEMENT_RANGE_SQUARED = 49; @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( PlaceBlockInteraction.class, PlaceBlockInteraction::new, SimpleInteraction.CODEC @@ -105,16 +106,19 @@ public class PlaceBlockInteraction extends SimpleInteraction { long chunkIndex = ChunkUtil.indexChunkFromBlock(blockPosition.x, blockPosition.z); Ref chunkReference = chunkStore.getExternalData().getChunkReference(chunkIndex); if (chunkReference == null || !chunkReference.isValid()) { + context.getState().state = InteractionState.Failed; return; } ItemStack heldItemStack = context.getHeldItem(); if (heldItemStack == null) { + context.getState().state = InteractionState.Failed; return; } ItemContainer heldItemContainer = context.getHeldItemContainer(); if (heldItemContainer == null) { + context.getState().state = InteractionState.Failed; return; } @@ -123,7 +127,8 @@ public class PlaceBlockInteraction extends SimpleInteraction { if (transformComponent != null && playerComponent != null && playerComponent.getGameMode() != GameMode.Creative) { Vector3d position = transformComponent.getPosition(); Vector3d blockCenter = new Vector3d(blockPosition.x + 0.5, blockPosition.y + 0.5, blockPosition.z + 0.5); - if (position.distanceSquaredTo(blockCenter) > 36.0) { + if (position.distanceSquaredTo(blockCenter) > 49.0) { + context.getState().state = InteractionState.Failed; return; } } @@ -149,6 +154,7 @@ public class PlaceBlockInteraction extends SimpleInteraction { } if (blockPosition.y < 0 || blockPosition.y >= 320) { + context.getState().state = InteractionState.Failed; return; } @@ -174,9 +180,9 @@ public class PlaceBlockInteraction extends SimpleInteraction { BlockChunk blockChunk = chunkStore.getComponent(chunkReference, BlockChunk.getComponentType()); BlockSection section = blockChunk.getSectionAtBlockY(blockPosition.y); + RotationTuple resultRotation = section.getRotation(blockPosition.x, blockPosition.y, blockPosition.z); context.getState().blockPosition = blockPosition; context.getState().placedBlockId = section.get(blockPosition.x, blockPosition.y, blockPosition.z); - RotationTuple resultRotation = section.getRotation(blockPosition.x, blockPosition.y, blockPosition.z); context.getState().blockRotation = new BlockRotation( resultRotation.yaw().toPacket(), resultRotation.pitch().toPacket(), resultRotation.roll().toPacket() ); diff --git a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/DoorInteraction.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/DoorInteraction.java index b8d7b4c3..a30ed8c8 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/DoorInteraction.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/DoorInteraction.java @@ -83,36 +83,31 @@ public class DoorInteraction extends SimpleBlockInteraction { newDoorState = DoorInteraction.DoorState.OPENED_IN; } - if (newDoorState != DoorInteraction.DoorState.CLOSED) { - DoorInteraction.DoorState checkResult = this.checkDoor(world, targetBlock, blockType, rotation, doorState, newDoorState); - if (checkResult == null) { - context.getState().state = InteractionState.Failed; - return; + DoorInteraction.DoorState checkResult = this.checkDoor(world, targetBlock, blockType, rotation, doorState, newDoorState); + if (checkResult == null) { + context.getState().state = InteractionState.Failed; + } else { + DoorInteraction.DoorState stateDoubleDoor = getOppositeDoorState(doorState); + BlockType interactionBlockState = activateDoor(world, blockType, targetBlock, doorState, checkResult); + boolean doubleDoor = this.checkForDoubleDoor(world, targetBlock, blockType, rotation, checkResult, stateDoubleDoor); + if (interactionBlockState != null) { + Vector3d pos = new Vector3d(); + int hitboxTypeIndex = BlockType.getAssetMap().getAsset(blockType.getItem().getId()).getHitboxTypeIndex(); + BlockBoundingBoxes blockBoundingBoxes = BlockBoundingBoxes.getAssetMap().getAsset(hitboxTypeIndex); + BlockBoundingBoxes.RotatedVariantBoxes rotatedBoxes = blockBoundingBoxes.get(rotation); + Box hitbox = rotatedBoxes.getBoundingBox(); + if (doubleDoor) { + Vector3d offset = new Vector3d(hitbox.middleX(), 0.0, 0.0); + Rotation rotationToCheck = RotationTuple.get(rotation).yaw(); + pos.add(MathUtil.rotateVectorYAxis(offset, rotationToCheck.getDegrees(), false)); + pos.add(hitbox.middleX(), hitbox.middleY(), hitbox.middleZ()); + } else { + pos.add(hitbox.middleX(), hitbox.middleY(), hitbox.middleZ()); + } + + pos.add(targetBlock); + SoundUtil.playSoundEvent3d(ref, interactionBlockState.getInteractionSoundEventIndex(), pos, commandBuffer); } - - newDoorState = checkResult; - } - - DoorInteraction.DoorState stateDoubleDoor = getOppositeDoorState(doorState); - BlockType interactionBlockState = activateDoor(world, blockType, targetBlock, doorState, newDoorState); - boolean doubleDoor = this.checkForDoubleDoor(world, targetBlock, blockType, rotation, newDoorState, stateDoubleDoor); - if (interactionBlockState != null) { - Vector3d pos = new Vector3d(); - int hitboxTypeIndex = BlockType.getAssetMap().getAsset(blockType.getItem().getId()).getHitboxTypeIndex(); - BlockBoundingBoxes blockBoundingBoxes = BlockBoundingBoxes.getAssetMap().getAsset(hitboxTypeIndex); - BlockBoundingBoxes.RotatedVariantBoxes rotatedBoxes = blockBoundingBoxes.get(rotation); - Box hitbox = rotatedBoxes.getBoundingBox(); - if (doubleDoor) { - Vector3d offset = new Vector3d(hitbox.middleX(), 0.0, 0.0); - Rotation rotationToCheck = RotationTuple.get(rotation).yaw(); - pos.add(MathUtil.rotateVectorYAxis(offset, rotationToCheck.getDegrees(), false)); - pos.add(hitbox.middleX(), hitbox.middleY(), hitbox.middleZ()); - } else { - pos.add(hitbox.middleX(), hitbox.middleY(), hitbox.middleZ()); - } - - pos.add(targetBlock); - SoundUtil.playSoundEvent3d(ref, interactionBlockState.getInteractionSoundEventIndex(), pos, commandBuffer); } } } @@ -186,14 +181,19 @@ public class DoorInteraction extends SimpleBlockInteraction { chunkAccessor.setBlockInteractionState(blockPosition, blockType, "DoorBlocked"); return null; } - } else if (!canOpenDoor(chunkAccessor, blockPosition, newOppositeDoorInteractionState) || this.horizontal) { - chunkAccessor.setBlockInteractionState(blockPosition, blockType, "DoorBlocked"); - return null; - } else if (doubleDoor != null && !canOpenDoor(chunkAccessor, doubleDoor.blockPosition, newDoorInteractionState)) { - chunkAccessor.setBlockInteractionState(blockPosition, blockType, "DoorBlocked"); - return null; + } else if (canOpenDoor(chunkAccessor, blockPosition, newOppositeDoorInteractionState) && !this.horizontal) { + if (doubleDoor != null && !canOpenDoor(chunkAccessor, doubleDoor.blockPosition, newDoorInteractionState)) { + chunkAccessor.setBlockInteractionState(blockPosition, blockType, "DoorBlocked"); + return null; + } else { + return newOppositeDoorState; + } } else { - return newOppositeDoorState; + if (newDoorState != DoorInteraction.DoorState.CLOSED) { + chunkAccessor.setBlockInteractionState(blockPosition, blockType, "DoorBlocked"); + } + + return null; } } diff --git a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/OpenCustomUIInteraction.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/OpenCustomUIInteraction.java index e4a62e11..c7f09bfd 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/OpenCustomUIInteraction.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/OpenCustomUIInteraction.java @@ -178,17 +178,18 @@ public class OpenCustomUIInteraction extends SimpleInstantInteraction { } else { Store store = ref.getStore(); World world = store.getExternalData().getWorld(); - WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z)); - if (chunk == null) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); + WorldChunk worldChunkComponent = world.getChunkIfInMemory(chunkIndex); + if (worldChunkComponent == null) { return null; } else { BlockPosition targetBaseBlock = world.getBaseBlock(targetBlock); - BlockComponentChunk blockComponentChunk = chunk.getBlockComponentChunk(); + BlockComponentChunk blockComponentChunk = worldChunkComponent.getBlockComponentChunk(); int index = ChunkUtil.indexBlockInColumn(targetBaseBlock.x, targetBaseBlock.y, targetBaseBlock.z); Ref blockEntityRef = blockComponentChunk.getEntityReference(index); - if (blockEntityRef == null) { + if (blockEntityRef == null || !blockEntityRef.isValid()) { Holder holder = creator.get(); - holder.putComponent(BlockModule.BlockStateInfo.getComponentType(), new BlockModule.BlockStateInfo(index, chunk.getReference())); + holder.putComponent(BlockModule.BlockStateInfo.getComponentType(), new BlockModule.BlockStateInfo(index, worldChunkComponent.getReference())); blockEntityRef = world.getChunkStore().getStore().addEntity(holder, AddReason.SPAWN); } @@ -201,17 +202,19 @@ public class OpenCustomUIInteraction extends SimpleInstantInteraction { @FunctionalInterface public interface BlockCustomPageSupplier { - CustomUIPage tryCreate(PlayerRef var1, T var2); + CustomUIPage tryCreate(@Nonnull PlayerRef var1, @Nonnull T var2); } @FunctionalInterface public interface BlockEntityCustomPageSupplier { - CustomUIPage tryCreate(PlayerRef var1, Ref var2); + CustomUIPage tryCreate(@Nonnull PlayerRef var1, @Nonnull Ref var2); } @FunctionalInterface public interface CustomPageSupplier { @Nullable - CustomUIPage tryCreate(Ref var1, ComponentAccessor var2, PlayerRef var3, InteractionContext var4); + CustomUIPage tryCreate( + @Nonnull Ref var1, @Nonnull ComponentAccessor var2, @Nonnull PlayerRef var3, @Nonnull InteractionContext var4 + ); } } diff --git a/src/com/hypixel/hytale/server/core/modules/projectile/ProjectileModule.java b/src/com/hypixel/hytale/server/core/modules/projectile/ProjectileModule.java index f6aab7cd..16732f4d 100644 --- a/src/com/hypixel/hytale/server/core/modules/projectile/ProjectileModule.java +++ b/src/com/hypixel/hytale/server/core/modules/projectile/ProjectileModule.java @@ -13,7 +13,6 @@ import com.hypixel.hytale.math.vector.Vector3f; import com.hypixel.hytale.protocol.Direction; import com.hypixel.hytale.protocol.InteractionType; import com.hypixel.hytale.protocol.SoundCategory; -import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.asset.type.model.config.Model; import com.hypixel.hytale.server.core.entity.EntityUtils; import com.hypixel.hytale.server.core.entity.InteractionChain; @@ -65,7 +64,6 @@ public class ProjectileModule extends JavaPlugin { .depends(CollisionModule.class) .depends(EntityModule.class) .build(); - public static final Message MESSAGE_GENERAL_UNKNOWN = Message.translation("server.general.unknown"); private static ProjectileModule instance; private ComponentType projectileComponentType; private ComponentType standardPhysicsProviderComponentType; diff --git a/src/com/hypixel/hytale/server/core/modules/singleplayer/commands/PlayCommandBase.java b/src/com/hypixel/hytale/server/core/modules/singleplayer/commands/PlayCommandBase.java index 03b91365..918e0b0d 100644 --- a/src/com/hypixel/hytale/server/core/modules/singleplayer/commands/PlayCommandBase.java +++ b/src/com/hypixel/hytale/server/core/modules/singleplayer/commands/PlayCommandBase.java @@ -28,31 +28,103 @@ public abstract class PlayCommandBase extends CommandBase { @Override protected void executeSync(@Nonnull CommandContext context) { if (!Constants.SINGLEPLAYER) { - context.sendMessage(Message.translation("server.commands.play.singleplayerOnly").param("commandAccess", this.commandAccess.toString())); + switch (this.commandAccess) { + case Private: + context.sendMessage(Message.translation("server.commands.play.singleplayerOnlyPrivate")); + break; + case LAN: + context.sendMessage(Message.translation("server.commands.play.singleplayerOnlyLan")); + break; + case Friend: + context.sendMessage(Message.translation("server.commands.play.singleplayerOnlyFriend")); + break; + case Open: + context.sendMessage(Message.translation("server.commands.play.singleplayerOnlyOpen")); + } } else { Access access = SingleplayerModule.get().getAccess(); if (!this.enabledArg.provided(context)) { if (access == this.commandAccess) { this.singleplayerModule.requestServerAccess(Access.Private); - context.sendMessage(Message.translation("server.commands.play.accessDisabled").param("commandAccess", this.commandAccess.toString())); + switch (this.commandAccess) { + case Private: + context.sendMessage(Message.translation("server.commands.play.accessDisabledPrivate")); + break; + case LAN: + context.sendMessage(Message.translation("server.commands.play.accessDisabledLan")); + break; + case Friend: + context.sendMessage(Message.translation("server.commands.play.accessDisabledFriend")); + break; + case Open: + context.sendMessage(Message.translation("server.commands.play.accessDisabledOpen")); + } } else { this.singleplayerModule.requestServerAccess(this.commandAccess); - context.sendMessage(Message.translation("server.commands.play.accessEnabled").param("commandAccess", this.commandAccess.toString())); + switch (this.commandAccess) { + case Private: + context.sendMessage(Message.translation("server.commands.play.accessEnabledPrivate")); + break; + case LAN: + context.sendMessage(Message.translation("server.commands.play.accessEnabledLan")); + break; + case Friend: + context.sendMessage(Message.translation("server.commands.play.accessEnabledFriend")); + break; + case Open: + context.sendMessage(Message.translation("server.commands.play.accessEnabledOpen")); + } } } else { boolean enabled = this.enabledArg.get(context); if (!enabled && access == this.commandAccess) { this.singleplayerModule.requestServerAccess(Access.Private); - context.sendMessage(Message.translation("server.commands.play.accessDisabled").param("commandAccess", this.commandAccess.toString())); + switch (this.commandAccess) { + case Private: + context.sendMessage(Message.translation("server.commands.play.accessDisabledPrivate")); + break; + case LAN: + context.sendMessage(Message.translation("server.commands.play.accessDisabledLan")); + break; + case Friend: + context.sendMessage(Message.translation("server.commands.play.accessDisabledFriend")); + break; + case Open: + context.sendMessage(Message.translation("server.commands.play.accessDisabledOpen")); + } } else if (enabled && access != this.commandAccess) { this.singleplayerModule.requestServerAccess(this.commandAccess); - context.sendMessage(Message.translation("server.commands.play.accessEnabled").param("commandAccess", this.commandAccess.toString())); + switch (this.commandAccess) { + case Private: + context.sendMessage(Message.translation("server.commands.play.accessEnabledPrivate")); + break; + case LAN: + context.sendMessage(Message.translation("server.commands.play.accessEnabledLan")); + break; + case Friend: + context.sendMessage(Message.translation("server.commands.play.accessEnabledFriend")); + break; + case Open: + context.sendMessage(Message.translation("server.commands.play.accessEnabledOpen")); + } } else { - context.sendMessage( - Message.translation("server.commands.play.accessAlreadyToggled") - .param("commandAccess", this.commandAccess.toString()) - .param("enabled", MessageFormat.enabled(enabled)) - ); + switch (this.commandAccess) { + case Private: + context.sendMessage( + Message.translation("server.commands.play.accessAlreadyToggledPrivate").param("enabled", MessageFormat.enabled(enabled)) + ); + break; + case LAN: + context.sendMessage(Message.translation("server.commands.play.accessAlreadyToggledLan").param("enabled", MessageFormat.enabled(enabled))); + break; + case Friend: + context.sendMessage( + Message.translation("server.commands.play.accessAlreadyToggledFriend").param("enabled", MessageFormat.enabled(enabled)) + ); + break; + case Open: + context.sendMessage(Message.translation("server.commands.play.accessAlreadyToggledOpen").param("enabled", MessageFormat.enabled(enabled))); + } } } } diff --git a/src/com/hypixel/hytale/server/core/permissions/commands/op/OpSelfCommand.java b/src/com/hypixel/hytale/server/core/permissions/commands/op/OpSelfCommand.java index bf0f9324..ed06c878 100644 --- a/src/com/hypixel/hytale/server/core/permissions/commands/op/OpSelfCommand.java +++ b/src/com/hypixel/hytale/server/core/permissions/commands/op/OpSelfCommand.java @@ -16,14 +16,11 @@ import java.util.UUID; import javax.annotation.Nonnull; public class OpSelfCommand extends AbstractPlayerCommand { - @Nonnull private static final Message MESSAGE_COMMANDS_OP_ADDED = Message.translation("server.commands.op.self.added"); - @Nonnull private static final Message MESSAGE_COMMANDS_OP_REMOVED = Message.translation("server.commands.op.self.removed"); - @Nonnull private static final Message MESSAGE_COMMANDS_NON_VANILLA_PERMISSIONS = Message.translation("server.commands.op.self.nonVanillaPermissions"); - @Nonnull private static final Message MESSAGE_COMMANDS_SINGLEPLAYER_OWNER_REQ = Message.translation("server.commands.op.self.singleplayerOwnerReq"); + private static final Message MESSAGE_COMMANDS_CURRENTLY_OP = Message.translation("server.commands.op.self.currentlyOpNote"); public OpSelfCommand() { super("self", "server.commands.op.self.desc"); @@ -42,24 +39,30 @@ public class OpSelfCommand extends AbstractPlayerCommand { playerRef.sendMessage(MESSAGE_COMMANDS_NON_VANILLA_PERMISSIONS); } else if (Constants.SINGLEPLAYER && !SingleplayerModule.isOwner(playerRef)) { playerRef.sendMessage(MESSAGE_COMMANDS_SINGLEPLAYER_OWNER_REQ); - } else if (!Constants.SINGLEPLAYER && !Constants.ALLOWS_SELF_OP_COMMAND) { - playerRef.sendMessage( - Message.translation("server.commands.op.self.multiplayerTip") - .param("uuidCommand", "uuid") - .param("permissionFile", "permissions.json") - .param("launchArg", "--allow-op") - ); } else { UUID uuid = playerRef.getUuid(); PermissionsModule perms = PermissionsModule.get(); String opGroup = "OP"; Set groups = perms.getGroupsForUser(uuid); - if (groups.contains("OP")) { - perms.removeUserFromGroup(uuid, "OP"); - context.sendMessage(MESSAGE_COMMANDS_OP_REMOVED); + boolean isOp = groups.contains("OP"); + if (!Constants.SINGLEPLAYER && !Constants.ALLOWS_SELF_OP_COMMAND) { + playerRef.sendMessage( + Message.translation("server.commands.op.self.multiplayerTip") + .param("uuidCommand", "uuid") + .param("permissionFile", "permissions.json") + .param("launchArg", "--allow-op") + ); + if (isOp) { + playerRef.sendMessage(MESSAGE_COMMANDS_CURRENTLY_OP); + } } else { - perms.addUserToGroup(uuid, "OP"); - context.sendMessage(MESSAGE_COMMANDS_OP_ADDED); + if (isOp) { + perms.removeUserFromGroup(uuid, "OP"); + context.sendMessage(MESSAGE_COMMANDS_OP_REMOVED); + } else { + perms.addUserToGroup(uuid, "OP"); + context.sendMessage(MESSAGE_COMMANDS_OP_ADDED); + } } } } diff --git a/src/com/hypixel/hytale/server/core/plugin/PluginManager.java b/src/com/hypixel/hytale/server/core/plugin/PluginManager.java index 2a78a065..5e14a5ac 100644 --- a/src/com/hypixel/hytale/server/core/plugin/PluginManager.java +++ b/src/com/hypixel/hytale/server/core/plugin/PluginManager.java @@ -102,14 +102,16 @@ public class PluginManager { this.corePlugins.add(new PendingLoadJavaPlugin(null, builder, this.corePluginClassLoader)); } - private boolean canLoadOnBoot(@Nonnull PluginManifest manifest) { - PluginIdentifier identifier = new PluginIdentifier(manifest); + private boolean canLoadOnBoot(@Nonnull PendingLoadPlugin plugin) { + PluginIdentifier identifier = plugin.getIdentifier(); + PluginManifest manifest = plugin.getManifest(); HytaleServerConfig.ModConfig modConfig = HytaleServer.get().getConfig().getModConfig().get(identifier); boolean enabled; if (modConfig != null && modConfig.getEnabled() != null) { enabled = modConfig.getEnabled(); } else { - enabled = !manifest.isDisabledByDefault(); + HytaleServerConfig serverConfig = HytaleServer.get().getConfig(); + enabled = !manifest.isDisabledByDefault() && (plugin.isInServerClassPath() || serverConfig.getDefaultModsEnabled()); } if (enabled) { @@ -135,7 +137,7 @@ public class PluginManager { for (int i = 0; i < this.corePlugins.size(); i++) { PendingLoadPlugin plugin = this.corePlugins.get(i); LOGGER.at(Level.INFO).log("- %s", plugin.getIdentifier()); - if (this.canLoadOnBoot(plugin.getManifest())) { + if (this.canLoadOnBoot(plugin)) { loadPendingPlugin(pending, plugin); } else { this.availablePlugins.put(plugin.getIdentifier(), plugin.getManifest()); @@ -357,7 +359,7 @@ public class PluginManager { assert plugin.getPath() != null; LOGGER.at(Level.INFO).log("- %s from path %s", plugin.getIdentifier(), path.relativize(plugin.getPath())); - if (this.canLoadOnBoot(plugin.getManifest())) { + if (this.canLoadOnBoot(plugin)) { loadPendingPlugin(pending, plugin); } else { bootRejectMap.put(plugin.getIdentifier(), plugin.getManifest()); @@ -442,7 +444,7 @@ public class PluginManager { } LOGGER.at(Level.INFO).log("- %s", plugin.getIdentifier()); - if (this.canLoadOnBoot(plugin.getManifest())) { + if (this.canLoadOnBoot(plugin)) { loadPendingPlugin(pending, plugin); } else { rejectedBootList.put(plugin.getIdentifier(), plugin.getManifest()); @@ -468,7 +470,7 @@ public class PluginManager { for (PluginManifest manifestx : manifests) { PendingLoadJavaPlugin pluginx = new PendingLoadJavaPlugin(path, manifestx, pluginClassLoader); LOGGER.at(Level.INFO).log("- %s", pluginx.getIdentifier()); - if (this.canLoadOnBoot(pluginx.getManifest())) { + if (this.canLoadOnBoot(pluginx)) { loadPendingPlugin(pending, pluginx); } else { rejectedBootList.put(pluginx.getIdentifier(), pluginx.getManifest()); diff --git a/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadPlugin.java b/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadPlugin.java index b043a09d..d942361a 100644 --- a/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadPlugin.java +++ b/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadPlugin.java @@ -114,7 +114,7 @@ public abstract class PendingLoadPlugin { HashSet classpathPlugins = new HashSet<>(); for (Entry entry : pending.entrySet()) { - if (entry.getValue().isInServerClassPath()) { + if (entry.getValue().isInServerClassPath() && "Hytale".equals(entry.getKey().getGroup())) { classpathPlugins.add(entry.getKey()); } } diff --git a/src/com/hypixel/hytale/server/core/prefab/selection/buffer/PrefabLoader.java b/src/com/hypixel/hytale/server/core/prefab/selection/buffer/PrefabLoader.java index 8f53b252..1697cf8b 100644 --- a/src/com/hypixel/hytale/server/core/prefab/selection/buffer/PrefabLoader.java +++ b/src/com/hypixel/hytale/server/core/prefab/selection/buffer/PrefabLoader.java @@ -5,7 +5,6 @@ import java.io.File; import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.NotDirectoryException; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; @@ -36,7 +35,7 @@ public class PrefabLoader { } else { Path prefabPath = rootFolder.resolve(prefabName.replace('.', File.separatorChar) + ".prefab.json"); if (!Files.exists(prefabPath)) { - throw new NoSuchFileException(prefabPath.toString()); + return; } pathConsumer.accept(prefabPath); @@ -46,22 +45,24 @@ public class PrefabLoader { public static void resolvePrefabFolder(@Nonnull Path rootFolder, @Nonnull String prefabName, @Nonnull final Consumer pathConsumer) throws IOException { String prefabDirectory = prefabName.substring(0, prefabName.length() - 2); Path directoryPath = rootFolder.resolve(prefabDirectory.replace('.', File.separatorChar)); - if (!Files.isDirectory(directoryPath)) { - throw new NotDirectoryException(directoryPath.toString()); - } else { - Files.walkFileTree(directoryPath, FileUtil.DEFAULT_WALK_TREE_OPTIONS_SET, Integer.MAX_VALUE, new SimpleFileVisitor() { - @Nonnull - public FileVisitResult visitFile(@Nonnull Path file, BasicFileAttributes attrs) { - String fileName = file.getFileName().toString(); - Matcher matcher = PrefabBufferUtil.FILE_SUFFIX_PATTERN.matcher(fileName); - if (matcher.find()) { - String fileNameNoExtension = matcher.replaceAll(""); - pathConsumer.accept(file.resolveSibling(fileNameNoExtension)); - } + if (Files.exists(directoryPath)) { + if (!Files.isDirectory(directoryPath)) { + throw new NotDirectoryException(directoryPath.toString()); + } else { + Files.walkFileTree(directoryPath, FileUtil.DEFAULT_WALK_TREE_OPTIONS_SET, Integer.MAX_VALUE, new SimpleFileVisitor() { + @Nonnull + public FileVisitResult visitFile(@Nonnull Path file, BasicFileAttributes attrs) { + String fileName = file.getFileName().toString(); + Matcher matcher = PrefabBufferUtil.FILE_SUFFIX_PATTERN.matcher(fileName); + if (matcher.find()) { + String fileNameNoExtension = matcher.replaceAll(""); + pathConsumer.accept(file.resolveSibling(fileNameNoExtension)); + } - return FileVisitResult.CONTINUE; - } - }); + return FileVisitResult.CONTINUE; + } + }); + } } } diff --git a/src/com/hypixel/hytale/server/core/prefab/selection/standard/BlockSelection.java b/src/com/hypixel/hytale/server/core/prefab/selection/standard/BlockSelection.java index b42b5e43..eb509c8c 100644 --- a/src/com/hypixel/hytale/server/core/prefab/selection/standard/BlockSelection.java +++ b/src/com/hypixel/hytale/server/core/prefab/selection/standard/BlockSelection.java @@ -634,6 +634,21 @@ public class BlockSelection implements NetworkSerializable, } } + public void clearAllSupportValues() { + this.blocksLock.writeLock().lock(); + + try { + this.blocks + .replaceAll( + (k, b) -> (BlockSelection.BlockHolder)(b.supportValue() == 0 + ? b + : new BlockSelection.BlockHolder(b.blockId(), b.rotation(), b.filler(), 0, b.holder())) + ); + } finally { + this.blocksLock.writeLock().unlock(); + } + } + public void addEntityFromWorld(@Nonnull Holder entityHolder) { TransformComponent transformComponent = entityHolder.getComponent(TransformComponent.getComponentType()); diff --git a/src/com/hypixel/hytale/server/core/universe/Universe.java b/src/com/hypixel/hytale/server/core/universe/Universe.java index baef1b1a..0cfad631 100644 --- a/src/com/hypixel/hytale/server/core/universe/Universe.java +++ b/src/com/hypixel/hytale/server/core/universe/Universe.java @@ -91,6 +91,7 @@ import com.hypixel.hytale.server.core.universe.world.worldgen.provider.DummyWorl import com.hypixel.hytale.server.core.universe.world.worldgen.provider.FlatWorldGenProvider; import com.hypixel.hytale.server.core.universe.world.worldgen.provider.IWorldGenProvider; import com.hypixel.hytale.server.core.universe.world.worldgen.provider.VoidWorldGenProvider; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.worldstore.WorldMarkersResource; import com.hypixel.hytale.server.core.universe.world.worldmap.provider.DisabledWorldMapProvider; import com.hypixel.hytale.server.core.universe.world.worldmap.provider.IWorldMapProvider; import com.hypixel.hytale.server.core.universe.world.worldmap.provider.chunk.WorldGenWorldMapProvider; @@ -119,6 +120,7 @@ import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiPredicate; import java.util.logging.Level; import javax.annotation.CheckReturnValue; @@ -152,7 +154,9 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv private PlayerStorage playerStorage; private WorldConfigProvider worldConfigProvider; private ResourceType indexedStorageCacheResourceType; + private ResourceType worldMarkersResourceType; private CompletableFuture universeReady; + private final AtomicBoolean isBackingUp = new AtomicBoolean(false); public static Universe get() { return instance; @@ -173,11 +177,23 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv int frequencyMinutes = Math.max(Options.getOptionSet().valueOf(Options.BACKUP_FREQUENCY_MINUTES), 1); this.getLogger().at(Level.INFO).log("Scheduled backup to run every %d minute(s)", frequencyMinutes); HytaleServer.SCHEDULED_EXECUTOR.scheduleWithFixedDelay(() -> { - try { - this.getLogger().at(Level.INFO).log("Backing up universe..."); - this.runBackup().thenAccept(aVoid -> this.getLogger().at(Level.INFO).log("Completed scheduled backup.")); - } catch (Exception var2x) { - this.getLogger().at(Level.SEVERE).withCause(var2x).log("Error backing up universe"); + if (!this.isBackingUp.compareAndSet(false, true)) { + this.getLogger().at(Level.WARNING).log("Skipping scheduled backup: previous backup still in progress"); + } else { + try { + this.getLogger().at(Level.INFO).log("Backing up universe..."); + this.runBackup().whenComplete((aVoid, throwable) -> { + this.isBackingUp.set(false); + if (throwable != null) { + this.getLogger().at(Level.SEVERE).withCause(throwable).log("Scheduled backup failed"); + } else { + this.getLogger().at(Level.INFO).log("Completed scheduled backup."); + } + }); + } catch (Exception var2x) { + this.isBackingUp.set(false); + this.getLogger().at(Level.SEVERE).withCause(var2x).log("Error backing up universe"); + } } }, frequencyMinutes, frequencyMinutes, TimeUnit.MINUTES); } @@ -225,6 +241,7 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv this.indexedStorageCacheResourceType = chunkStoreRegistry.registerResource( IndexedStorageChunkStorageProvider.IndexedStorageCache.class, IndexedStorageChunkStorageProvider.IndexedStorageCache::new ); + this.worldMarkersResourceType = chunkStoreRegistry.registerResource(WorldMarkersResource.class, "SharedUserMapMarkers", WorldMarkersResource.CODEC); chunkStoreRegistry.registerSystem(new IndexedStorageChunkStorageProvider.IndexedStorageCacheSetupSystem()); chunkStoreRegistry.registerSystem(new WorldPregenerateSystem()); entityStoreRegistry.registerSystem(new WorldConfigSaveSystem()); @@ -364,6 +381,10 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv return this.indexedStorageCacheResourceType; } + public ResourceType getWorldMarkersResourceType() { + return this.worldMarkersResourceType; + } + public boolean isWorldLoadable(@Nonnull String name) { Path savePath = this.path.resolve("worlds").resolve(name); return Files.isDirectory(savePath) && (Files.exists(savePath.resolve("config.bson")) || Files.exists(savePath.resolve("config.json"))); diff --git a/src/com/hypixel/hytale/server/core/universe/world/WorldMapTracker.java b/src/com/hypixel/hytale/server/core/universe/world/WorldMapTracker.java index e29c5776..8bc65441 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/WorldMapTracker.java +++ b/src/com/hypixel/hytale/server/core/universe/world/WorldMapTracker.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.math.shape.Box2D; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.protocol.GameMode; import com.hypixel.hytale.protocol.SoundCategory; import com.hypixel.hytale.protocol.packets.worldmap.ClearWorldMap; import com.hypixel.hytale.protocol.packets.worldmap.MapChunk; @@ -21,6 +22,7 @@ import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.protocol.packets.worldmap.UpdateWorldMap; import com.hypixel.hytale.protocol.packets.worldmap.UpdateWorldMapSettings; import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.asset.type.gameplay.WorldMapConfig; import com.hypixel.hytale.server.core.asset.type.soundevent.config.SoundEvent; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.event.events.ecs.DiscoverZoneEvent; @@ -72,6 +74,8 @@ public class WorldMapTracker implements Tickable { private String currentBiomeName; @Nullable private WorldMapTracker.ZoneDiscoveryInfo currentZone; + private boolean allowTeleportToCoordinates = true; + private boolean allowTeleportToMarkers = true; private boolean clientHasWorldMapVisible; @Nullable private TransformComponent transformComponent; @@ -483,8 +487,13 @@ public class WorldMapTracker implements Tickable { assert playerRefComponent != null; - worldMapSettingsPacket.allowTeleportToCoordinates = this.isAllowTeleportToCoordinates(); - worldMapSettingsPacket.allowTeleportToMarkers = this.isAllowTeleportToMarkers(); + worldMapSettingsPacket.allowTeleportToCoordinates = this.allowTeleportToCoordinates && playerComponent.getGameMode() != GameMode.Adventure; + worldMapSettingsPacket.allowTeleportToMarkers = this.allowTeleportToMarkers && playerComponent.getGameMode() != GameMode.Adventure; + WorldMapConfig worldMapConfig = world.getGameplayConfig().getWorldMapConfig(); + worldMapSettingsPacket.allowCreatingMapMarkers = worldMapConfig.getUserMapMarkerConfig().isAllowCreatingMarkers(); + worldMapSettingsPacket.allowShowOnMapToggle = worldMapConfig.canTogglePlayersInMap(); + worldMapSettingsPacket.allowCompassTrackingToggle = worldMapConfig.canTrackPlayersInCompass(); + worldMapSettingsPacket.allowRemovingOtherPlayersMarkers = worldMapConfig.getUserMapMarkerConfig().isAllowDeleteOtherPlayersSharedMarkers(); playerRefComponent.getPacketHandler().write(worldMapSettingsPacket); } }); @@ -547,11 +556,11 @@ public class WorldMapTracker implements Tickable { } public boolean isAllowTeleportToCoordinates() { - return this.player.hasPermission("hytale.world_map.teleport.coordinate"); + return this.player.hasPermission("hytale.world_map.teleport.coordinate") && this.player.getGameMode() != GameMode.Adventure; } public boolean isAllowTeleportToMarkers() { - return this.player.hasPermission("hytale.world_map.teleport.marker"); + return this.player.hasPermission("hytale.world_map.teleport.marker") && this.player.getGameMode() != GameMode.Adventure; } public void setPlayerMapFilter(Predicate playerMapFilter) { diff --git a/src/com/hypixel/hytale/server/core/universe/world/accessor/IChunkAccessorSync.java b/src/com/hypixel/hytale/server/core/universe/world/accessor/IChunkAccessorSync.java index 67df38d6..81729b3c 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/accessor/IChunkAccessorSync.java +++ b/src/com/hypixel/hytale/server/core/universe/world/accessor/IChunkAccessorSync.java @@ -32,11 +32,13 @@ public interface IChunkAccessorSync { WorldChunk getNonTickingChunk(long var1); default int getBlock(@Nonnull Vector3i pos) { - return this.getChunk(ChunkUtil.indexChunkFromBlock(pos.getX(), pos.getZ())).getBlock(pos.getX(), pos.getY(), pos.getZ()); + return this.getBlock(pos.getX(), pos.getY(), pos.getZ()); } default int getBlock(int x, int y, int z) { - return this.getChunk(ChunkUtil.indexChunkFromBlock(x, z)).getBlock(x, y, z); + long chunkIndex = ChunkUtil.indexChunkFromBlock(x, z); + WorldChunk worldChunk = this.getChunk(chunkIndex); + return worldChunk == null ? 0 : worldChunk.getBlock(x, y, z); } @Nullable @@ -46,9 +48,14 @@ public interface IChunkAccessorSync { @Nullable default BlockType getBlockType(int x, int y, int z) { - WorldChunk chunk = this.getChunk(ChunkUtil.indexChunkFromBlock(x, z)); - int blockId = chunk.getBlock(x, y, z); - return BlockType.getAssetMap().getAsset(blockId); + long chunkIndex = ChunkUtil.indexChunkFromBlock(x, z); + WorldChunk worldChunk = this.getChunk(chunkIndex); + if (worldChunk == null) { + return null; + } else { + int blockId = worldChunk.getBlock(x, y, z); + return BlockType.getAssetMap().getAsset(blockId); + } } default void setBlock(int x, int y, int z, String blockTypeKey) { diff --git a/src/com/hypixel/hytale/server/core/universe/world/chunk/WorldChunk.java b/src/com/hypixel/hytale/server/core/universe/world/chunk/WorldChunk.java index 42cbcac1..09dd6085 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/chunk/WorldChunk.java +++ b/src/com/hypixel/hytale/server/core/universe/world/chunk/WorldChunk.java @@ -406,11 +406,14 @@ public class WorldChunk implements BlockAccessor, Component { int settingsWithoutFiller = settings | 8 | 16; BlockType oldBlockType = blockTypeAssetMap.getAsset(oldBlock); String oldBlockKey = oldBlockType.getId(); - int baseX = worldX - FillerBlockUtil.unpackX(oldFiller); - int baseY = y - FillerBlockUtil.unpackY(oldFiller); - int baseZ = worldZ - FillerBlockUtil.unpackZ(oldFiller); + int fx = FillerBlockUtil.unpackX(oldFiller); + int fy = FillerBlockUtil.unpackY(oldFiller); + int fz = FillerBlockUtil.unpackZ(oldFiller); + int baseX = worldX - fx; + int baseY = y - fy; + int baseZ = worldZ - fz; FillerBlockUtil.forEachFillerBlock(hitboxAssetMap.getAsset(oldBlockType.getHitboxTypeIndex()).get(oldRotation), (x1, y1, z1) -> { - if (x1 != 0 || y1 != 0 || z1 != 0) { + if (x1 != fx || y1 != fy || z1 != fz) { int blockX = baseX + x1; int blockY = baseY + y1; int blockZ = baseZ + z1; diff --git a/src/com/hypixel/hytale/server/core/universe/world/chunk/environment/EnvironmentChunk.java b/src/com/hypixel/hytale/server/core/universe/world/chunk/environment/EnvironmentChunk.java index 655c8d36..d392d8b6 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/chunk/environment/EnvironmentChunk.java +++ b/src/com/hypixel/hytale/server/core/universe/world/chunk/environment/EnvironmentChunk.java @@ -14,10 +14,12 @@ import com.hypixel.hytale.sneakythrow.SneakyThrow; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.Int2IntFunction; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2LongMap; import it.unimi.dsi.fastutil.ints.Int2LongOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.Int2LongMap.Entry; import javax.annotation.Nonnull; @@ -193,4 +195,101 @@ public class EnvironmentChunk implements Component { private static int idx(int x, int z) { return ChunkUtil.indexColumn(x, z); } + + public static class BulkWriter { + private final EnvironmentChunk.BulkWriter.ColumnWriter[] columnWriters = new EnvironmentChunk.BulkWriter.ColumnWriter[1024]; + + public BulkWriter() { + for (int i = 0; i < this.columnWriters.length; i++) { + this.columnWriters[i] = new EnvironmentChunk.BulkWriter.ColumnWriter(); + } + } + + @Nonnull + public EnvironmentChunk.BulkWriter.ColumnWriter getColumnWriter(int x, int z) { + assert x >= 0 && x < 32; + + assert z >= 0 && z < 32; + + int idx = EnvironmentChunk.idx(x, z); + return this.columnWriters[idx]; + } + + public void write(@Nonnull EnvironmentChunk environmentChunk) { + environmentChunk.counts.clear(); + + for (int x = 0; x < 32; x++) { + for (int z = 0; z < 32; z++) { + int idx = EnvironmentChunk.idx(x, z); + + assert this.columnWriters[idx] != null; + + this.columnWriters[idx].write(environmentChunk.columns[idx]); + transferCounts(this.columnWriters[idx].columnCounts, environmentChunk.counts); + } + } + } + + private static void transferCounts(@Nonnull Int2LongMap from, @Nonnull Int2LongMap into) { + for (Entry entry : from.int2LongEntrySet()) { + long currentCount = into.getOrDefault(entry.getIntKey(), 0L); + into.put(entry.getIntKey(), currentCount + entry.getLongValue()); + } + } + + public static class ColumnWriter { + private final IntArrayList maxYsReversed = new IntArrayList(2); + private final IntArrayList valuesReversed = new IntArrayList(2); + private final Int2LongMap columnCounts = new Int2LongOpenHashMap(2); + + public void write(@Nonnull EnvironmentColumn environmentColumn) { + int[] maxYs = new int[this.maxYsReversed.size()]; + int[] values = new int[this.valuesReversed.size()]; + int index = 0; + + for (int reversedIndex = maxYs.length - 1; reversedIndex >= 0; index++) { + maxYs[index] = this.maxYsReversed.getInt(reversedIndex); + reversedIndex--; + } + + index = 0; + + for (int reversedIndex = values.length - 1; reversedIndex >= 0; index++) { + values[index] = this.valuesReversed.getInt(reversedIndex); + reversedIndex--; + } + + environmentColumn.resetTo(maxYs, values); + } + + public void count(int environmentId, int count) { + long currentCount = this.columnCounts.getOrDefault(environmentId, 0L); + count = (int)(count + currentCount); + this.columnCounts.put(environmentId, count); + } + + public void intake(@Nonnull Int2IntFunction dataSource) { + int maxYInclusive = 319; + int previousEnvironment = 0; + int runCounter = 0; + + for (int y = 319; y >= 0; y--) { + int environmentId = dataSource.applyAsInt(y); + if (y == 319) { + previousEnvironment = environmentId; + this.valuesReversed.add(environmentId); + runCounter++; + } else if (environmentId == previousEnvironment) { + runCounter++; + } else { + this.maxYsReversed.add(y); + this.valuesReversed.add(environmentId); + previousEnvironment = environmentId; + this.count(environmentId, runCounter); + runCounter = 1; + } + } + } + } + } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/chunk/environment/EnvironmentColumn.java b/src/com/hypixel/hytale/server/core/universe/world/chunk/environment/EnvironmentColumn.java index e159401a..8a9f8dd4 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/chunk/environment/EnvironmentColumn.java +++ b/src/com/hypixel/hytale/server/core/universe/world/chunk/environment/EnvironmentColumn.java @@ -11,9 +11,9 @@ public class EnvironmentColumn { public static final int MIN = Integer.MIN_VALUE; public static final int MAX = Integer.MAX_VALUE; @Nonnull - private final IntArrayList maxYs; + private IntArrayList maxYs; @Nonnull - private final IntArrayList values; + private IntArrayList values; public EnvironmentColumn(@Nonnull int[] maxYs, @Nonnull int[] values) { this(new IntArrayList(maxYs), new IntArrayList(values)); @@ -166,6 +166,13 @@ public class EnvironmentColumn { } } + public void resetTo(@Nonnull int[] maxYs, @Nonnull int[] values) { + assert maxYs.length == values.length - 1; + + this.maxYs = new IntArrayList(maxYs); + this.values = new IntArrayList(values); + } + public void serialize(@Nonnull ByteBuf buf, @Nonnull IntObjectConsumer valueSerializer) { int n = this.maxYs.size(); buf.writeInt(n); diff --git a/src/com/hypixel/hytale/server/core/universe/world/commands/WorldSettingsCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/WorldSettingsCommand.java index d56c4aab..aeefb209 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/commands/WorldSettingsCommand.java +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/WorldSettingsCommand.java @@ -284,10 +284,9 @@ public class WorldSettingsCommand extends AbstractCommandCollection { WorldSettingsBox2DCommand.this.setter.accept(world, newValue); world.getWorldConfig().markChanged(); context.sendMessage( - Message.translation("server.commands.world.settings.displaySet") + Message.translation("server.commands.world.settings.displaySetDefault") .param("display", WorldSettingsBox2DCommand.this.display) .param("worldName", world.getName()) - .param("isDefault", " default value ") .param("newValue", Objects.toString(newValue)) .param("oldValue", Objects.toString(currentValue)) ); @@ -320,7 +319,6 @@ public class WorldSettingsCommand extends AbstractCommandCollection { Message.translation("server.commands.world.settings.displaySet") .param("display", WorldSettingsBox2DCommand.this.display) .param("worldName", world.getName()) - .param("isDefault", "") .param("newValue", Objects.toString(newValue)) .param("oldValue", Objects.toString(currentValue)) ); @@ -386,10 +384,9 @@ public class WorldSettingsCommand extends AbstractCommandCollection { WorldSettingsSubCommand.this.setter.accept(world, newValue); world.getWorldConfig().markChanged(); context.sendMessage( - Message.translation("server.commands.world.settings.displaySet") + Message.translation("server.commands.world.settings.displaySetDefault") .param("display", WorldSettingsSubCommand.this.display) .param("worldName", world.getName()) - .param("isDefault", " default value ") .param("newValue", newValue.toString()) .param("oldValue", currentValue.toString()) ); @@ -416,7 +413,6 @@ public class WorldSettingsCommand extends AbstractCommandCollection { Message.translation("server.commands.world.settings.displaySet") .param("display", WorldSettingsSubCommand.this.display) .param("worldName", world.getName()) - .param("isDefault", "") .param("newValue", newValue.toString()) .param("oldValue", currentValue.toString()) ); diff --git a/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkFindCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkFindCommand.java index f140698b..6942ef2b 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkFindCommand.java +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkFindCommand.java @@ -44,7 +44,7 @@ public class BlockBulkFindCommand extends AbstractWorldCommand { private final RequiredArg timeoutArg = this.withRequiredArg("timeout", "", ArgTypes.INTEGER); public BlockBulkFindCommand() { - super("find", "server.commands.find.desc", true); + super("find", "server.commands.block.find.desc", true); } @Override diff --git a/src/com/hypixel/hytale/server/core/universe/world/map/WorldMap.java b/src/com/hypixel/hytale/server/core/universe/world/map/WorldMap.java index b09522fc..9f253610 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/map/WorldMap.java +++ b/src/com/hypixel/hytale/server/core/universe/world/map/WorldMap.java @@ -46,7 +46,7 @@ public class WorldMap implements NetworkSerializable { } public void addPointOfInterest(String id, String name, String markerType, @Nonnull Transform transform) { - MapMarker old = this.pointsOfInterest.putIfAbsent(id, new MapMarker(id, name, markerType, PositionUtil.toTransformPacket(transform), null)); + MapMarker old = this.pointsOfInterest.putIfAbsent(id, new MapMarker(id, null, name, markerType, PositionUtil.toTransformPacket(transform), null, null)); if (old != null) { throw new IllegalArgumentException("Id " + id + " already exists!"); } diff --git a/src/com/hypixel/hytale/server/core/universe/world/meta/state/BlockMapMarker.java b/src/com/hypixel/hytale/server/core/universe/world/meta/state/BlockMapMarker.java index a7b023d8..de72544c 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/meta/state/BlockMapMarker.java +++ b/src/com/hypixel/hytale/server/core/universe/world/meta/state/BlockMapMarker.java @@ -15,18 +15,18 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefSystem; import com.hypixel.hytale.math.util.ChunkUtil; +import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.math.vector.Vector3i; -import com.hypixel.hytale.protocol.Direction; -import com.hypixel.hytale.protocol.Position; -import com.hypixel.hytale.protocol.Transform; import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.modules.block.BlockModule; 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.WorldChunk; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -73,17 +73,16 @@ public class BlockMapMarker implements Component { public static final BlockMapMarker.MarkerProvider INSTANCE = new BlockMapMarker.MarkerProvider(); @Override - public void update(World world, MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { BlockMapMarkersResource resource = world.getChunkStore().getStore().getResource(BlockMapMarkersResource.getResourceType()); Long2ObjectMap markers = resource.getMarkers(); for (BlockMapMarkersResource.BlockMapMarkerData markerData : markers.values()) { Vector3i position = markerData.getPosition(); - Transform transform = new Transform(); - transform.position = new Position(position.getX() + 0.5F, position.getY(), position.getZ() + 0.5F); - transform.orientation = new Direction(0.0F, 0.0F, 0.0F); - MapMarker marker = new MapMarker(markerData.getMarkerId(), markerData.getName(), markerData.getIcon(), transform, null); - tracker.trySendMarker(chunkViewRadius, playerChunkX, playerChunkZ, marker); + MapMarker marker = new MapMarkerBuilder(markerData.getMarkerId(), markerData.getIcon(), new Transform(position)) + .withCustomName(markerData.getName()) + .build(); + collector.add(marker); } } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/meta/state/ItemContainerState.java b/src/com/hypixel/hytale/server/core/universe/world/meta/state/ItemContainerState.java index a5a16372..1f2de237 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/meta/state/ItemContainerState.java +++ b/src/com/hypixel/hytale/server/core/universe/world/meta/state/ItemContainerState.java @@ -25,7 +25,6 @@ import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.core.universe.world.meta.BlockState; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.List; import java.util.Map; @@ -35,12 +34,11 @@ import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ItemContainerState extends BlockState implements ItemContainerBlockState, DestroyableBlockState, MarkerBlockState { +public class ItemContainerState extends BlockState implements ItemContainerBlockState, DestroyableBlockState { public static final Codec CODEC = BuilderCodec.builder(ItemContainerState.class, ItemContainerState::new, BlockState.BASE_CODEC) .addField(new KeyedCodec<>("Custom", Codec.BOOLEAN), (state, o) -> state.custom = o, state -> state.custom) .addField(new KeyedCodec<>("AllowViewing", Codec.BOOLEAN), (state, o) -> state.allowViewing = o, state -> state.allowViewing) .addField(new KeyedCodec<>("Droplist", Codec.STRING), (state, o) -> state.droplist = o, state -> state.droplist) - .addField(new KeyedCodec<>("Marker", WorldMapManager.MarkerReference.CODEC), (state, o) -> state.marker = o, state -> state.marker) .addField(new KeyedCodec<>("ItemContainer", SimpleItemContainer.CODEC), (state, o) -> state.itemContainer = o, state -> state.itemContainer) .build(); private final Map windows = new ConcurrentHashMap<>(); @@ -49,7 +47,6 @@ public class ItemContainerState extends BlockState implements ItemContainerBlock @Nullable protected String droplist; protected SimpleItemContainer itemContainer; - protected WorldMapManager.MarkerReference marker; @Override public boolean initialize(@Nonnull BlockType blockType) { @@ -109,10 +106,6 @@ public class ItemContainerState extends BlockState implements ItemContainerBlock if (itemEntityHolders.length > 0) { world.execute(() -> store.addEntities(itemEntityHolders, AddReason.SPAWN)); } - - if (this.marker != null) { - this.marker.remove(); - } } public void setCustom(boolean custom) { @@ -144,12 +137,6 @@ public class ItemContainerState extends BlockState implements ItemContainerBlock this.markNeedsSave(); } - @Override - public void setMarker(WorldMapManager.MarkerReference marker) { - this.marker = marker; - this.markNeedsSave(); - } - @Nonnull public Map getWindows() { return this.windows; diff --git a/src/com/hypixel/hytale/server/core/universe/world/meta/state/MarkerBlockState.java b/src/com/hypixel/hytale/server/core/universe/world/meta/state/MarkerBlockState.java deleted file mode 100644 index b376bc2a..00000000 --- a/src/com/hypixel/hytale/server/core/universe/world/meta/state/MarkerBlockState.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.hypixel.hytale.server.core.universe.world.meta.state; - -import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; - -public interface MarkerBlockState { - void setMarker(WorldMapManager.MarkerReference var1); -} diff --git a/src/com/hypixel/hytale/server/core/universe/world/storage/component/ChunkSavingSystems.java b/src/com/hypixel/hytale/server/core/universe/world/storage/component/ChunkSavingSystems.java index 246345c6..e64460e6 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/storage/component/ChunkSavingSystems.java +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/component/ChunkSavingSystems.java @@ -235,22 +235,22 @@ public class ChunkSavingSystems { chunk.setSaving(true); Holder holder = store.copySerializableEntity(reference); data.toSaveTotal.getAndIncrement(); - data.chunkSavingFutures - .add( - CompletableFuture.>supplyAsync(() -> saver.saveHolder(chunk.getX(), chunk.getZ(), holder)) - .thenCompose(Function.identity()) - .whenCompleteAsync((aVoid, throwable) -> { - if (throwable != null) { - ChunkSavingSystems.LOGGER.at(Level.SEVERE).withCause(throwable).log("Failed to save chunk (%d, %d):", chunk.getX(), chunk.getZ()); - } else { - chunk.setFlag(ChunkFlag.ON_DISK, true); - ChunkSavingSystems.LOGGER.at(Level.FINEST).log("Finished saving chunk (%d, %d)", chunk.getX(), chunk.getZ()); - } + CompletableFuture savingFuture = CompletableFuture.>supplyAsync( + () -> saver.saveHolder(chunk.getX(), chunk.getZ(), holder) + ) + .thenCompose(Function.identity()); + data.chunkSavingFutures.add(savingFuture); + savingFuture.whenCompleteAsync((aVoid, throwable) -> { + if (throwable != null) { + ChunkSavingSystems.LOGGER.at(Level.SEVERE).withCause(throwable).log("Failed to save chunk (%d, %d):", chunk.getX(), chunk.getZ()); + } else { + chunk.setFlag(ChunkFlag.ON_DISK, true); + ChunkSavingSystems.LOGGER.at(Level.FINEST).log("Finished saving chunk (%d, %d)", chunk.getX(), chunk.getZ()); + } - chunk.consumeNeedsSaving(); - chunk.setSaving(false); - }, world) - ); + chunk.consumeNeedsSaving(); + chunk.setSaving(false); + }, world); } } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldgen/GeneratedBlockChunk.java b/src/com/hypixel/hytale/server/core/universe/world/worldgen/GeneratedBlockChunk.java index 3f610932..9d30e318 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/worldgen/GeneratedBlockChunk.java +++ b/src/com/hypixel/hytale/server/core/universe/world/worldgen/GeneratedBlockChunk.java @@ -94,6 +94,11 @@ public class GeneratedBlockChunk { return height; } + @Nonnull + public EnvironmentChunk getEnvironmentChunk() { + return this.environments; + } + @Nullable public GeneratedChunkSection getSection(int y) { int index = ChunkUtil.indexSection(y); diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/WorldMapManager.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/WorldMapManager.java index 562c3a5f..80c8f533 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/worldmap/WorldMapManager.java +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/WorldMapManager.java @@ -5,34 +5,43 @@ import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.lookup.CodecMapCodec; -import com.hypixel.hytale.common.util.ArrayUtil; import com.hypixel.hytale.common.util.CompletableFutureUtil; -import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.util.MathUtil; +import com.hypixel.hytale.protocol.Color; +import com.hypixel.hytale.protocol.packets.player.RemoveMapMarker; +import com.hypixel.hytale.protocol.packets.worldmap.CreateUserMarker; import com.hypixel.hytale.protocol.packets.worldmap.MapImage; import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; -import com.hypixel.hytale.server.core.entity.UUIDComponent; +import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerConfigData; import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerWorldData; +import com.hypixel.hytale.server.core.modules.entity.component.DisplayNameComponent; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.DeathMarkerProvider; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.OtherPlayersMarkerProvider; import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.POIMarkerProvider; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.PerWorldDataMarkerProvider; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.PlayerIconMarkerProvider; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.PersonalMarkersProvider; import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.RespawnMarkerProvider; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.SharedMarkersProvider; import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.SpawnMarkerProvider; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarkersStore; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMarkerValidator; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.worldstore.WorldMarkersResource; import com.hypixel.hytale.server.core.util.thread.TickingThread; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; @@ -71,10 +80,11 @@ public class WorldMapManager extends TickingThread { this.logger = HytaleLogger.get("World|" + world.getName() + "|M"); this.world = world; this.addMarkerProvider("spawn", SpawnMarkerProvider.INSTANCE); - this.addMarkerProvider("playerIcons", PlayerIconMarkerProvider.INSTANCE); + this.addMarkerProvider("playerIcons", OtherPlayersMarkerProvider.INSTANCE); this.addMarkerProvider("death", DeathMarkerProvider.INSTANCE); this.addMarkerProvider("respawn", RespawnMarkerProvider.INSTANCE); - this.addMarkerProvider("playerMarkers", PerWorldDataMarkerProvider.INSTANCE); + this.addMarkerProvider("personal", PersonalMarkersProvider.INSTANCE); + this.addMarkerProvider("shared", SharedMarkersProvider.INSTANCE); this.addMarkerProvider("poi", POIMarkerProvider.INSTANCE); } @@ -275,6 +285,74 @@ public class WorldMapManager extends TickingThread { } } + public void handleUserCreateMarker(PlayerRef playerRef, CreateUserMarker packet) { + Ref ref = playerRef.getReference(); + if (ref != null) { + UserMarkerValidator.PlaceResult validation = UserMarkerValidator.validatePlacing(ref, packet); + if (validation instanceof UserMarkerValidator.CanSpawn canSpawn) { + Store var13 = ref.getStore(); + UserMapMarkersStore markersStore = canSpawn.markersStore(); + DisplayNameComponent displayNameComponent = var13.getComponent(ref, DisplayNameComponent.getComponentType()); + String createdByName = displayNameComponent == null ? playerRef.getUsername() : displayNameComponent.getDisplayName().getRawText(); + UserMapMarker userMapMarker = new UserMapMarker(); + userMapMarker.setId("user_" + (packet.shared ? "shared" : "personal") + "_" + UUID.randomUUID()); + userMapMarker.setPosition(packet.x, packet.z); + userMapMarker.setName(packet.name); + userMapMarker.setIcon(packet.markerImage == null ? "User1.png" : packet.markerImage); + userMapMarker.setColorTint(packet.tintColor == null ? new Color((byte)0, (byte)0, (byte)0) : packet.tintColor); + userMapMarker.withCreatedByName(createdByName); + userMapMarker.withCreatedByUuid(playerRef.getUuid()); + markersStore.addUserMapMarker(userMapMarker); + } else { + if (validation instanceof UserMarkerValidator.Fail(Message displayNameComponent)) { + playerRef.sendMessage(displayNameComponent.color("#ffc800")); + } + } + } + } + + public void handleUserRemoveMarker(PlayerRef playerRef, RemoveMapMarker packet) { + Ref ref = playerRef.getReference(); + if (ref != null) { + Store store = ref.getStore(); + World world = store.getExternalData().getWorld(); + Player player = store.getComponent(ref, Player.getComponentType()); + PlayerWorldData perWorldData = player.getPlayerConfigData().getPerWorldData(world.getName()); + boolean removedDeathMarker = perWorldData.removeLastDeath(packet.markerId); + if (!removedDeathMarker) { + WorldMapManager.MarkerAndItsStore userMarkerAndStore = this.findUserMapMarker(packet.markerId, player, world); + if (userMarkerAndStore == null) { + playerRef.sendMessage(Message.translation("server.worldmap.markers.edit.notFound").color("#ffc800")); + HytaleLogger.getLogger() + .at(Level.WARNING) + .log("Couldn't find marker to remove '" + packet.markerId + "' from " + playerRef.getUsername() + " " + playerRef.getUuid()); + } else { + UserMarkerValidator.RemoveResult validation = UserMarkerValidator.validateRemove(ref, userMarkerAndStore.marker); + if (!(validation instanceof UserMarkerValidator.CanRemove)) { + if (validation instanceof UserMarkerValidator.Fail(Message var13)) { + playerRef.sendMessage(var13.color("#ffc800")); + } + } else { + userMarkerAndStore.store.removeUserMapMarker(userMarkerAndStore.marker.getId()); + } + } + } + } + } + + @Nullable + private WorldMapManager.MarkerAndItsStore findUserMapMarker(String markerId, Player player, World world) { + PlayerWorldData perWorldData = player.getPlayerConfigData().getPerWorldData(world.getName()); + UserMapMarker personalMarker = perWorldData.getUserMapMarker(markerId); + if (personalMarker != null) { + return new WorldMapManager.MarkerAndItsStore(personalMarker, perWorldData); + } else { + WorldMarkersResource sharedMarkers = world.getChunkStore().getStore().getResource(WorldMarkersResource.getResourceType()); + UserMapMarker sharedMarker = sharedMarkers.getUserMapMarker(markerId); + return sharedMarker != null ? new WorldMapManager.MarkerAndItsStore(sharedMarker, sharedMarkers) : null; + } + } + public void clearImages() { this.images.clear(); this.generating.clear(); @@ -287,23 +365,10 @@ public class WorldMapManager extends TickingThread { }); } - @Nonnull - public static WorldMapManager.PlayerMarkerReference createPlayerMarker( - @Nonnull Ref playerRef, @Nonnull MapMarker marker, @Nonnull ComponentAccessor componentAccessor - ) { - World world = componentAccessor.getExternalData().getWorld(); - Player playerComponent = componentAccessor.getComponent(playerRef, Player.getComponentType()); - - assert playerComponent != null; - - UUIDComponent uuidComponent = componentAccessor.getComponent(playerRef, UUIDComponent.getComponentType()); - - assert uuidComponent != null; - - PlayerWorldData perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(world.getName()); - MapMarker[] worldMapMarkers = perWorldData.getWorldMapMarkers(); - perWorldData.setWorldMapMarkers(ArrayUtil.append(worldMapMarkers, marker)); - return new WorldMapManager.PlayerMarkerReference(uuidComponent.getUuid(), world.getName(), marker.id); + public static void sendSettingsToAllWorlds() { + for (World world : Universe.get().getWorlds().values()) { + world.execute(() -> world.getWorldMapManager().sendSettings()); + } } static { @@ -319,8 +384,11 @@ public class WorldMapManager extends TickingThread { } } + private record MarkerAndItsStore(UserMapMarker marker, UserMapMarkersStore store) { + } + public interface MarkerProvider { - void update(World var1, MapMarkerTracker var2, int var3, int var4, int var5); + void update(@Nonnull World var1, @Nonnull Player var2, @Nonnull MarkersCollector var3); } public interface MarkerReference { @@ -409,31 +477,11 @@ public class WorldMapManager extends TickingThread { } @Nullable - private static MapMarker removeMarkerFromData(@Nonnull PlayerConfigData data, @Nonnull String worldName, @Nonnull String markerId) { + private static void removeMarkerFromData(@Nonnull PlayerConfigData data, @Nonnull String worldName, @Nonnull String markerId) { PlayerWorldData perWorldData = data.getPerWorldData(worldName); - MapMarker[] worldMapMarkers = perWorldData.getWorldMapMarkers(); - if (worldMapMarkers == null) { - return null; - } else { - int index = -1; - - for (int i = 0; i < worldMapMarkers.length; i++) { - if (worldMapMarkers[i].id.equals(markerId)) { - index = i; - break; - } - } - - if (index == -1) { - return null; - } else { - MapMarker[] newWorldMapMarkers = new MapMarker[worldMapMarkers.length - 1]; - System.arraycopy(worldMapMarkers, 0, newWorldMapMarkers, 0, index); - System.arraycopy(worldMapMarkers, index + 1, newWorldMapMarkers, index, newWorldMapMarkers.length - index); - perWorldData.setWorldMapMarkers(newWorldMapMarkers); - return worldMapMarkers[index]; - } - } + ArrayList playerMarkers = new ArrayList<>(perWorldData.getUserMapMarkers()); + playerMarkers.removeIf(marker -> markerId.equals(marker.getId())); + perWorldData.setUserMapMarkers(playerMarkers); } } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MapMarkerBuilder.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MapMarkerBuilder.java new file mode 100644 index 00000000..78582f6f --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MapMarkerBuilder.java @@ -0,0 +1,66 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers; + +import com.hypixel.hytale.math.vector.Transform; +import com.hypixel.hytale.protocol.packets.worldmap.ContextMenuItem; +import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.protocol.packets.worldmap.MapMarkerComponent; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.util.PositionUtil; +import java.util.ArrayList; +import java.util.List; + +public class MapMarkerBuilder { + private final String id; + private final String image; + private final Transform transform; + private Message name; + private String customName; + private List contextMenuItems; + private List mapMarkerComponents; + + public MapMarkerBuilder(String id, String image, Transform transform) { + this.id = id; + this.image = image; + this.transform = transform; + } + + public MapMarkerBuilder withName(Message name) { + this.name = name; + return this; + } + + public MapMarkerBuilder withCustomName(String customName) { + this.customName = customName; + return this; + } + + public MapMarkerBuilder withContextMenuItem(ContextMenuItem contextMenuItem) { + if (this.contextMenuItems == null) { + this.contextMenuItems = new ArrayList<>(); + } + + this.contextMenuItems.add(contextMenuItem); + return this; + } + + public MapMarkerBuilder withComponent(MapMarkerComponent component) { + if (this.mapMarkerComponents == null) { + this.mapMarkerComponents = new ArrayList<>(); + } + + this.mapMarkerComponents.add(component); + return this; + } + + public MapMarker build() { + return new MapMarker( + this.id, + this.name == null ? null : this.name.getFormattedMessage(), + this.customName, + this.image, + PositionUtil.toTransformPacket(this.transform), + this.contextMenuItems == null ? null : this.contextMenuItems.toArray(ContextMenuItem[]::new), + this.mapMarkerComponents == null ? null : this.mapMarkerComponents.toArray(MapMarkerComponent[]::new) + ); + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MapMarkerTracker.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MapMarkerTracker.java index f6e8e241..01cca55c 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MapMarkerTracker.java +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MapMarkerTracker.java @@ -1,8 +1,5 @@ package com.hypixel.hytale.server.core.universe.world.worldmap.markers; -import com.hypixel.hytale.function.function.TriFunction; -import com.hypixel.hytale.math.util.MathUtil; -import com.hypixel.hytale.math.vector.Vector2d; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.protocol.Position; import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; @@ -14,11 +11,13 @@ import com.hypixel.hytale.server.core.universe.world.WorldMapTracker; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class MapMarkerTracker { private final WorldMapTracker worldMapTracker; @@ -70,9 +69,10 @@ public class MapMarkerTracker { Map markerProviders = worldMapManager.getMarkerProviders(); this.tempToAdd.clear(); this.tempTestedMarkers.clear(); + MarkersCollectorImpl markersCollector = new MarkersCollectorImpl(this, chunkViewRadius, playerChunkX, playerChunkZ); for (WorldMapManager.MarkerProvider provider : markerProviders.values()) { - provider.update(world, this, chunkViewRadius, playerChunkX, playerChunkZ); + provider.update(world, this.player, markersCollector); } if (this.isSendingSmallMovements()) { @@ -97,76 +97,31 @@ public class MapMarkerTracker { } } - public void trySendMarker(int chunkViewRadius, int playerChunkX, int playerChunkZ, @Nonnull MapMarker marker) { - this.trySendMarker( - chunkViewRadius, - playerChunkX, - playerChunkZ, - marker.transform.position.x, - marker.transform.position.z, - marker.transform.orientation.yaw, - marker.id, - marker.name, - marker, - (id, name, m) -> m - ); + public void sendMapMarker(MapMarker marker) { + this.tempTestedMarkers.add(marker.id); + MapMarker oldMarker = this.sentToClientById.get(marker.id); + if (this.doesMarkerNeedNetworkUpdate(oldMarker, marker)) { + this.sentToClientById.put(marker.id, marker); + this.tempToAdd.add(marker); + } } - public void trySendMarker( - int chunkViewRadius, - int playerChunkX, - int playerChunkZ, - @Nonnull Vector3d markerPos, - float markerYaw, - @Nonnull String markerId, - @Nonnull String markerDisplayName, - @Nonnull T param, - @Nonnull TriFunction markerSupplier - ) { - this.trySendMarker(chunkViewRadius, playerChunkX, playerChunkZ, markerPos.x, markerPos.z, markerYaw, markerId, markerDisplayName, param, markerSupplier); - } - - private void trySendMarker( - int chunkViewRadius, - int playerChunkX, - int playerChunkZ, - double markerX, - double markerZ, - float markerYaw, - @Nonnull String markerId, - @Nonnull String markerName, - @Nonnull T param, - @Nonnull TriFunction markerSupplier - ) { - boolean shouldBeVisible = chunkViewRadius == -1 - || WorldMapTracker.shouldBeVisible(chunkViewRadius, MathUtil.floor(markerX) >> 5, MathUtil.floor(markerZ) >> 5, playerChunkX, playerChunkZ); - if (shouldBeVisible) { - this.tempTestedMarkers.add(markerId); - boolean needsUpdate = false; - MapMarker oldMarker = this.sentToClientById.get(markerId); - if (oldMarker != null) { - if (!markerName.equals(oldMarker.name)) { - needsUpdate = true; - } - - if (!needsUpdate) { - double distance = Math.abs(oldMarker.transform.orientation.yaw - markerYaw); - needsUpdate = distance > 0.05 || this.isSendingSmallMovements() && distance > 0.001; - } - - if (!needsUpdate) { - Position oldPosition = oldMarker.transform.position; - double distance = Vector2d.distance(oldPosition.x, oldPosition.z, markerX, markerZ); - needsUpdate = distance > 5.0 || this.isSendingSmallMovements() && distance > 0.1; - } + private boolean doesMarkerNeedNetworkUpdate(@Nullable MapMarker oldMarker, MapMarker newMarker) { + if (oldMarker == null) { + return true; + } else if (!Objects.equals(oldMarker.name, newMarker.name)) { + return true; + } else if (!Objects.equals(oldMarker.customName, newMarker.customName)) { + return true; + } else { + double yawDistance = Math.abs(oldMarker.transform.orientation.yaw - newMarker.transform.orientation.yaw); + if (!(yawDistance > 0.05) && (!this.isSendingSmallMovements() || !(yawDistance > 0.001))) { + Position oldPosition = oldMarker.transform.position; + Position newPosition = newMarker.transform.position; + double distanceSq = Vector3d.distanceSquared(oldPosition.x, oldPosition.y, oldPosition.z, newPosition.x, newPosition.y, newPosition.z); + return distanceSq > 25.0 || this.isSendingSmallMovements() && distanceSq > 0.01; } else { - needsUpdate = true; - } - - if (needsUpdate) { - MapMarker marker = markerSupplier.apply(markerId, markerName, param); - this.sentToClientById.put(markerId, marker); - this.tempToAdd.add(marker); + return true; } } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MarkersCollector.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MarkersCollector.java new file mode 100644 index 00000000..b7e00006 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MarkersCollector.java @@ -0,0 +1,28 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers; + +import com.hypixel.hytale.math.vector.Transform; +import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.universe.PlayerRef; +import java.util.function.Predicate; +import javax.annotation.Nullable; + +public interface MarkersCollector { + void add(MapMarker var1); + + void addIgnoreViewDistance(MapMarker var1); + + @Deprecated + @Nullable + Predicate getPlayerMapFilter(); + + default boolean isInViewDistance(Transform transform) { + return this.isInViewDistance(transform.getPosition()); + } + + default boolean isInViewDistance(Vector3d position) { + return this.isInViewDistance(position.x, position.z); + } + + boolean isInViewDistance(double var1, double var3); +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MarkersCollectorImpl.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MarkersCollectorImpl.java new file mode 100644 index 00000000..b4a7cd50 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/MarkersCollectorImpl.java @@ -0,0 +1,59 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers; + +import com.hypixel.hytale.math.util.MathUtil; +import com.hypixel.hytale.protocol.Position; +import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.universe.PlayerRef; +import com.hypixel.hytale.server.core.universe.world.WorldMapTracker; +import java.util.function.Predicate; +import javax.annotation.Nullable; + +class MarkersCollectorImpl implements MarkersCollector { + private final MapMarkerTracker tracker; + private final int chunkViewRadius; + private final int playerChunkX; + private final int playerChunkZ; + + public MarkersCollectorImpl(MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + this.tracker = tracker; + this.chunkViewRadius = chunkViewRadius; + this.playerChunkX = playerChunkX; + this.playerChunkZ = playerChunkZ; + } + + public int getChunkViewRadius() { + return this.chunkViewRadius; + } + + public int getPlayerChunkX() { + return this.playerChunkX; + } + + public int getPlayerChunkZ() { + return this.playerChunkZ; + } + + @Override + public boolean isInViewDistance(double x, double z) { + return WorldMapTracker.shouldBeVisible(this.chunkViewRadius, MathUtil.floor(x) >> 5, MathUtil.floor(z) >> 5, this.playerChunkX, this.playerChunkZ); + } + + @Override + public void add(MapMarker marker) { + Position position = marker.transform.position; + if (this.isInViewDistance(position.x, position.z)) { + this.tracker.sendMapMarker(marker); + } + } + + @Override + public void addIgnoreViewDistance(MapMarker marker) { + this.tracker.sendMapMarker(marker); + } + + @Nullable + @Override + public Predicate getPlayerMapFilter() { + return this.tracker.getPlayerMapFilter(); + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/DeathMarkerProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/DeathMarkerProvider.java index ae96628e..26df1a4e 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/DeathMarkerProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/DeathMarkerProvider.java @@ -1,15 +1,15 @@ package com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers; import com.hypixel.hytale.math.vector.Transform; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.asset.type.gameplay.WorldMapConfig; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerDeathPositionData; import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerWorldData; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; -import com.hypixel.hytale.server.core.util.PositionUtil; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import javax.annotation.Nonnull; public class DeathMarkerProvider implements WorldMapManager.MarkerProvider { @@ -19,32 +19,24 @@ public class DeathMarkerProvider implements WorldMapManager.MarkerProvider { } @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { WorldMapConfig worldMapConfig = world.getGameplayConfig().getWorldMapConfig(); if (worldMapConfig.isDisplayDeathMarker()) { - Player player = tracker.getPlayer(); PlayerWorldData perWorldData = player.getPlayerConfigData().getPerWorldData(world.getName()); for (PlayerDeathPositionData deathPosition : perWorldData.getDeathPositions()) { - addDeathMarker(tracker, playerChunkX, playerChunkZ, deathPosition); + addDeathMarker(collector, deathPosition); } } } - private static void addDeathMarker(@Nonnull MapMarkerTracker tracker, int playerChunkX, int playerChunkZ, @Nonnull PlayerDeathPositionData deathPosition) { - String markerId = deathPosition.getMarkerId(); + private static void addDeathMarker(@Nonnull MarkersCollector collector, @Nonnull PlayerDeathPositionData deathPosition) { Transform transform = deathPosition.getTransform(); - int deathDay = deathPosition.getDay(); - tracker.trySendMarker( - -1, - playerChunkX, - playerChunkZ, - transform.getPosition(), - transform.getRotation().getYaw(), - markerId, - "Death (Day " + deathDay + ")", - transform, - (id, name, t) -> new MapMarker(id, name, "Death.png", PositionUtil.toTransformPacket(t), null) - ); + if (collector.isInViewDistance(transform)) { + int deathDay = deathPosition.getDay(); + Message name = Message.translation("server.map.markers.death").param("day", deathDay); + MapMarkerBuilder builder = new MapMarkerBuilder(deathPosition.getMarkerId(), "Death.png", transform).withName(name); + collector.addIgnoreViewDistance(builder.build()); + } } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/OtherPlayersMarkerProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/OtherPlayersMarkerProvider.java new file mode 100644 index 00000000..af320df9 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/OtherPlayersMarkerProvider.java @@ -0,0 +1,56 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers; + +import com.hypixel.hytale.math.vector.Transform; +import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.protocol.packets.worldmap.HeightDeltaIconComponent; +import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.protocol.packets.worldmap.PlayerMarkerComponent; +import com.hypixel.hytale.server.core.asset.type.gameplay.WorldMapConfig; +import com.hypixel.hytale.server.core.asset.type.gameplay.worldmap.PlayersMapMarkerConfig; +import com.hypixel.hytale.server.core.entity.entities.Player; +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.worldmap.WorldMapManager; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; +import java.util.function.Predicate; +import javax.annotation.Nonnull; + +public class OtherPlayersMarkerProvider implements WorldMapManager.MarkerProvider { + public static final OtherPlayersMarkerProvider INSTANCE = new OtherPlayersMarkerProvider(); + + private OtherPlayersMarkerProvider() { + } + + @Override + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { + WorldMapConfig worldMapConfig = world.getGameplayConfig().getWorldMapConfig(); + if (worldMapConfig.isDisplayPlayers()) { + PlayersMapMarkerConfig playersMapConfig = worldMapConfig.getPlayersConfig(); + Predicate playerMapFilter = collector.getPlayerMapFilter(); + + for (PlayerRef otherPlayer : world.getPlayerRefs()) { + if (!otherPlayer.getUuid().equals(player.getUuid())) { + Transform otherPlayerTransform = otherPlayer.getTransform(); + Vector3d otherPos = otherPlayerTransform.getPosition(); + if (collector.isInViewDistance(otherPos) && (playerMapFilter == null || !playerMapFilter.test(otherPlayer))) { + PlayerMarkerComponent playerMarker = new PlayerMarkerComponent(otherPlayer.getUuid()); + HeightDeltaIconComponent heightDeltaComponent = new HeightDeltaIconComponent( + playersMapConfig.getIconSwapHeightDelta(), + playersMapConfig.getAboveIcon(), + playersMapConfig.getIconSwapHeightDelta(), + playersMapConfig.getBelowIcon() + ); + String markerId = "Player-" + otherPlayer.getUuid(); + MapMarker marker = new MapMarkerBuilder(markerId, "Player.png", otherPlayerTransform) + .withCustomName(otherPlayer.getUsername()) + .withComponent(playerMarker) + .withComponent(heightDeltaComponent) + .build(); + collector.addIgnoreViewDistance(marker); + } + } + } + } + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/POIMarkerProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/POIMarkerProvider.java index f9f91d41..624dd856 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/POIMarkerProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/POIMarkerProvider.java @@ -1,9 +1,10 @@ package com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers; import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import java.util.Map; import javax.annotation.Nonnull; @@ -14,11 +15,11 @@ public class POIMarkerProvider implements WorldMapManager.MarkerProvider { } @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { Map globalMarkers = world.getWorldMapManager().getPointsOfInterest(); if (!globalMarkers.isEmpty()) { for (MapMarker marker : globalMarkers.values()) { - tracker.trySendMarker(chunkViewRadius, playerChunkX, playerChunkZ, marker); + collector.add(marker); } } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PerWorldDataMarkerProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PerWorldDataMarkerProvider.java deleted file mode 100644 index d696f8a8..00000000 --- a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PerWorldDataMarkerProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers; - -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; -import com.hypixel.hytale.server.core.entity.entities.Player; -import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerWorldData; -import com.hypixel.hytale.server.core.universe.world.World; -import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; -import javax.annotation.Nonnull; - -public class PerWorldDataMarkerProvider implements WorldMapManager.MarkerProvider { - public static final PerWorldDataMarkerProvider INSTANCE = new PerWorldDataMarkerProvider(); - - private PerWorldDataMarkerProvider() { - } - - @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { - Player player = tracker.getPlayer(); - PlayerWorldData perWorldData = player.getPlayerConfigData().getPerWorldData(world.getName()); - MapMarker[] worldMapMarkers = perWorldData.getWorldMapMarkers(); - if (worldMapMarkers != null) { - for (MapMarker marker : worldMapMarkers) { - tracker.trySendMarker(chunkViewRadius, playerChunkX, playerChunkZ, marker); - } - } - } -} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PersonalMarkersProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PersonalMarkersProvider.java new file mode 100644 index 00000000..4384abc9 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PersonalMarkersProvider.java @@ -0,0 +1,25 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers; + +import com.hypixel.hytale.server.core.entity.entities.Player; +import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerWorldData; +import com.hypixel.hytale.server.core.universe.world.World; +import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarker; +import javax.annotation.Nonnull; + +public class PersonalMarkersProvider implements WorldMapManager.MarkerProvider { + public static final PersonalMarkersProvider INSTANCE = new PersonalMarkersProvider(); + + private PersonalMarkersProvider() { + } + + @Override + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { + PlayerWorldData perWorldData = player.getPlayerConfigData().getPerWorldData(world.getName()); + + for (UserMapMarker userMapMarker : perWorldData.getUserMapMarkers()) { + collector.add(userMapMarker.toProtocolMarker()); + } + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PlayerIconMarkerProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PlayerIconMarkerProvider.java deleted file mode 100644 index b580daa4..00000000 --- a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/PlayerIconMarkerProvider.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers; - -import com.hypixel.hytale.math.vector.Transform; -import com.hypixel.hytale.math.vector.Vector3d; -import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; -import com.hypixel.hytale.server.core.asset.type.gameplay.WorldMapConfig; -import com.hypixel.hytale.server.core.entity.entities.Player; -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.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; -import com.hypixel.hytale.server.core.util.PositionUtil; -import java.util.function.Predicate; -import javax.annotation.Nonnull; - -public class PlayerIconMarkerProvider implements WorldMapManager.MarkerProvider { - public static final PlayerIconMarkerProvider INSTANCE = new PlayerIconMarkerProvider(); - - private PlayerIconMarkerProvider() { - } - - @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { - WorldMapConfig worldMapConfig = world.getGameplayConfig().getWorldMapConfig(); - if (worldMapConfig.isDisplayPlayers()) { - Player player = tracker.getPlayer(); - int chunkViewRadiusSq = chunkViewRadius * chunkViewRadius; - Predicate playerMapFilter = tracker.getPlayerMapFilter(); - - for (PlayerRef otherPlayer : world.getPlayerRefs()) { - if (!otherPlayer.getUuid().equals(player.getUuid())) { - Transform otherPlayerTransform = otherPlayer.getTransform(); - Vector3d otherPos = otherPlayerTransform.getPosition(); - int otherChunkX = (int)otherPos.x >> 5; - int otherChunkZ = (int)otherPos.z >> 5; - int chunkDiffX = otherChunkX - playerChunkX; - int chunkDiffZ = otherChunkZ - playerChunkZ; - int chunkDistSq = chunkDiffX * chunkDiffX + chunkDiffZ * chunkDiffZ; - if (chunkDistSq <= chunkViewRadiusSq && (playerMapFilter == null || !playerMapFilter.test(otherPlayer))) { - tracker.trySendMarker( - chunkViewRadius, - playerChunkX, - playerChunkZ, - otherPos, - otherPlayer.getHeadRotation().getYaw(), - "Player-" + otherPlayer.getUuid(), - otherPlayer.getUsername(), - otherPlayer, - (id, name, op) -> new MapMarker(id, name, "Player.png", PositionUtil.toTransformPacket(op.getTransform()), null) - ); - } - } - } - } - } -} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/RespawnMarkerProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/RespawnMarkerProvider.java index 10d376fd..f7e4ecc1 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/RespawnMarkerProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/RespawnMarkerProvider.java @@ -4,11 +4,12 @@ import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; import com.hypixel.hytale.server.core.asset.type.gameplay.WorldMapConfig; +import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerRespawnPointData; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; -import com.hypixel.hytale.server.core.util.PositionUtil; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import javax.annotation.Nonnull; public class RespawnMarkerProvider implements WorldMapManager.MarkerProvider { @@ -18,33 +19,23 @@ public class RespawnMarkerProvider implements WorldMapManager.MarkerProvider { } @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { WorldMapConfig worldMapConfig = world.getGameplayConfig().getWorldMapConfig(); if (worldMapConfig.isDisplayHome()) { - PlayerRespawnPointData[] respawnPoints = tracker.getPlayer().getPlayerConfigData().getPerWorldData(world.getName()).getRespawnPoints(); + PlayerRespawnPointData[] respawnPoints = player.getPlayerConfigData().getPerWorldData(world.getName()).getRespawnPoints(); if (respawnPoints != null) { for (int i = 0; i < respawnPoints.length; i++) { - addRespawnMarker(tracker, playerChunkX, playerChunkZ, respawnPoints[i], i); + addRespawnMarker(collector, respawnPoints[i], i); } } } } - private static void addRespawnMarker( - @Nonnull MapMarkerTracker tracker, int playerChunkX, int playerChunkZ, @Nonnull PlayerRespawnPointData respawnPoint, int index - ) { + private static void addRespawnMarker(MarkersCollector collector, PlayerRespawnPointData respawnPoint, int index) { String respawnPointName = respawnPoint.getName(); Vector3i respawnPointPosition = respawnPoint.getBlockPosition(); - tracker.trySendMarker( - -1, - playerChunkX, - playerChunkZ, - respawnPointPosition.toVector3d(), - 0.0F, - respawnPointName + index, - respawnPointName, - respawnPointPosition, - (id, name, rp) -> new MapMarker(id, name, "Home.png", PositionUtil.toTransformPacket(new Transform(rp)), null) - ); + String markerId = respawnPointName + index; + MapMarker marker = new MapMarkerBuilder(markerId, "Home.png", new Transform(respawnPointPosition)).withCustomName(respawnPointName).build(); + collector.addIgnoreViewDistance(marker); } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/SharedMarkersProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/SharedMarkersProvider.java new file mode 100644 index 00000000..59387d59 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/SharedMarkersProvider.java @@ -0,0 +1,25 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers; + +import com.hypixel.hytale.server.core.entity.entities.Player; +import com.hypixel.hytale.server.core.universe.world.World; +import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.worldstore.WorldMarkersResource; +import javax.annotation.Nonnull; + +public class SharedMarkersProvider implements WorldMapManager.MarkerProvider { + public static final SharedMarkersProvider INSTANCE = new SharedMarkersProvider(); + + private SharedMarkersProvider() { + } + + @Override + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { + WorldMarkersResource worldMarkersResource = world.getChunkStore().getStore().getResource(WorldMarkersResource.getResourceType()); + + for (UserMapMarker userMapMarker : worldMarkersResource.getUserMapMarkers()) { + collector.add(userMapMarker.toProtocolMarker()); + } + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/SpawnMarkerProvider.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/SpawnMarkerProvider.java index e4aa57c2..4b58a693 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/SpawnMarkerProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/providers/SpawnMarkerProvider.java @@ -3,12 +3,13 @@ package com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.asset.type.gameplay.WorldMapConfig; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager; -import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerTracker; -import com.hypixel.hytale.server.core.util.PositionUtil; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector; import javax.annotation.Nonnull; public class SpawnMarkerProvider implements WorldMapManager.MarkerProvider { @@ -18,24 +19,16 @@ public class SpawnMarkerProvider implements WorldMapManager.MarkerProvider { } @Override - public void update(@Nonnull World world, @Nonnull MapMarkerTracker tracker, int chunkViewRadius, int playerChunkX, int playerChunkZ) { + public void update(@Nonnull World world, @Nonnull Player player, @Nonnull MarkersCollector collector) { WorldMapConfig worldMapConfig = world.getGameplayConfig().getWorldMapConfig(); if (worldMapConfig.isDisplaySpawn()) { - Player player = tracker.getPlayer(); Transform spawnPoint = world.getWorldConfig().getSpawnProvider().getSpawnPoint(player); if (spawnPoint != null) { Vector3d spawnPosition = spawnPoint.getPosition(); - tracker.trySendMarker( - chunkViewRadius, - playerChunkX, - playerChunkZ, - spawnPosition, - spawnPoint.getRotation().getYaw(), - "Spawn", - "Spawn", - spawnPosition, - (id, name, pos) -> new MapMarker(id, name, "Spawn.png", PositionUtil.toTransformPacket(new Transform(pos)), null) - ); + MapMarker marker = new MapMarkerBuilder("Spawn", "Spawn.png", new Transform(spawnPosition)) + .withName(Message.translation("server.general.spawn")) + .build(); + collector.add(marker); } } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMapMarker.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMapMarker.java new file mode 100644 index 00000000..ddb5cd92 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMapMarker.java @@ -0,0 +1,148 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers.user; + +import com.hypixel.hytale.codec.Codec; +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.math.vector.Transform; +import com.hypixel.hytale.protocol.Color; +import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.protocol.packets.worldmap.PlacedByMarkerComponent; +import com.hypixel.hytale.protocol.packets.worldmap.TintComponent; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.codec.ProtocolCodecs; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerBuilder; +import java.util.UUID; +import javax.annotation.Nullable; + +public class UserMapMarker { + public static final BuilderCodec CODEC = BuilderCodec.builder(UserMapMarker.class, UserMapMarker::new) + .append(new KeyedCodec<>("Id", Codec.STRING), (marker, o) -> marker.id = o, marker -> marker.id) + .add() + .append(new KeyedCodec<>("X", Codec.FLOAT), (marker, o) -> marker.x = o, marker -> marker.x) + .add() + .append(new KeyedCodec<>("Z", Codec.FLOAT), (marker, o) -> marker.z = o, marker -> marker.z) + .add() + .append(new KeyedCodec<>("Name", Codec.STRING), (marker, o) -> marker.name = o, marker -> marker.name) + .add() + .append(new KeyedCodec<>("Icon", Codec.STRING), (marker, o) -> marker.icon = o, marker -> marker.icon) + .add() + .append(new KeyedCodec<>("ColorTint", ProtocolCodecs.COLOR), (marker, o) -> marker.colorTint = o, marker -> marker.colorTint) + .add() + .append(new KeyedCodec<>("CreatedByUuid", Codec.UUID_BINARY), (marker, o) -> marker.createdByUuid = o, marker -> marker.createdByUuid) + .add() + .append(new KeyedCodec<>("CreatedByName", Codec.STRING), (marker, o) -> marker.createdByName = o, marker -> marker.createdByName) + .add() + .build(); + public static final ArrayCodec ARRAY_CODEC = new ArrayCodec<>(CODEC, UserMapMarker[]::new); + private String id; + private float x; + private float z; + @Nullable + private String name; + private String icon; + private Color colorTint; + @Nullable + private UUID createdByUuid; + @Nullable + private String createdByName; + @Nullable + private MapMarker cachedProto; + + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + public float getX() { + return this.x; + } + + public float getZ() { + return this.z; + } + + public void setPosition(float blockX, float blockZ) { + this.x = blockX; + this.z = blockZ; + this.invalidateCachedProto(); + } + + @Nullable + public String getName() { + return this.name; + } + + public void setName(@Nullable String name) { + this.name = name; + this.invalidateCachedProto(); + } + + public String getIcon() { + return this.icon; + } + + public void setIcon(String icon) { + this.icon = icon; + this.invalidateCachedProto(); + } + + public Color getColorTint() { + return this.colorTint; + } + + public void setColorTint(Color colorTint) { + this.colorTint = colorTint; + this.invalidateCachedProto(); + } + + @Nullable + public UUID getCreatedByUuid() { + return this.createdByUuid; + } + + public UserMapMarker withCreatedByUuid(@Nullable UUID uuid) { + this.createdByUuid = uuid; + this.invalidateCachedProto(); + return this; + } + + @Nullable + public String getCreatedByName() { + return this.createdByName; + } + + public UserMapMarker withCreatedByName(@Nullable String name) { + this.createdByName = name; + this.invalidateCachedProto(); + return this; + } + + public MapMarker toProtocolMarker() { + if (this.cachedProto == null) { + MapMarkerBuilder builder = new MapMarkerBuilder(this.id, this.icon, new Transform(this.x, 100.0, this.z)); + if (this.name != null) { + builder.withCustomName(this.name); + } + + if (this.colorTint != null) { + builder.withComponent(new TintComponent(this.colorTint)); + } + + if (this.createdByName != null) { + builder.withComponent(new PlacedByMarkerComponent(Message.raw(this.createdByName).getFormattedMessage(), this.createdByUuid)); + } + + this.cachedProto = builder.build(); + } + + return this.cachedProto; + } + + private void invalidateCachedProto() { + this.cachedProto = null; + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMapMarkersStore.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMapMarkersStore.java new file mode 100644 index 00000000..7762f5ec --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMapMarkersStore.java @@ -0,0 +1,33 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers.user; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public interface UserMapMarkersStore { + @Nonnull + Collection getUserMapMarkers(); + + @Nonnull + Collection getUserMapMarkers(UUID var1); + + void setUserMapMarkers(@Nullable Collection var1); + + default void addUserMapMarker(UserMapMarker marker) { + List markers = new ArrayList<>(this.getUserMapMarkers()); + markers.add(marker); + this.setUserMapMarkers(markers); + } + + default void removeUserMapMarker(String markerId) { + List markers = new ArrayList<>(this.getUserMapMarkers()); + markers.removeIf(marker -> markerId.equals(marker.getId())); + this.setUserMapMarkers(markers); + } + + @Nullable + UserMapMarker getUserMapMarker(String var1); +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMarkerValidator.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMarkerValidator.java new file mode 100644 index 00000000..c08adc8a --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/user/UserMarkerValidator.java @@ -0,0 +1,100 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers.user; + +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.math.vector.Transform; +import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.protocol.packets.worldmap.CreateUserMarker; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.asset.type.gameplay.worldmap.UserMapMarkerConfig; +import com.hypixel.hytale.server.core.entity.UUIDComponent; +import com.hypixel.hytale.server.core.entity.entities.Player; +import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; +import com.hypixel.hytale.server.core.universe.world.World; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.worldstore.WorldMarkersResource; +import java.util.Collection; +import java.util.UUID; + +public final class UserMarkerValidator { + private static final int NAME_LENGTH_LIMIT = 24; + + public static UserMarkerValidator.PlaceResult validatePlacing(Ref ref, CreateUserMarker packet) { + boolean shared = packet.shared; + Store store = ref.getStore(); + World world = store.getExternalData().getWorld(); + Player player = store.getComponent(ref, Player.getComponentType()); + if (isPlayerTooFarFromMarker(ref, packet.x, packet.z)) { + return new UserMarkerValidator.Fail("server.worldmap.markers.edit.tooFar"); + } else if (packet.name != null && packet.name.length() > 24) { + return new UserMarkerValidator.Fail("server.worldmap.markers.create.nameTooLong"); + } else { + UserMapMarkersStore markersStore = (UserMapMarkersStore)(shared + ? world.getChunkStore().getStore().getResource(WorldMarkersResource.getResourceType()) + : player.getPlayerConfigData().getPerWorldData(world.getName())); + UUID playerUuid = store.getComponent(ref, UUIDComponent.getComponentType()).getUuid(); + Collection markersByPlayer = markersStore.getUserMapMarkers(playerUuid); + UserMapMarkerConfig markersConfig = world.getGameplayConfig().getWorldMapConfig().getUserMapMarkerConfig(); + if (!markersConfig.isAllowCreatingMarkers()) { + return new UserMarkerValidator.Fail("server.worldmap.markers.create.creationDisabled"); + } else { + int limit = shared ? markersConfig.getMaxSharedMarkersPerPlayer() : markersConfig.getMaxPersonalMarkersPerPlayer(); + if (markersByPlayer.size() + 1 >= limit) { + String msg = shared ? "server.worldmap.markers.create.tooManyShared" : "server.worldmap.markers.create.tooManyPersonal"; + return new UserMarkerValidator.Fail(Message.translation(msg).param("limit", limit)); + } else { + return new UserMarkerValidator.CanSpawn(player, markersStore); + } + } + } + } + + public static UserMarkerValidator.RemoveResult validateRemove(Ref ref, UserMapMarker marker) { + Store store = ref.getStore(); + World world = store.getExternalData().getWorld(); + if (isPlayerTooFarFromMarker(ref, marker.getX(), marker.getZ())) { + return new UserMarkerValidator.Fail("server.worldmap.markers.edit.tooFar"); + } else { + UserMapMarkerConfig markersConfig = world.getGameplayConfig().getWorldMapConfig().getUserMapMarkerConfig(); + UUID playerUuid = store.getComponent(ref, UUIDComponent.getComponentType()).getUuid(); + UUID createdBy = marker.getCreatedByUuid(); + boolean isOwner = playerUuid.equals(createdBy) || createdBy == null; + boolean hasPermission = isOwner || markersConfig.isAllowDeleteOtherPlayersSharedMarkers(); + return (UserMarkerValidator.RemoveResult)(!hasPermission + ? new UserMarkerValidator.Fail("server.worldmap.markers.edit.notOwner") + : new UserMarkerValidator.CanRemove()); + } + } + + private static boolean isPlayerTooFarFromMarker(Ref ref, double markerX, double markerZ) { + Store store = ref.getStore(); + Player player = store.getComponent(ref, Player.getComponentType()); + Transform transform = store.getComponent(ref, TransformComponent.getComponentType()).getTransform(); + Vector3d playerPosition = transform.getPosition(); + double distanceToMarker = playerPosition.distanceSquaredTo(markerX, playerPosition.y, markerZ); + return distanceToMarker > getMaxRemovalDistanceSquared(player); + } + + private static double getMaxRemovalDistanceSquared(Player player) { + double maxDistance = player.getViewRadius() * 1.5 * 32.0; + return maxDistance * maxDistance; + } + + public record CanRemove() implements UserMarkerValidator.RemoveResult { + } + + public record CanSpawn(Player player, UserMapMarkersStore markersStore) implements UserMarkerValidator.PlaceResult { + } + + public record Fail(Message errorMsg) implements UserMarkerValidator.PlaceResult, UserMarkerValidator.RemoveResult { + public Fail(String messageKey) { + this(Message.translation(messageKey)); + } + } + + public sealed interface PlaceResult permits UserMarkerValidator.Fail, UserMarkerValidator.CanSpawn { + } + + public sealed interface RemoveResult permits UserMarkerValidator.Fail, UserMarkerValidator.CanRemove { + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/utils/MapMarkerUtils.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/utils/MapMarkerUtils.java new file mode 100644 index 00000000..43670b58 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/utils/MapMarkerUtils.java @@ -0,0 +1,24 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers.utils; + +import com.hypixel.hytale.protocol.packets.worldmap.MapMarker; +import com.hypixel.hytale.protocol.packets.worldmap.MapMarkerComponent; +import com.hypixel.hytale.protocol.packets.worldmap.PlacedByMarkerComponent; + +public final class MapMarkerUtils { + private MapMarkerUtils() { + } + + public static boolean isUserMarker(MapMarker protoMarker) { + if (protoMarker.components == null) { + return false; + } else { + for (MapMarkerComponent component : protoMarker.components) { + if (component instanceof PlacedByMarkerComponent) { + return true; + } + } + + return false; + } + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/worldstore/WorldMarkersResource.java b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/worldstore/WorldMarkersResource.java new file mode 100644 index 00000000..caa978d8 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/worldmap/markers/worldstore/WorldMarkersResource.java @@ -0,0 +1,78 @@ +package com.hypixel.hytale.server.core.universe.world.worldmap.markers.worldstore; + +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.component.Resource; +import com.hypixel.hytale.component.ResourceType; +import com.hypixel.hytale.server.core.universe.Universe; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarker; +import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarkersStore; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; +import org.checkerframework.checker.nullness.compatqual.NullableDecl; + +public class WorldMarkersResource implements Resource, UserMapMarkersStore { + public static final BuilderCodec CODEC = BuilderCodec.builder(WorldMarkersResource.class, WorldMarkersResource::new) + .append( + new KeyedCodec<>("UserMarkers", UserMapMarker.ARRAY_CODEC), + (res, value) -> res.mapMarkersById = Arrays.stream(value).collect(Collectors.toConcurrentMap(UserMapMarker::getId, m -> (UserMapMarker)m)), + res -> res.getUserMapMarkers().toArray(new UserMapMarker[0]) + ) + .documentation("The stored map markers submitted by this player.") + .add() + .build(); + private Map mapMarkersById = new ConcurrentHashMap<>(); + + public static ResourceType getResourceType() { + return Universe.get().getWorldMarkersResourceType(); + } + + @NonNullDecl + @Override + public Collection getUserMapMarkers() { + return this.mapMarkersById.values(); + } + + @NonNullDecl + @Override + public Collection getUserMapMarkers(UUID createdByUuid) { + List filtered = new ArrayList<>(); + + for (UserMapMarker marker : this.mapMarkersById.values()) { + if (createdByUuid.equals(marker.getCreatedByUuid())) { + filtered.add(marker); + } + } + + return filtered; + } + + @Override + public void setUserMapMarkers(@NullableDecl Collection markers) { + this.mapMarkersById = (Map)(markers == null + ? new ConcurrentHashMap<>() + : markers.stream().collect(Collectors.toConcurrentMap(UserMapMarker::getId, x -> (UserMapMarker)x))); + } + + @NullableDecl + @Override + public UserMapMarker getUserMapMarker(String markerId) { + return this.mapMarkersById.get(markerId); + } + + @NullableDecl + @Override + public Resource clone() { + WorldMarkersResource clone = new WorldMarkersResource(); + clone.mapMarkersById = new ConcurrentHashMap<>(this.mapMarkersById); + return clone; + } +} diff --git a/src/com/hypixel/hytale/server/core/util/MessageUtil.java b/src/com/hypixel/hytale/server/core/util/MessageUtil.java index b635f27d..77c0182b 100644 --- a/src/com/hypixel/hytale/server/core/util/MessageUtil.java +++ b/src/com/hypixel/hytale/server/core/util/MessageUtil.java @@ -14,7 +14,13 @@ import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.asset.util.ColorParseUtil; import com.hypixel.hytale.server.core.modules.i18n.I18nModule; import com.hypixel.hytale.server.core.universe.PlayerRef; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.format.FormatStyle; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -142,7 +148,7 @@ public class MessageUtil { } else if (replacement != null) { String formattedReplacement; formattedReplacement = ""; - label147: + label155: switch (format) { case "upper": if (replacement instanceof StringParamValue s) { @@ -165,7 +171,7 @@ public class MessageUtil { case LongParamValue l -> Long.toString(l.value); default -> ""; }; - break label147; + break label155; case "decimal": case null: default: @@ -177,7 +183,7 @@ public class MessageUtil { case LongParamValue l -> Long.toString(l.value); default -> ""; }; - break label147; + break label155; } case "plural": if (options != null) { @@ -195,6 +201,24 @@ public class MessageUtil { formattedReplacement = formatText(selected, params, messageParams); } + break; + case "date": + Instant instantx = parseDateTime(replacement); + if (instantx != null) { + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(Locale.getDefault()); + formattedReplacement = formatter.format(instantx.atZone(ZoneId.systemDefault())); + } else { + formattedReplacement = ""; + } + break; + case "time": + Instant instant = parseDateTime(replacement); + if (instant != null) { + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(Locale.getDefault()); + formattedReplacement = formatter.format(instant.atZone(ZoneId.systemDefault())); + } else { + formattedReplacement = ""; + } case null: } @@ -434,4 +458,29 @@ public class MessageUtil { private static String getKoreanPluralCategory(int n) { return "other"; } + + @Nullable + private static Instant parseDateTime(@Nonnull ParamValue value) { + return switch (value) { + case LongParamValue l -> { + Instant var10 = Instant.ofEpochMilli(l.value); + yield var10; + } + case StringParamValue s -> { + Instant var9; + try { + var9 = Instant.parse(s.value); + } catch (DateTimeParseException var7) { + var9 = null; + yield var9; + } + + yield var9; + } + default -> { + Object var3 = null; + yield var3; + } + }; + } } diff --git a/src/com/hypixel/hytale/server/core/util/NotificationUtil.java b/src/com/hypixel/hytale/server/core/util/NotificationUtil.java index 2f68098f..7525c8b6 100644 --- a/src/com/hypixel/hytale/server/core/util/NotificationUtil.java +++ b/src/com/hypixel/hytale/server/core/util/NotificationUtil.java @@ -138,7 +138,7 @@ public class NotificationUtil { sendNotification(handler, Message.raw(message), Message.raw(secondaryMessage), null, null, NotificationStyle.Default); } - public static void sendNotification(@Nonnull PacketHandler handler, Message message, Message secondaryMessage, String icon) { + public static void sendNotification(@Nonnull PacketHandler handler, @Nonnull Message message, @Nullable Message secondaryMessage, @Nullable String icon) { sendNotification(handler, message, secondaryMessage, icon, null, NotificationStyle.Default); } diff --git a/src/com/hypixel/hytale/server/core/util/backup/BackupTask.java b/src/com/hypixel/hytale/server/core/util/backup/BackupTask.java index 9e37b1b7..e02ca526 100644 --- a/src/com/hypixel/hytale/server/core/util/backup/BackupTask.java +++ b/src/com/hypixel/hytale/server/core/util/backup/BackupTask.java @@ -45,7 +45,7 @@ public class BackupTask { Files.createDirectories(backupDir); Files.createDirectories(archiveDir); BackupTask.cleanOrArchiveOldBackups(backupDir, archiveDir); - BackupTask.cleanOldBackups(archiveDir); + BackupTask.cleanOldArchives(archiveDir); String backupName = BackupTask.BACKUP_FILE_DATE_FORMATTER.format(LocalDateTime.now()) + ".zip"; Path tempZip = backupDir.resolve(backupName + ".tmp"); BackupUtil.walkFileTreeAndZip(universeDir, tempZip); @@ -73,7 +73,7 @@ public class BackupTask { FileTime oldestBackupTime = Files.getLastModifiedTime(oldestBackup); FileTime lastArchive = getMostRecentArchive(archiveDir); boolean doArchive = lastArchive == null - || Duration.between(oldestBackupTime.toInstant(), lastArchive.toInstant()).compareTo(BACKUP_ARCHIVE_FREQUENCY) > 0; + || Duration.between(lastArchive.toInstant(), oldestBackupTime.toInstant()).compareTo(BACKUP_ARCHIVE_FREQUENCY) > 0; if (doArchive) { oldBackups = oldBackups.subList(1, oldBackups.size()); Files.move(oldestBackup, archiveDir.resolve(oldestBackup.getFileName()), StandardCopyOption.REPLACE_EXISTING); @@ -88,13 +88,13 @@ public class BackupTask { } } - private static void cleanOldBackups(@Nonnull Path dir) throws IOException { - int maxCount = Options.getOptionSet().valueOf(Options.BACKUP_MAX_COUNT); + private static void cleanOldArchives(@Nonnull Path dir) throws IOException { + int maxCount = Options.getOptionSet().valueOf(Options.BACKUP_ARCHIVE_MAX_COUNT); if (maxCount >= 1) { List oldBackups = BackupUtil.findOldBackups(dir, maxCount); if (oldBackups != null && !oldBackups.isEmpty()) { for (Path path : oldBackups) { - LOGGER.at(Level.INFO).log("Clearing old backup: %s", path); + LOGGER.at(Level.INFO).log("Clearing old archive backup: %s", path); Files.deleteIfExists(path); } } @@ -108,9 +108,9 @@ public class BackupTask { try (DirectoryStream stream = Files.newDirectoryStream(dir)) { for (Path path : stream) { if (Files.isRegularFile(path)) { - FileTime modifiedTime = Files.getLastModifiedTime(path); - if (mostRecent == null || modifiedTime.compareTo(mostRecent) > 0) { - mostRecent = modifiedTime; + FileTime modificationTime = Files.getLastModifiedTime(path); + if (mostRecent == null || modificationTime.compareTo(mostRecent) > 0) { + mostRecent = modificationTime; } } } diff --git a/src/com/hypixel/hytale/server/flock/FlockMembershipSystems.java b/src/com/hypixel/hytale/server/flock/FlockMembershipSystems.java index 78989a9c..24613c94 100644 --- a/src/com/hypixel/hytale/server/flock/FlockMembershipSystems.java +++ b/src/com/hypixel/hytale/server/flock/FlockMembershipSystems.java @@ -346,6 +346,48 @@ public class FlockMembershipSystems { } } + public static class FilterPlayerFlockDamageSystem extends DamageEventSystem { + @Nonnull + private final Query query = Query.and(Player.getComponentType(), FlockMembership.getComponentType()); + + @Nullable + @Override + public SystemGroup getGroup() { + return DamageModule.get().getFilterDamageGroup(); + } + + @Nonnull + @Override + public Query getQuery() { + return this.query; + } + + public void handle( + int index, + @Nonnull ArchetypeChunk archetypeChunk, + @Nonnull Store store, + @Nonnull CommandBuffer commandBuffer, + @Nonnull Damage damage + ) { + FlockMembership flockMembership = archetypeChunk.getComponent(index, FlockMembership.getComponentType()); + + assert flockMembership != null; + + if (damage.getSource() instanceof Damage.EntitySource entitySource) { + Ref flockRef = flockMembership.getFlockRef(); + if (flockRef != null && flockRef.isValid()) { + Ref sourceRef = entitySource.getRef(); + if (sourceRef.isValid()) { + EntityGroup group = store.getComponent(flockRef, EntityGroup.getComponentType()); + if (group != null && group.isMember(sourceRef)) { + damage.setCancelled(true); + } + } + } + } + } + } + public static class NPCAddedFromWorldGen extends HolderSystem { @Nullable private final ComponentType npcComponentType = NPCEntity.getComponentType(); diff --git a/src/com/hypixel/hytale/server/flock/FlockPlugin.java b/src/com/hypixel/hytale/server/flock/FlockPlugin.java index 0687a148..ac47283a 100644 --- a/src/com/hypixel/hytale/server/flock/FlockPlugin.java +++ b/src/com/hypixel/hytale/server/flock/FlockPlugin.java @@ -108,6 +108,7 @@ public class FlockPlugin extends JavaPlugin { entityStoreRegistry.registerSystem(new PositionCacheSystems.OnFlockJoinSystem(NPCEntity.getComponentType(), this.flockMembershipComponentType)); entityStoreRegistry.registerSystem(new FlockDeathSystems.EntityDeath()); entityStoreRegistry.registerSystem(new FlockDeathSystems.PlayerDeath()); + entityStoreRegistry.registerSystem(new FlockMembershipSystems.FilterPlayerFlockDamageSystem()); entityStoreRegistry.registerSystem(new FlockMembershipSystems.OnDamageReceived()); entityStoreRegistry.registerSystem(new FlockMembershipSystems.OnDamageDealt()); entityStoreRegistry.registerSystem(new FlockMembershipSystems.NPCAddedFromWorldGen()); @@ -177,7 +178,7 @@ public class FlockPlugin extends JavaPlugin { int flockSize, FlockAsset flockDefinition, TriConsumer, Store> preAddToWorld, - TriConsumer, Store> postSpawn, + @Nullable TriConsumer, Store> postSpawn, @Nonnull Store store ) { if (flockSize > 1 && npcRef.isValid()) { diff --git a/src/com/hypixel/hytale/server/flock/StoredFlock.java b/src/com/hypixel/hytale/server/flock/StoredFlock.java index bc05dfc4..f30414ae 100644 --- a/src/com/hypixel/hytale/server/flock/StoredFlock.java +++ b/src/com/hypixel/hytale/server/flock/StoredFlock.java @@ -90,4 +90,21 @@ public class StoredFlock { return storedFlock; } + + @Nonnull + public StoredFlock cloneSerializable() { + StoredFlock storedFlock = new StoredFlock(); + if (this.members != null) { + ComponentRegistry.Data data = EntityStore.REGISTRY.getData(); + Holder[] newMembers = new Holder[this.members.length]; + + for (int i = 0; i < newMembers.length; i++) { + newMembers[i] = this.members[i].cloneSerializable(data); + } + + storedFlock.members = newMembers; + } + + return storedFlock; + } } diff --git a/src/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstruction.java b/src/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstruction.java index 8de498b3..ede07440 100644 --- a/src/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstruction.java +++ b/src/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstruction.java @@ -93,14 +93,14 @@ public class BuilderInstruction extends BuilderBase { "Internal identifier tag for debugging", null ); - this.getBoolean(data, "Enabled", this.enabled, true, BuilderDescriptorState.Stable, "Whether this step should be enabled on the NPC", null); + this.getBoolean(data, "Enabled", this.enabled, true, BuilderDescriptorState.Stable, "Whether this instruction should be enabled on the NPC", null); this.getObject( data, "Sensor", this.sensorBuilderObjectReferenceHelper, BuilderDescriptorState.Stable, - "Sensor for testing if step can be applied", - "Sensor for testing if step can be applied. If not supplied, will always match", + "Sensor for testing if instruction can be applied", + "Sensor for testing if instruction can be applied. If not supplied, will always match", helper ); features.lock(); @@ -139,7 +139,7 @@ public class BuilderInstruction extends BuilderBase { ) ); this.getBoolean( - data, "Continue", v -> this.continueAfter = v, false, BuilderDescriptorState.WorkInProgress, "Continue after this step was executed", null + data, "Continue", v -> this.continueAfter = v, false, BuilderDescriptorState.WorkInProgress, "Continue after this instruction was executed", null ); this.getDouble( data, @@ -148,7 +148,7 @@ public class BuilderInstruction extends BuilderBase { 1.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, - "Weighted chance of picking this step in a random instruction", + "Weighted chance of picking this instruction in a random instruction", null ); this.getBoolean( @@ -157,8 +157,8 @@ public class BuilderInstruction extends BuilderBase { v -> this.treeMode = v, false, BuilderDescriptorState.Stable, - "Whether this step and its contents should be treated like a traditional behaviour tree.", - "Whether this step and its contents should be treated like a traditional behaviour tree, i.e. will continue if all child steps fail" + "Whether this instruction and its contents should be treated like a traditional behaviour tree.", + "Whether this instruction and its contents should be treated like a traditional behaviour tree, i.e. will continue if all child instructions fail" ); this.getBoolean( data, @@ -166,13 +166,13 @@ public class BuilderInstruction extends BuilderBase { this.invertTreeModeResult, false, BuilderDescriptorState.Stable, - "Whether or not to invert the result of TreeMode evaluation when passing up to parent TreeMode steps", + "Whether or not to invert the result of TreeMode evaluation when passing up to parent TreeMode instructions", null ); this.decreaseDepth(); - this.validateOneOrNonePresent("BodyMotion", this.bodyMotionBuilderObjectReferenceHelper, "Steps", this.steps); - this.validateOneOrNonePresent("HeadMotion", this.headMotionBuilderObjectReferenceHelper, "Steps", this.steps); - this.validateOneOrNonePresent("Actions", this.actionsBuilderObjectReferenceHelper, "Steps", this.steps); + this.validateOneOrNonePresent("BodyMotion", this.bodyMotionBuilderObjectReferenceHelper, "Instructions", this.steps); + this.validateOneOrNonePresent("HeadMotion", this.headMotionBuilderObjectReferenceHelper, "Instructions", this.steps); + this.validateOneOrNonePresent("Actions", this.actionsBuilderObjectReferenceHelper, "Instructions", this.steps); this.validateBooleanImplicationAnyAntecedent(ANTECEDENT, new boolean[]{this.treeMode}, true, SUBSEQUENT, new boolean[]{this.continueAfter}, false); return this; } diff --git a/src/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstructionRandomized.java b/src/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstructionRandomized.java index 7ad35361..215df625 100644 --- a/src/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstructionRandomized.java +++ b/src/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstructionRandomized.java @@ -101,14 +101,14 @@ public class BuilderInstructionRandomized extends BuilderInstruction { "Internal identifier tag for debugging", null ); - this.getBoolean(data, "Enabled", this.enabled, true, BuilderDescriptorState.Stable, "Whether this step should be enabled on the NPC", null); + this.getBoolean(data, "Enabled", this.enabled, true, BuilderDescriptorState.Stable, "Whether this instruction should be enabled on the NPC", null); this.getObject( data, "Sensor", this.sensorBuilderObjectReferenceHelper, BuilderDescriptorState.Stable, - "Sensor for testing if step can be applied", - "Sensor for testing if step can be applied. If not supplied, will always match", + "Sensor for testing if instruction can be applied", + "Sensor for testing if instruction can be applied. If not supplied, will always match", helper ); features.lock(); @@ -132,7 +132,7 @@ public class BuilderInstructionRandomized extends BuilderInstruction { ) ); this.getBoolean( - data, "Continue", v -> this.continueAfter = v, false, BuilderDescriptorState.WorkInProgress, "Continue after this step was executed", null + data, "Continue", v -> this.continueAfter = v, false, BuilderDescriptorState.WorkInProgress, "Continue after this instruction was executed", null ); this.getDouble( data, @@ -141,7 +141,7 @@ public class BuilderInstructionRandomized extends BuilderInstruction { 1.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, - "Weighted chance of picking this step in a random selector", + "Weighted chance of picking this instruction in a random instruction", null ); this.getBoolean( @@ -150,8 +150,8 @@ public class BuilderInstructionRandomized extends BuilderInstruction { v -> this.treeMode = v, false, BuilderDescriptorState.Stable, - "Whether this step and its contents should be treated like a traditional behaviour tree.", - "Whether this step and its contents should be treated like a traditional behaviour tree, i.e. will continue if all child steps fail" + "Whether this instruction and its contents should be treated like a traditional behaviour tree.", + "Whether this instruction and its contents should be treated like a traditional behaviour tree, i.e. will continue if all child instructions fail" ); this.getBoolean( data, @@ -159,7 +159,7 @@ public class BuilderInstructionRandomized extends BuilderInstruction { this.invertTreeModeResult, false, BuilderDescriptorState.Stable, - "Whether or not to invert the result of TreeMode evaluation when passing up to parent TreeMode steps", + "Whether or not to invert the result of TreeMode evaluation when passing up to parent TreeMode instructions", null ); this.getBoolean(data, "ResetOnStateChange", this.resetOnStateChange, true, BuilderDescriptorState.Stable, "Whether to reset when NPC state changes", null); @@ -170,7 +170,7 @@ public class BuilderInstructionRandomized extends BuilderInstruction { DEFAULT_EXECUTION_RANGE, DoubleSequenceValidator.fromExclToInclWeaklyMonotonic(0.0, Double.MAX_VALUE), BuilderDescriptorState.Stable, - "How long to execute the chosen step before picking another", + "How long to execute the chosen instruction before picking another", null ); this.decreaseDepth(); diff --git a/src/com/hypixel/hytale/server/npc/interactions/SpawnNPCInteraction.java b/src/com/hypixel/hytale/server/npc/interactions/SpawnNPCInteraction.java index 04b6bb1e..a8c651fa 100644 --- a/src/com/hypixel/hytale/server/npc/interactions/SpawnNPCInteraction.java +++ b/src/com/hypixel/hytale/server/npc/interactions/SpawnNPCInteraction.java @@ -3,6 +3,12 @@ package com.hypixel.hytale.server.npc.interactions; import com.hypixel.hytale.codec.Codec; 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.validation.Validators; +import com.hypixel.hytale.common.map.IWeightedElement; +import com.hypixel.hytale.common.map.IWeightedMap; +import com.hypixel.hytale.common.map.WeightedMap; +import com.hypixel.hytale.common.util.ArrayUtil; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; @@ -43,6 +49,13 @@ public class SpawnNPCInteraction extends SimpleBlockInteraction { .documentation("The ID of the entity asset to spawn.") .addValidator(NPCRoleValidator.INSTANCE) .add() + .append( + new KeyedCodec<>("WeightedEntityIds", new ArrayCodec<>(SpawnNPCInteraction.WeightedNPCSpawn.CODEC, SpawnNPCInteraction.WeightedNPCSpawn[]::new)), + (spawnNPCInteraction, o) -> spawnNPCInteraction.weightedSpawns = o, + spawnNPCInteraction -> spawnNPCInteraction.weightedSpawns + ) + .documentation("A weighted list of entity IDs from which an entity will be selected for spawning. Supersedes any provided EntityId.") + .add() .append( new KeyedCodec<>("SpawnOffset", Vector3d.CODEC), (spawnNPCInteraction, s) -> spawnNPCInteraction.spawnOffset.assign(s), @@ -64,8 +77,21 @@ public class SpawnNPCInteraction extends SimpleBlockInteraction { ) .documentation("The chance of the NPC spawning when the interaction is triggered.") .add() + .afterDecode(interaction -> { + if (interaction.weightedSpawns != null && interaction.weightedSpawns.length > 0) { + WeightedMap.Builder mapBuilder = WeightedMap.builder(ArrayUtil.EMPTY_STRING_ARRAY); + + for (SpawnNPCInteraction.WeightedNPCSpawn entry : interaction.weightedSpawns) { + mapBuilder.put(entry.id, entry.weight); + } + + interaction.weightedSpawnMap = mapBuilder.build(); + } + }) .build(); protected String entityId; + protected SpawnNPCInteraction.WeightedNPCSpawn[] weightedSpawns; + protected IWeightedMap weightedSpawnMap; @Nonnull protected Vector3d spawnOffset = new Vector3d(); protected float spawnYawOffset; @@ -74,7 +100,14 @@ public class SpawnNPCInteraction extends SimpleBlockInteraction { private void spawnNPC(@Nonnull Store store, @Nonnull Vector3i targetBlock) { World world = store.getExternalData().getWorld(); SpawnNPCInteraction.SpawnData spawnData = this.computeSpawnData(world, targetBlock); - NPCPlugin.get().spawnNPC(store, this.entityId, null, spawnData.position(), spawnData.rotation()); + String entityToSpawn = this.entityId; + if (this.weightedSpawnMap != null) { + entityToSpawn = this.weightedSpawnMap.get(ThreadLocalRandom.current()); + } + + if (entityToSpawn != null) { + NPCPlugin.get().spawnNPC(store, entityToSpawn, null, spawnData.position(), spawnData.rotation()); + } } @Nonnull @@ -141,4 +174,31 @@ public class SpawnNPCInteraction extends SimpleBlockInteraction { private record SpawnData(@Nonnull Vector3d position, @Nonnull Vector3f rotation) { } + + protected static class WeightedNPCSpawn implements IWeightedElement { + private static final BuilderCodec CODEC = BuilderCodec.builder( + SpawnNPCInteraction.WeightedNPCSpawn.class, SpawnNPCInteraction.WeightedNPCSpawn::new + ) + .append(new KeyedCodec<>("Id", Codec.STRING), (spawn, s) -> spawn.id = s, spawn -> spawn.id) + .documentation("The Role ID of the NPC to spawn.") + .addValidator(Validators.nonNull()) + .addValidator(NPCRoleValidator.INSTANCE) + .add() + .append(new KeyedCodec<>("Weight", Codec.DOUBLE, true), (spawn, d) -> spawn.weight = d, spawn -> spawn.weight) + .documentation("The relative weight of this NPC (chance of being spawned is this value relative to the sum of all weights).") + .addValidator(Validators.nonNull()) + .addValidator(Validators.greaterThan(0.0)) + .add() + .build(); + private String id; + private double weight; + + private WeightedNPCSpawn() { + } + + @Override + public double getWeight() { + return this.weight; + } + } } diff --git a/src/com/hypixel/hytale/server/npc/metadata/CapturedNPCMetadata.java b/src/com/hypixel/hytale/server/npc/metadata/CapturedNPCMetadata.java index 5ebeb812..30ccc2f2 100644 --- a/src/com/hypixel/hytale/server/npc/metadata/CapturedNPCMetadata.java +++ b/src/com/hypixel/hytale/server/npc/metadata/CapturedNPCMetadata.java @@ -11,13 +11,6 @@ public class CapturedNPCMetadata { new KeyedCodec<>("IconPath", Codec.STRING), (meta, s) -> meta.iconPath = s, meta -> meta.iconPath, (meta, parent) -> meta.iconPath = parent.iconPath ) .add() - .appendInherited( - new KeyedCodec<>("RoleIndex", Codec.INTEGER), - (meta, s) -> meta.roleIndex = s, - meta -> meta.roleIndex, - (meta, parent) -> meta.roleIndex = parent.roleIndex - ) - .add() .appendInherited( new KeyedCodec<>("NpcNameKey", Codec.STRING), (meta, s) -> meta.npcNameKey = s, @@ -35,14 +28,9 @@ public class CapturedNPCMetadata { .build(); public static final KeyedCodec KEYED_CODEC = new KeyedCodec<>("CapturedEntity", CODEC); private String iconPath; - private int roleIndex; private String npcNameKey; private String fullItemIcon; - public int getRoleIndex() { - return this.roleIndex; - } - public String getIconPath() { return this.iconPath; } @@ -59,10 +47,6 @@ public class CapturedNPCMetadata { this.iconPath = iconPath; } - public void setRoleIndex(int roleIndex) { - this.roleIndex = roleIndex; - } - public void setNpcNameKey(String npcNameKey) { this.npcNameKey = npcNameKey; } diff --git a/src/com/hypixel/hytale/server/npc/role/Role.java b/src/com/hypixel/hytale/server/npc/role/Role.java index 2f984449..024db349 100644 --- a/src/com/hypixel/hytale/server/npc/role/Role.java +++ b/src/com/hypixel/hytale/server/npc/role/Role.java @@ -209,11 +209,11 @@ public class Role implements IAnnotatedComponentCollection { this.collisionRadius = builder.getCollisionRadius(); this.collisionViewAngle = builder.getCollisionViewAngle(); this.collisionViewHalfAngleCosine = TrigMathUtil.cos(this.collisionViewAngle / 2.0F); - this.separationDistance = builder.getSeparationDistance(); - this.separationWeight = builder.getSeparationWeight(); - this.separationDistanceTarget = builder.getSeparationDistanceTarget(); - this.separationNearRadiusTarget = builder.getSeparationNearRadiusTarget(); - this.separationFarRadiusTarget = builder.getSeparationFarRadiusTarget(); + this.separationDistance = builder.getSeparationDistance(builderSupport); + this.separationWeight = builder.getSeparationWeight(builderSupport); + this.separationDistanceTarget = builder.getSeparationDistanceTarget(builderSupport); + this.separationNearRadiusTarget = builder.getSeparationNearRadiusTarget(builderSupport); + this.separationFarRadiusTarget = builder.getSeparationFarRadiusTarget(builderSupport); this.applySeparation = builder.isApplySeparation(builderSupport); if (builder.isOverridingHeadPitchAngle(builderSupport)) { this.headPitchAngleRange = builder.getHeadPitchAngleRange(builderSupport); diff --git a/src/com/hypixel/hytale/server/npc/role/RoleDebugFlags.java b/src/com/hypixel/hytale/server/npc/role/RoleDebugFlags.java index 49469684..b831ca85 100644 --- a/src/com/hypixel/hytale/server/npc/role/RoleDebugFlags.java +++ b/src/com/hypixel/hytale/server/npc/role/RoleDebugFlags.java @@ -7,8 +7,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public enum RoleDebugFlags implements Supplier { - TraceFail("Trace failed steps"), - TraceSuccess("Trace matched steps"), + TraceFail("Trace failed instructions"), + TraceSuccess("Trace matched instructions"), TraceSensorFailures("Trace failing sensors"), Flock("Trace flock events"), FlockDamage("Trace flock damage events"), diff --git a/src/com/hypixel/hytale/server/npc/role/builders/BuilderRole.java b/src/com/hypixel/hytale/server/npc/role/builders/BuilderRole.java index c41c1d18..7841380e 100644 --- a/src/com/hypixel/hytale/server/npc/role/builders/BuilderRole.java +++ b/src/com/hypixel/hytale/server/npc/role/builders/BuilderRole.java @@ -96,11 +96,11 @@ public class BuilderRole extends SpawnableWithModelBuilder implements Spaw protected double collisionForceFalloff; protected double collisionRadius; protected float collisionViewAngle; - protected double separationDistance; - protected double separationWeight; - protected double separationDistanceTarget; - protected double separationNearRadiusTarget; - protected double separationFarRadiusTarget; + protected final DoubleHolder separationDistance = new DoubleHolder(); + protected final DoubleHolder separationWeight = new DoubleHolder(); + protected final DoubleHolder separationDistanceTarget = new DoubleHolder(); + protected final DoubleHolder separationNearRadiusTarget = new DoubleHolder(); + protected final DoubleHolder separationFarRadiusTarget = new DoubleHolder(); protected final BooleanHolder applySeparation = new BooleanHolder(); protected boolean stayInEnvironment; protected String allowedEnvironments; @@ -426,7 +426,7 @@ public class BuilderRole extends SpawnableWithModelBuilder implements Spaw this.getDouble( data, "SeparationDistance", - d -> this.separationDistance = d, + this.separationDistance, 3.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Experimental, @@ -436,7 +436,7 @@ public class BuilderRole extends SpawnableWithModelBuilder implements Spaw this.getDouble( data, "SeparationWeight", - d -> this.separationWeight = d, + this.separationWeight, 1.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.Experimental, @@ -446,7 +446,7 @@ public class BuilderRole extends SpawnableWithModelBuilder implements Spaw this.getDouble( data, "SeparationDistanceTarget", - d -> this.separationDistanceTarget = d, + this.separationDistanceTarget, 1.0, DoubleSingleValidator.greaterEqual0(), BuilderDescriptorState.Experimental, @@ -456,7 +456,7 @@ public class BuilderRole extends SpawnableWithModelBuilder implements Spaw this.getDouble( data, "SeparationNearRadiusTarget", - d -> this.separationNearRadiusTarget = d, + this.separationNearRadiusTarget, 1.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Experimental, @@ -466,7 +466,7 @@ public class BuilderRole extends SpawnableWithModelBuilder implements Spaw this.getDouble( data, "SeparationFarRadiusTarget", - d -> this.separationFarRadiusTarget = d, + this.separationFarRadiusTarget, 5.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Experimental, @@ -1051,24 +1051,24 @@ public class BuilderRole extends SpawnableWithModelBuilder implements Spaw return this.collisionRadius; } - public double getSeparationDistance() { - return this.separationDistance; + public double getSeparationDistance(BuilderSupport support) { + return this.separationDistance.get(support.getExecutionContext()); } - public double getSeparationWeight() { - return this.separationWeight; + public double getSeparationWeight(BuilderSupport support) { + return this.separationWeight.get(support.getExecutionContext()); } - public double getSeparationDistanceTarget() { - return this.separationDistanceTarget; + public double getSeparationDistanceTarget(BuilderSupport support) { + return this.separationDistanceTarget.get(support.getExecutionContext()); } - public double getSeparationNearRadiusTarget() { - return this.separationNearRadiusTarget; + public double getSeparationNearRadiusTarget(BuilderSupport support) { + return this.separationNearRadiusTarget.get(support.getExecutionContext()); } - public double getSeparationFarRadiusTarget() { - return this.separationFarRadiusTarget; + public double getSeparationFarRadiusTarget(BuilderSupport support) { + return this.separationFarRadiusTarget.get(support.getExecutionContext()); } public boolean isApplySeparation(BuilderSupport support) { diff --git a/src/com/hypixel/hytale/server/npc/systems/NPCSystems.java b/src/com/hypixel/hytale/server/npc/systems/NPCSystems.java index f8cd7f32..5340b55d 100644 --- a/src/com/hypixel/hytale/server/npc/systems/NPCSystems.java +++ b/src/com/hypixel/hytale/server/npc/systems/NPCSystems.java @@ -32,6 +32,7 @@ import com.hypixel.hytale.server.core.modules.entity.component.FromPrefab; import com.hypixel.hytale.server.core.modules.entity.component.FromWorldGen; import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; import com.hypixel.hytale.server.core.modules.entity.component.MovementAudioComponent; +import com.hypixel.hytale.server.core.modules.entity.component.NPCMarkerComponent; import com.hypixel.hytale.server.core.modules.entity.component.NewSpawnComponent; import com.hypixel.hytale.server.core.modules.entity.component.PositionDataComponent; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; @@ -239,6 +240,7 @@ public class NPCSystems { npcComponent.initBlockChangeBlackboardView(ref, commandBuffer); role.loaded(); commandBuffer.ensureComponent(ref, PrefabCopyableComponent.getComponentType()); + commandBuffer.ensureComponent(ref, NPCMarkerComponent.getComponentType()); commandBuffer.ensureComponent(ref, PositionDataComponent.getComponentType()); commandBuffer.ensureComponent(ref, MovementAudioComponent.getComponentType()); if (reason == AddReason.SPAWN) { diff --git a/src/com/hypixel/hytale/server/spawning/SpawningPlugin.java b/src/com/hypixel/hytale/server/spawning/SpawningPlugin.java index d8154ada..d9351f40 100644 --- a/src/com/hypixel/hytale/server/spawning/SpawningPlugin.java +++ b/src/com/hypixel/hytale/server/spawning/SpawningPlugin.java @@ -566,13 +566,13 @@ public class SpawningPlugin extends JavaPlugin { return this.localSpawnControllerJoinDelay; } - public static void validateSpawnsConfigurations(String type, @Nonnull Map spawns, @Nonnull List errors) { + public static void validateSpawnsConfigurations(@Nonnull String type, @Nonnull Map spawns, @Nonnull List errors) { for (Entry spawn : spawns.entrySet()) { - RoleSpawnParameters[] npcs = spawn.getValue().getNPCs(); + RoleSpawnParameters[] spawnParameters = spawn.getValue().getNPCs(); - for (RoleSpawnParameters npc : npcs) { + for (RoleSpawnParameters spawnParameter : spawnParameters) { try { - NPCPlugin.get().validateSpawnableRole(npc.getId()); + NPCPlugin.get().validateSpawnableRole(spawnParameter.getId()); } catch (IllegalArgumentException var11) { errors.add(type + " " + spawn.getKey() + ": " + var11.getMessage()); } @@ -582,17 +582,21 @@ public class SpawningPlugin extends JavaPlugin { public static void validateSpawnMarkers(@Nonnull Map markers, @Nonnull List errors) { for (Entry marker : markers.entrySet()) { - IWeightedMap npcs = marker.getValue().getWeightedConfigurations(); - npcs.forEach(config -> { - try { - String npc = config.getNpc(); - if (npc != null) { - NPCPlugin.get().validateSpawnableRole(npc); + IWeightedMap configs = marker.getValue().getWeightedConfigurations(); + if (configs == null) { + errors.add("Spawn marker " + marker.getKey() + ": No configurations defined"); + } else { + configs.forEach(config -> { + try { + String npcConfig = config.getNpc(); + if (npcConfig != null) { + NPCPlugin.get().validateSpawnableRole(npcConfig); + } + } catch (IllegalArgumentException var4x) { + errors.add("Spawn marker " + marker.getKey() + ": " + var4x.getMessage()); } - } catch (IllegalArgumentException var4x) { - errors.add("Spawn marker " + marker.getKey() + ": " + var4x.getMessage()); - } - }); + }); + } } } @@ -643,8 +647,8 @@ public class SpawningPlugin extends JavaPlugin { (name, world) -> world.execute( () -> world.getEntityStore().getStore().forEachChunk(SpawnMarkerEntity.getComponentType(), (archetypeChunk, commandBuffer) -> { for (int index = 0; index < archetypeChunk.size(); index++) { - SpawnMarkerEntity spawnMarkerEntity = archetypeChunk.getComponent(index, SpawnMarkerEntity.getComponentType()); - if (removedAssets.contains(spawnMarkerEntity.getSpawnMarkerId())) { + SpawnMarkerEntity spawnMarkerEntityComponent = archetypeChunk.getComponent(index, SpawnMarkerEntity.getComponentType()); + if (spawnMarkerEntityComponent != null && removedAssets.contains(spawnMarkerEntityComponent.getSpawnMarkerId())) { commandBuffer.removeEntity(archetypeChunk.getReferenceTo(index), RemoveReason.REMOVE); } } @@ -908,7 +912,11 @@ public class SpawningPlugin extends JavaPlugin { @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - Map unknownComponents = holder.getComponent(this.unknownComponentsComponentType).getUnknownComponents(); + UnknownComponents unknownComponent = holder.getComponent(this.unknownComponentsComponentType); + + assert unknownComponent != null; + + Map unknownComponents = unknownComponent.getUnknownComponents(); BsonDocument spawnSuppressor = unknownComponents.remove("SpawnSuppressor"); if (spawnSuppressor != null) { Archetype archetype = holder.getArchetype(); @@ -947,6 +955,7 @@ public class SpawningPlugin extends JavaPlugin { } public static class NPCSpawningConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SpawningPlugin.NPCSpawningConfig.class, SpawningPlugin.NPCSpawningConfig::new ) diff --git a/src/com/hypixel/hytale/server/spawning/assets/spawnmarker/config/SpawnMarker.java b/src/com/hypixel/hytale/server/spawning/assets/spawnmarker/config/SpawnMarker.java index b9e22b64..cf6458bb 100644 --- a/src/com/hypixel/hytale/server/spawning/assets/spawnmarker/config/SpawnMarker.java +++ b/src/com/hypixel/hytale/server/spawning/assets/spawnmarker/config/SpawnMarker.java @@ -108,30 +108,36 @@ public class SpawnMarker implements JsonAssetWithMap { boolean isRealtime = asset.isRealtimeRespawn(); IWeightedMap configs = asset.getWeightedConfigurations(); - configs.forEach( - config -> { - if (isRealtime && config.getRealtimeRespawnTime() <= 0.0) { - results.fail( - String.format("Value for RealtimeRespawn in %s:%s must be greater than zero if using realtime spawning", asset.getId(), config.getNpc()) - ); - } else if (!isRealtime && config.getSpawnAfterGameTime() == null) { - results.fail( - String.format("Value for SpawnAfterGameTime in %s:%s must be provided if using game time spawning", asset.getId(), config.getNpc()) - ); - } else { - if (config.getSpawnAfterGameTime() != null && config.getRealtimeRespawnTime() > 0.0) { - results.warn( + if (configs != null && configs.size() != 0) { + configs.forEach( + config -> { + if (isRealtime && config.getRealtimeRespawnTime() <= 0.0) { + results.fail( String.format( - "%s:%s defines both RealtimeRespawn and SpawnAfterGameTime despite being set to %s spawning", - asset.getId(), - config.getNpc(), - isRealtime ? "realtime" : "game time" + "Value for RealtimeRespawn in %s:%s must be greater than zero if using realtime spawning", asset.getId(), config.getNpc() ) ); + } else if (!isRealtime && config.getSpawnAfterGameTime() == null) { + results.fail( + String.format("Value for SpawnAfterGameTime in %s:%s must be provided if using game time spawning", asset.getId(), config.getNpc()) + ); + } else { + if (config.getSpawnAfterGameTime() != null && config.getRealtimeRespawnTime() > 0.0) { + results.warn( + String.format( + "%s:%s defines both RealtimeRespawn and SpawnAfterGameTime despite being set to %s spawning", + asset.getId(), + config.getNpc(), + isRealtime ? "realtime" : "game time" + ) + ); + } } } - } - ); + ); + } else { + results.fail(String.format("Spawn marker %s must define at least one NPC configuration to spawn", asset.getId())); + } } ) .build(); @@ -140,6 +146,7 @@ public class SpawnMarker implements JsonAssetWithMap weightedConfigurations; protected double exclusionRadius; protected double maxDropHeightSquared = 4.0; @@ -163,6 +170,7 @@ public class SpawnMarker implements JsonAssetWithMap getWeightedConfigurations() { return this.weightedConfigurations; } diff --git a/src/com/hypixel/hytale/server/spawning/beacons/SpawnBeaconSystems.java b/src/com/hypixel/hytale/server/spawning/beacons/SpawnBeaconSystems.java index 4a225995..ad259952 100644 --- a/src/com/hypixel/hytale/server/spawning/beacons/SpawnBeaconSystems.java +++ b/src/com/hypixel/hytale/server/spawning/beacons/SpawnBeaconSystems.java @@ -235,22 +235,24 @@ public class SpawnBeaconSystems { NPCEntity spawnedEntityNpcComponent = commandBuffer.getComponent(spawnedEntityReference, this.npcComponentType); if (spawnedEntityNpcComponent != null && !spawnedEntityNpcComponent.isDespawning()) { Role role = spawnedEntityNpcComponent.getRole(); - boolean hasTarget = role.getMarkedEntitySupport() - .hasMarkedEntityInSlot(legacySpawnBeaconComponent.getSpawnWrapper().getSpawn().getTargetSlot()); - TransformComponent spawnedEntityTransformComponent = commandBuffer.getComponent(spawnedEntityReference, this.transformComponentType); + if (role != null) { + boolean hasTarget = role.getMarkedEntitySupport() + .hasMarkedEntityInSlot(legacySpawnBeaconComponent.getSpawnWrapper().getSpawn().getTargetSlot()); + TransformComponent spawnedEntityTransformComponent = commandBuffer.getComponent(spawnedEntityReference, this.transformComponentType); - assert spawnedEntityTransformComponent != null; + assert spawnedEntityTransformComponent != null; - Vector3d npcPosition = spawnedEntityTransformComponent.getPosition(); - double beaconDistance = npcPosition.distanceSquaredTo(position); - if ((despawnNPCsIfIdle && !hasTarget || beaconDistance > beaconRadiusSquared) && !role.getStateSupport().isInBusyState()) { - double timeout = entityTimeoutCounter.mergeDouble(spawnedEntityReference, (double)dt, Double::sum); - if (timeout >= despawnNPCAfterTimeout) { - spawnedEntityNpcComponent.setToDespawn(); + Vector3d npcPosition = spawnedEntityTransformComponent.getPosition(); + double beaconDistance = npcPosition.distanceSquaredTo(position); + if ((despawnNPCsIfIdle && !hasTarget || beaconDistance > beaconRadiusSquared) && !role.getStateSupport().isInBusyState()) { + double timeout = entityTimeoutCounter.mergeDouble(spawnedEntityReference, (double)dt, Double::sum); + if (timeout >= despawnNPCAfterTimeout) { + spawnedEntityNpcComponent.setToDespawn(); + } + } else { + entityTimeoutCounter.put(spawnedEntityReference, 0.0); + validatedEntityList.add(spawnedEntityNpcComponent); } - } else { - entityTimeoutCounter.put(spawnedEntityReference, 0.0); - validatedEntityList.add(spawnedEntityNpcComponent); } } } @@ -330,13 +332,15 @@ public class SpawnBeaconSystems { for (int ixx = 0; ixx < validatedEntityList.size(); ixx++) { NPCEntity npc = validatedEntityList.get(ixx); - Ref lockedTargetRef = npc.getRole() - .getMarkedEntitySupport() - .getMarkedEntityRef(legacySpawnBeaconComponent.getSpawnWrapper().getSpawn().getTargetSlot()); - if (lockedTargetRef != null) { - UUIDComponent lockedTarget = commandBuffer.getComponent(lockedTargetRef, this.uuidComponentType); - if (lockedTarget != null) { - entitiesPerPlayer.mergeInt(lockedTarget.getUuid(), 1, Integer::sum); + Role role = npc.getRole(); + if (role != null) { + Ref lockedTargetRef = role.getMarkedEntitySupport() + .getMarkedEntityRef(legacySpawnBeaconComponent.getSpawnWrapper().getSpawn().getTargetSlot()); + if (lockedTargetRef != null) { + UUIDComponent lockedTargetUuidComponent = commandBuffer.getComponent(lockedTargetRef, this.uuidComponentType); + if (lockedTargetUuidComponent != null) { + entitiesPerPlayer.mergeInt(lockedTargetUuidComponent.getUuid(), 1, Integer::sum); + } } } } @@ -353,12 +357,12 @@ public class SpawnBeaconSystems { } } - private static boolean isReadyToRespawn(LegacySpawnBeaconEntity spawnBeacon, WorldTimeResource timeManager) { + private static boolean isReadyToRespawn(@Nonnull LegacySpawnBeaconEntity spawnBeacon, @Nonnull WorldTimeResource worldTimeResource) { Instant nextSpawnAfter = spawnBeacon.getNextSpawnAfter(); if (nextSpawnAfter == null) { return true; } else { - Instant now = spawnBeacon.isNextSpawnAfterRealtime() ? Instant.now() : timeManager.getGameTime(); + Instant now = spawnBeacon.isNextSpawnAfterRealtime() ? Instant.now() : worldTimeResource.getGameTime(); return now.isAfter(nextSpawnAfter); } } diff --git a/src/com/hypixel/hytale/server/spawning/commands/SpawnMarkersCommand.java b/src/com/hypixel/hytale/server/spawning/commands/SpawnMarkersCommand.java index 6d2821bf..53b6da53 100644 --- a/src/com/hypixel/hytale/server/spawning/commands/SpawnMarkersCommand.java +++ b/src/com/hypixel/hytale/server/spawning/commands/SpawnMarkersCommand.java @@ -88,7 +88,7 @@ public class SpawnMarkersCommand extends AbstractCommandCollection { if (spawnMarkerRef != null && spawnMarkerRef.isValid()) { context.sendMessage(Message.translation("server.commands.spawning.markers.add.added").param("markerId", marker.getId())); } else { - context.sendMessage(Message.translation("server.commands.markers.add.failed").param("markerId", marker.getId())); + context.sendMessage(Message.translation("server.commands.spawning.markers.add.failed").param("markerId", marker.getId())); } } } diff --git a/src/com/hypixel/hytale/server/spawning/controllers/BeaconSpawnController.java b/src/com/hypixel/hytale/server/spawning/controllers/BeaconSpawnController.java index 2b8928f8..add4859b 100644 --- a/src/com/hypixel/hytale/server/spawning/controllers/BeaconSpawnController.java +++ b/src/com/hypixel/hytale/server/spawning/controllers/BeaconSpawnController.java @@ -69,33 +69,36 @@ public class BeaconSpawnController extends SpawnController { @Nullable public NPCBeaconSpawnJob createRandomSpawnJob(@Nonnull ComponentAccessor componentAccessor) { LegacySpawnBeaconEntity legacySpawnBeaconComponent = componentAccessor.getComponent(this.ownerRef, LegacySpawnBeaconEntity.getComponentType()); - - assert legacySpawnBeaconComponent != null; - - BeaconSpawnWrapper wrapper = legacySpawnBeaconComponent.getSpawnWrapper(); - RoleSpawnParameters spawn = wrapper.pickRole(ThreadLocalRandom.current()); - if (spawn == null) { + if (legacySpawnBeaconComponent == null) { return null; } else { - String spawnId = spawn.getId(); - int roleIndex = NPCPlugin.get().getIndex(spawnId); - if (roleIndex >= 0 && !this.unspawnableRoles.contains(roleIndex)) { - NPCBeaconSpawnJob job = null; - int predictedTotal = this.spawnedEntities.size() + this.activeJobs.size(); - if (this.activeJobs.size() < this.getMaxActiveJobs() - && this.nextPlayerIndex < this.playersInRegion.size() - && predictedTotal < this.currentScaledMaxTotalSpawns) { - job = this.idleJobs.isEmpty() ? new NPCBeaconSpawnJob() : this.idleJobs.pop(); - job.beginProbing(this.playersInRegion.get(this.nextPlayerIndex++), this.currentScaledMaxConcurrentSpawns, roleIndex, spawn.getFlockDefinition()); - this.activeJobs.add(job); - if (this.nextPlayerIndex >= this.playersInRegion.size()) { - this.nextPlayerIndex = 0; - } - } - - return job; - } else { + BeaconSpawnWrapper wrapper = legacySpawnBeaconComponent.getSpawnWrapper(); + RoleSpawnParameters spawn = wrapper.pickRole(ThreadLocalRandom.current()); + if (spawn == null) { return null; + } else { + String spawnId = spawn.getId(); + int roleIndex = NPCPlugin.get().getIndex(spawnId); + if (roleIndex >= 0 && !this.unspawnableRoles.contains(roleIndex)) { + NPCBeaconSpawnJob job = null; + int predictedTotal = this.spawnedEntities.size() + this.activeJobs.size(); + if (this.activeJobs.size() < this.getMaxActiveJobs() + && this.nextPlayerIndex < this.playersInRegion.size() + && predictedTotal < this.currentScaledMaxTotalSpawns) { + job = this.idleJobs.isEmpty() ? new NPCBeaconSpawnJob() : this.idleJobs.pop(); + job.beginProbing( + this.playersInRegion.get(this.nextPlayerIndex++), this.currentScaledMaxConcurrentSpawns, roleIndex, spawn.getFlockDefinition() + ); + this.activeJobs.add(job); + if (this.nextPlayerIndex >= this.playersInRegion.size()) { + this.nextPlayerIndex = 0; + } + } + + return job; + } else { + return null; + } } } } @@ -134,6 +137,7 @@ public class BeaconSpawnController extends SpawnController { this.roundStart = roundStart; } + @Nonnull public Ref getOwnerRef() { return this.ownerRef; } diff --git a/src/com/hypixel/hytale/server/spawning/spawnmarkers/SpawnMarkerEntity.java b/src/com/hypixel/hytale/server/spawning/spawnmarkers/SpawnMarkerEntity.java index 89fe6543..e21c60dd 100644 --- a/src/com/hypixel/hytale/server/spawning/spawnmarkers/SpawnMarkerEntity.java +++ b/src/com/hypixel/hytale/server/spawning/spawnmarkers/SpawnMarkerEntity.java @@ -4,6 +4,7 @@ import com.hypixel.hytale.codec.Codec; 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.common.map.IWeightedMap; import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; @@ -111,7 +112,7 @@ public class SpawnMarkerEntity implements Component { @Nullable private Set suppressedBy; private int failedSpawns; - @Nonnull + @Nullable private final SpawningContext context; private final Vector3d spawnPosition = new Vector3d(); private InvalidatablePersistentRef[] npcReferences; @@ -128,7 +129,11 @@ public class SpawnMarkerEntity implements Component { } public SpawnMarkerEntity() { - this.context = new SpawningContext(); + this(new SpawningContext()); + } + + private SpawnMarkerEntity(@Nullable SpawningContext context) { + this.context = context; this.npcReferences = EMPTY_REFERENCES; } @@ -241,160 +246,169 @@ public class SpawnMarkerEntity implements Component { } public boolean spawnNPC(@Nonnull Ref ref, @Nonnull SpawnMarker marker, @Nonnull Store store) { - SpawnMarker.SpawnConfiguration spawn = marker.getWeightedConfigurations().get(ThreadLocalRandom.current()); - if (spawn == null) { - SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s has no spawn configuration to spawn", ref); + IWeightedMap configs = marker.getWeightedConfigurations(); + if (configs == null) { + SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s has no spawn configurations to spawn", ref); this.refreshTimeout(); return false; } else { - boolean realtime = marker.isRealtimeRespawn(); - if (realtime) { - this.respawnCounter = spawn.getRealtimeRespawnTime(); + SpawnMarker.SpawnConfiguration spawn = configs.get(ThreadLocalRandom.current()); + if (spawn == null) { + SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s has no spawn configuration to spawn", ref); + this.refreshTimeout(); + return false; } else { - this.spawnAfter = null; - this.gameTimeRespawn = spawn.getSpawnAfterGameTime(); - } - - UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType()); - - assert uuidComponent != null; - - UUID uuid = uuidComponent.getUuid(); - String roleName = spawn.getNpc(); - if (roleName != null && !roleName.isEmpty()) { - NPCPlugin npcModule = NPCPlugin.get(); - int roleIndex = npcModule.getIndex(roleName); - TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); - - assert transformComponent != null; - - Vector3d position = transformComponent.getPosition(); - BuilderInfo builderInfo = npcModule.getRoleBuilderInfo(roleIndex); - if (builderInfo == null) { - SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s attempted to spawn non-existent NPC role '%s'", uuid, roleName); - this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.NONEXISTENT_ROLE); - return false; + boolean realtime = marker.isRealtimeRespawn(); + if (realtime) { + this.respawnCounter = spawn.getRealtimeRespawnTime(); } else { - Builder role = builderInfo.isValid() ? builderInfo.getBuilder() : null; - if (role == null) { - SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s attempted to spawn invalid NPC role '%s'", uuid, roleName); - this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.INVALID_ROLE); - return false; - } else if (!role.isSpawnable()) { - SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s attempted to spawn a non-spawnable (abstract) role '%s'", uuid, roleName); - this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.INVALID_ROLE); - return false; - } else if (!this.context.setSpawnable((ISpawnableWithModel)role)) { - SpawningPlugin.get() - .getLogger() - .at(Level.SEVERE) - .log("Marker %s failed to spawn NPC role '%s' due to failed role validation", uuid, roleName); - this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.FAILED_ROLE_VALIDATION); + this.spawnAfter = null; + this.gameTimeRespawn = spawn.getSpawnAfterGameTime(); + } + + UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType()); + + assert uuidComponent != null; + + UUID uuid = uuidComponent.getUuid(); + String roleName = spawn.getNpc(); + if (roleName != null && !roleName.isEmpty()) { + NPCPlugin npcModule = NPCPlugin.get(); + int roleIndex = npcModule.getIndex(roleName); + TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); + + assert transformComponent != null; + + Vector3d position = transformComponent.getPosition(); + BuilderInfo builderInfo = npcModule.getRoleBuilderInfo(roleIndex); + if (builderInfo == null) { + SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s attempted to spawn non-existent NPC role '%s'", uuid, roleName); + this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.NONEXISTENT_ROLE); return false; } else { - ObjectList> results = SpatialResource.getThreadLocalReferenceList(); - SpatialResource, EntityStore> spatialResource = store.getResource(EntityModule.get().getPlayerSpatialResourceType()); - spatialResource.getSpatialStructure().collect(position, marker.getExclusionRadius(), results); - boolean hasPlayersInRange = !results.isEmpty(); - if (hasPlayersInRange) { - this.refreshTimeout(); + Builder role = builderInfo.isValid() ? builderInfo.getBuilder() : null; + if (role == null) { + SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s attempted to spawn invalid NPC role '%s'", uuid, roleName); + this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.INVALID_ROLE); + return false; + } else if (!role.isSpawnable()) { + SpawningPlugin.get().getLogger().at(Level.SEVERE).log("Marker %s attempted to spawn a non-spawnable (abstract) role '%s'", uuid, roleName); + this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.INVALID_ROLE); + return false; + } else if (!this.context.setSpawnable((ISpawnableWithModel)role)) { + SpawningPlugin.get() + .getLogger() + .at(Level.SEVERE) + .log("Marker %s failed to spawn NPC role '%s' due to failed role validation", uuid, roleName); + this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.FAILED_ROLE_VALIDATION); return false; } else { - World world = store.getExternalData().getWorld(); - if (!this.context.set(world, position.x, position.y, position.z)) { - SpawningPlugin.get() - .getLogger() - .at(Level.FINE) - .log("Marker %s attempted to spawn NPC '%s' at %s but could not fit", uuid, roleName, position); - this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.NO_ROOM); + ObjectList> results = SpatialResource.getThreadLocalReferenceList(); + SpatialResource, EntityStore> spatialResource = store.getResource(EntityModule.get().getPlayerSpatialResourceType()); + spatialResource.getSpatialStructure().collect(position, marker.getExclusionRadius(), results); + boolean hasPlayersInRange = !results.isEmpty(); + if (hasPlayersInRange) { + this.refreshTimeout(); return false; } else { - SpawnTestResult testResult = this.context.canSpawn(true, false); - if (testResult != SpawnTestResult.TEST_OK) { + World world = store.getExternalData().getWorld(); + if (!this.context.set(world, position.x, position.y, position.z)) { SpawningPlugin.get() .getLogger() .at(Level.FINE) - .log("Marker %s attempted to spawn NPC '%s' at %s but could not fit: %s", uuid, roleName, position, testResult); + .log("Marker %s attempted to spawn NPC '%s' at %s but could not fit", uuid, roleName, position); this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.NO_ROOM); return false; } else { - this.spawnPosition.assign(this.context.xSpawn, this.context.ySpawn, this.context.zSpawn); - if (this.spawnPosition.distanceSquaredTo(position) > marker.getMaxDropHeightSquared()) { + SpawnTestResult testResult = this.context.canSpawn(true, false); + if (testResult != SpawnTestResult.TEST_OK) { SpawningPlugin.get() .getLogger() .at(Level.FINE) - .log("Marker %s attempted to spawn NPC '%s' but was offset too far from the ground at %s", uuid, roleName, position); - this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.TOO_HIGH); + .log("Marker %s attempted to spawn NPC '%s' at %s but could not fit: %s", uuid, roleName, position, testResult); + this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.NO_ROOM); return false; } else { - TriConsumer, Store> postSpawn = (_entity, _ref, _store) -> { - SpawnMarkerReference spawnMarkerReference = _store.ensureAndGetComponent(_ref, SpawnMarkerReference.getComponentType()); - spawnMarkerReference.getReference().setEntity(ref, _store); - spawnMarkerReference.refreshTimeoutCounter(); - WorldGenId worldGenIdComponent = _store.getComponent(ref, WorldGenId.getComponentType()); - int worldGenId = worldGenIdComponent != null ? worldGenIdComponent.getWorldGenId() : 0; - _store.putComponent(_ref, WorldGenId.getComponentType(), new WorldGenId(worldGenId)); - }; - Vector3f rotation = transformComponent.getRotation(); - Pair, NPCEntity> npcPair = npcModule.spawnEntity(store, roleIndex, this.spawnPosition, rotation, null, postSpawn); - if (npcPair == null) { - SpawningPlugin.get() - .getLogger() - .at(Level.SEVERE) - .log("Marker %s failed to spawn NPC role '%s' due to an internal error", uuid, roleName); - this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.INVALID_ROLE); - return false; - } else { - Ref npcRef = npcPair.first(); - NPCEntity npcComponent = npcPair.second(); - Ref flockReference = FlockPlugin.trySpawnFlock( - npcRef, npcComponent, store, roleIndex, this.spawnPosition, rotation, spawn.getFlockDefinition(), postSpawn - ); - EntityGroup group = flockReference == null ? null : store.getComponent(flockReference, EntityGroup.getComponentType()); - this.spawnCount = group != null ? group.size() : 1; - if (this.storedFlock != null) { - this.despawnStarted = false; - this.npcReferences = new InvalidatablePersistentRef[this.spawnCount]; - if (group != null) { - group.forEachMember((index, member, referenceArray) -> { - InvalidatablePersistentRef referencex = new InvalidatablePersistentRef(); - referencex.setEntity(member, store); - referenceArray[index] = referencex; - }, this.npcReferences); - } else { - InvalidatablePersistentRef reference = new InvalidatablePersistentRef(); - reference.setEntity(npcRef, store); - this.npcReferences[0] = reference; - } - - this.storedFlock.clear(); - } - + this.spawnPosition.assign(this.context.xSpawn, this.context.ySpawn, this.context.zSpawn); + if (this.spawnPosition.distanceSquaredTo(position) > marker.getMaxDropHeightSquared()) { SpawningPlugin.get() .getLogger() .at(Level.FINE) - .log( - "Marker %s spawned %s and set respawn to %s", - uuid, - npcComponent.getRoleName(), - realtime ? this.respawnCounter : this.gameTimeRespawn + .log("Marker %s attempted to spawn NPC '%s' but was offset too far from the ground at %s", uuid, roleName, position); + this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.TOO_HIGH); + return false; + } else { + TriConsumer, Store> postSpawn = (_entity, _ref, _store) -> { + SpawnMarkerReference spawnMarkerReference = _store.ensureAndGetComponent(_ref, SpawnMarkerReference.getComponentType()); + spawnMarkerReference.getReference().setEntity(ref, _store); + spawnMarkerReference.refreshTimeoutCounter(); + WorldGenId worldGenIdComponent = _store.getComponent(ref, WorldGenId.getComponentType()); + int worldGenId = worldGenIdComponent != null ? worldGenIdComponent.getWorldGenId() : 0; + _store.putComponent(_ref, WorldGenId.getComponentType(), new WorldGenId(worldGenId)); + }; + Vector3f rotation = transformComponent.getRotation(); + Pair, NPCEntity> npcPair = npcModule.spawnEntity( + store, roleIndex, this.spawnPosition, rotation, null, postSpawn + ); + if (npcPair == null) { + SpawningPlugin.get() + .getLogger() + .at(Level.SEVERE) + .log("Marker %s failed to spawn NPC role '%s' due to an internal error", uuid, roleName); + this.fail(ref, uuid, roleName, position, store, SpawnMarkerEntity.FailReason.INVALID_ROLE); + return false; + } else { + Ref npcRef = npcPair.first(); + NPCEntity npcComponent = npcPair.second(); + Ref flockReference = FlockPlugin.trySpawnFlock( + npcRef, npcComponent, store, roleIndex, this.spawnPosition, rotation, spawn.getFlockDefinition(), postSpawn ); - this.refreshTimeout(); - return true; + EntityGroup group = flockReference == null ? null : store.getComponent(flockReference, EntityGroup.getComponentType()); + this.spawnCount = group != null ? group.size() : 1; + if (this.storedFlock != null) { + this.despawnStarted = false; + this.npcReferences = new InvalidatablePersistentRef[this.spawnCount]; + if (group != null) { + group.forEachMember((index, member, referenceArray) -> { + InvalidatablePersistentRef referencex = new InvalidatablePersistentRef(); + referencex.setEntity(member, store); + referenceArray[index] = referencex; + }, this.npcReferences); + } else { + InvalidatablePersistentRef reference = new InvalidatablePersistentRef(); + reference.setEntity(npcRef, store); + this.npcReferences[0] = reference; + } + + this.storedFlock.clear(); + } + + SpawningPlugin.get() + .getLogger() + .at(Level.FINE) + .log( + "Marker %s spawned %s and set respawn to %s", + uuid, + npcComponent.getRoleName(), + realtime ? this.respawnCounter : this.gameTimeRespawn + ); + this.refreshTimeout(); + return true; + } } } } } } } + } else { + SpawningPlugin.get() + .getLogger() + .at(Level.FINE) + .log("Marker %s performed noop spawn and set repawn to %s", uuid, realtime ? this.respawnCounter : this.gameTimeRespawn); + this.refreshTimeout(); + return true; } - } else { - SpawningPlugin.get() - .getLogger() - .at(Level.FINE) - .log("Marker %s performed noop spawn and set repawn to %s", uuid, realtime ? this.respawnCounter : this.gameTimeRespawn); - this.refreshTimeout(); - return true; } } } @@ -487,6 +501,21 @@ public class SpawnMarkerEntity implements Component { return spawnMarker; } + @Nullable + @Override + public Component cloneSerializable() { + SpawnMarkerEntity spawnMarker = new SpawnMarkerEntity(null); + spawnMarker.spawnMarkerId = this.spawnMarkerId; + spawnMarker.respawnCounter = this.respawnCounter; + spawnMarker.spawnCount = this.spawnCount; + spawnMarker.gameTimeRespawn = this.gameTimeRespawn; + spawnMarker.spawnAfter = this.spawnAfter; + spawnMarker.npcReferences = this.npcReferences; + spawnMarker.storedFlock = this.storedFlock != null ? this.storedFlock.cloneSerializable() : null; + spawnMarker.spawnPosition.assign(this.spawnPosition); + return spawnMarker; + } + @Nonnull @Override public String toString() { diff --git a/src/com/hypixel/hytale/server/spawning/world/system/WorldSpawnJobSystems.java b/src/com/hypixel/hytale/server/spawning/world/system/WorldSpawnJobSystems.java index c166e316..29081016 100644 --- a/src/com/hypixel/hytale/server/spawning/world/system/WorldSpawnJobSystems.java +++ b/src/com/hypixel/hytale/server/spawning/world/system/WorldSpawnJobSystems.java @@ -162,10 +162,10 @@ public class WorldSpawnJobSystems { spawnJobData.incrementSpansTried(); spansTested++; if (!spawnJobData.getSpawnConfig().withinLightRange(spawningContext)) { - rejectSpan(spawnJobData.getRejectionMap(), SpawnRejection.OUTSIDE_LIGHT_RANGE); + rejectSpawn(spawnJobData.getRejectionMap(), SpawnRejection.OUTSIDE_LIGHT_RANGE); } else if (!canSpawnOnBlock(spawnBlockSet, spawnFluidTag, spawningContext)) { spansBlocked++; - rejectSpan(spawnJobData.getRejectionMap(), SpawnRejection.INVALID_SPAWN_BLOCK); + rejectSpawn(spawnJobData.getRejectionMap(), SpawnRejection.INVALID_SPAWN_BLOCK); } else { SpawnTestResult spawnTestResult = spawningContext.canSpawn(); if (spawnTestResult == SpawnTestResult.TEST_OK) { @@ -173,16 +173,16 @@ public class WorldSpawnJobSystems { } if (spawnTestResult == SpawnTestResult.FAIL_INVALID_POSITION) { - rejectSpan(spawnJobData.getRejectionMap(), SpawnRejection.INVALID_POSITION); + rejectSpawn(spawnJobData.getRejectionMap(), SpawnRejection.INVALID_POSITION); spansBlocked++; } else if (spawnTestResult == SpawnTestResult.FAIL_NO_POSITION) { - rejectSpan(spawnJobData.getRejectionMap(), SpawnRejection.NO_POSITION); + rejectSpawn(spawnJobData.getRejectionMap(), SpawnRejection.NO_POSITION); spansBlocked++; } else if (spawnTestResult == SpawnTestResult.FAIL_NOT_BREATHABLE) { - rejectSpan(spawnJobData.getRejectionMap(), SpawnRejection.NOT_BREATHABLE); + rejectSpawn(spawnJobData.getRejectionMap(), SpawnRejection.NOT_BREATHABLE); spansBlocked++; } else { - rejectSpan(spawnJobData.getRejectionMap(), SpawnRejection.OTHER); + rejectSpawn(spawnJobData.getRejectionMap(), SpawnRejection.OTHER); } } } @@ -254,6 +254,15 @@ public class WorldSpawnJobSystems { (_npc, _holder, _store) -> preAddToWorld(_npc, _holder, roleIndex, spawnJobData), null ); + if (npcPair == null) { + LOGGER.at(Level.SEVERE) + .log( + "Spawn job %s: Failed to create %s: The spawned entity returned null", Integer.valueOf(spawnJobData.getJobId()), npcModule.getName(roleIndex) + ); + rejectSpawn(spawnJobData.getRejectionMap(), SpawnRejection.OTHER); + return endProbing(WorldSpawnJobSystems.Result.FAILED, spawnJobData, worldChunk, worldSpawnData); + } + NPCEntity npcComponent = npcPair.right(); Ref npcRef = npcPair.left(); FlockPlugin.trySpawnFlock( @@ -272,7 +281,7 @@ public class WorldSpawnJobSystems { LOGGER.at(Level.SEVERE) .withCause(var12) .log("Spawn job %s: Failed to create %s: %s", spawnJobData.getJobId(), npcModule.getName(roleIndex), var12.getMessage()); - rejectSpan(spawnJobData.getRejectionMap(), SpawnRejection.OTHER); + rejectSpawn(spawnJobData.getRejectionMap(), SpawnRejection.OTHER); return endProbing(WorldSpawnJobSystems.Result.FAILED, spawnJobData, worldChunk, worldSpawnData); } @@ -314,7 +323,7 @@ public class WorldSpawnJobSystems { } } - private static void rejectSpan(@Nonnull Object2IntMap rejectionMap, SpawnRejection rejection) { + private static void rejectSpawn(@Nonnull Object2IntMap rejectionMap, @Nonnull SpawnRejection rejection) { rejectionMap.mergeInt(rejection, 1, Integer::sum); } diff --git a/src/com/hypixel/hytale/server/worldgen/ChunkGeneratorResource.java b/src/com/hypixel/hytale/server/worldgen/ChunkGeneratorResource.java index ee66e1e7..f9a2b4d7 100644 --- a/src/com/hypixel/hytale/server/worldgen/ChunkGeneratorResource.java +++ b/src/com/hypixel/hytale/server/worldgen/ChunkGeneratorResource.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.server.worldgen.chunk.ChunkGenerator; import com.hypixel.hytale.server.worldgen.chunk.ZoneBiomeResult; import com.hypixel.hytale.server.worldgen.chunk.populator.PrefabPopulator; import com.hypixel.hytale.server.worldgen.climate.ClimateNoise; +import com.hypixel.hytale.server.worldgen.loader.WorldGenPrefabLoader; import com.hypixel.hytale.server.worldgen.loader.WorldGenPrefabSupplier; import com.hypixel.hytale.server.worldgen.prefab.PrefabPasteUtil; import com.hypixel.hytale.server.worldgen.util.cache.TimeoutCache; @@ -50,6 +51,7 @@ public class ChunkGeneratorResource { public final ZoneBiomeResult zoneBiomeResult; public final ClimateNoise.Buffer climateBuffer = new ClimateNoise.Buffer(); public final PrefabPopulator prefabPopulator = new PrefabPopulator(); + public final WorldGenPrefabLoader.PrefabPathCollector prefabCollector = new WorldGenPrefabLoader.PrefabPathCollector(); @Nonnull public final Vector2d cacheVector2d; protected ChunkGenerator chunkGenerator; diff --git a/src/com/hypixel/hytale/server/worldgen/HytaleWorldGenProvider.java b/src/com/hypixel/hytale/server/worldgen/HytaleWorldGenProvider.java index 87e9ce73..9b0b612a 100644 --- a/src/com/hypixel/hytale/server/worldgen/HytaleWorldGenProvider.java +++ b/src/com/hypixel/hytale/server/worldgen/HytaleWorldGenProvider.java @@ -1,8 +1,11 @@ package com.hypixel.hytale.server.worldgen; +import com.hypixel.hytale.builtin.worldgen.WorldGenPlugin; import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.ExtraInfo; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.common.semver.Semver; import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.procedurallib.json.SeedString; import com.hypixel.hytale.server.core.universe.Universe; @@ -14,19 +17,30 @@ import com.hypixel.hytale.server.worldgen.prefab.PrefabStoreRoot; import java.nio.file.Files; import java.nio.file.Path; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class HytaleWorldGenProvider implements IWorldGenProvider { public static final String ID = "Hytale"; - public static final BuilderCodec CODEC = BuilderCodec.builder(HytaleWorldGenProvider.class, HytaleWorldGenProvider::new) - .documentation("The standard generator for Hytale.") - .append(new KeyedCodec<>("Name", Codec.STRING), (config, s) -> config.name = s, config -> config.name) - .documentation("The name of the generator to use. \"*Default*\" if not provided.") - .add() - .append(new KeyedCodec<>("Path", Codec.STRING), (config, s) -> config.path = s, config -> config.path) - .documentation("The path to the world generation configuration. \n\nDefaults to the server provided world generation folder if not set.") - .add() - .build(); + public static final String DEFAULT_NAME = "Default"; + public static final Semver MIN_VERSION = new Semver(0L, 0L, 0L); + public static final BuilderCodec CODEC = new HytaleWorldGenProvider.DefaultBuilderCodec( + BuilderCodec.builder(HytaleWorldGenProvider.class, HytaleWorldGenProvider::new) + .documentation("The standard generator for Hytale.") + .append(new KeyedCodec<>("Name", Codec.STRING), (config, s) -> config.name = s, config -> config.name) + .documentation("The name of the generator to use. \"*Default*\" if not provided.") + .add() + .append(new KeyedCodec<>("Version", Semver.CODEC), (config, v) -> config.version = v, config -> config.version) + .documentation("The version of the generator to use. \"0.0.0\" if not provided.") + .add() + .append(new KeyedCodec<>("Path", Codec.STRING), (config, s) -> config.path = s, config -> config.path) + .documentation("The path to the world generation configuration. \n\nDefaults to the server provided world generation folder if not set.") + .add() + ); + @Nonnull private String name = "Default"; + @Nonnull + private Semver version = MIN_VERSION; + @Nullable private String path; @Nonnull @@ -44,16 +58,28 @@ public class HytaleWorldGenProvider implements IWorldGenProvider { } try { - return new ChunkGeneratorJsonLoader(new SeedString<>("ChunkGenerator", new SeedStringResource(PrefabStoreRoot.DEFAULT, worldGenPath)), worldGenPath) - .load(); + WorldGenConfig config = new WorldGenConfig(worldGenPath, this.name, this.version); + return new ChunkGeneratorJsonLoader(new SeedString<>("ChunkGenerator", new SeedStringResource(PrefabStoreRoot.DEFAULT, config)), config).load(); } catch (Error var3) { throw new WorldGenLoadException("Failed to load world gen!", var3); } } - @Nonnull @Override public String toString() { - return "HytaleWorldGenProvider{name='" + this.name + "', path='" + this.path + "'}"; + return "HytaleWorldGenProvider{name='" + this.name + "', version=" + this.version + ", path='" + this.path + "'}"; + } + + private static class DefaultBuilderCodec extends BuilderCodec { + protected DefaultBuilderCodec(@Nonnull BuilderCodec.BuilderBase builder) { + super(builder); + } + + public HytaleWorldGenProvider getDefaultValue(ExtraInfo extraInfo) { + HytaleWorldGenProvider value = new HytaleWorldGenProvider(); + value.version = WorldGenPlugin.get().getLatestVersion("Default", HytaleWorldGenProvider.MIN_VERSION); + this.afterDecode(value, extraInfo); + return value; + } } } diff --git a/src/com/hypixel/hytale/server/worldgen/SeedStringResource.java b/src/com/hypixel/hytale/server/worldgen/SeedStringResource.java index 29cb35ab..47f565e9 100644 --- a/src/com/hypixel/hytale/server/worldgen/SeedStringResource.java +++ b/src/com/hypixel/hytale/server/worldgen/SeedStringResource.java @@ -10,7 +10,6 @@ import com.hypixel.hytale.server.worldgen.loader.util.FileMaskCache; import com.hypixel.hytale.server.worldgen.prefab.PrefabStoreRoot; import com.hypixel.hytale.server.worldgen.util.LogUtil; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import java.nio.file.Path; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; @@ -22,15 +21,15 @@ public class SeedStringResource implements SeedResource { @Nonnull protected final BlockPlacementMaskRegistry blockMaskRegistry; @Nonnull - protected Path dataFolder; + protected WorldGenConfig config; @Nonnull protected WorldGenPrefabLoader loader; @Nonnull protected final Map uniqueIds; - public SeedStringResource(@Nonnull PrefabStoreRoot prefabStore, @Nonnull Path dataFolder) { - this.dataFolder = dataFolder; - this.loader = new WorldGenPrefabLoader(prefabStore, dataFolder); + public SeedStringResource(@Nonnull PrefabStoreRoot prefabStore, @Nonnull WorldGenConfig config) { + this.config = config; + this.loader = new WorldGenPrefabLoader(prefabStore, config); this.biomeMaskRegistry = new FileMaskCache<>(); this.blockMaskRegistry = new BlockPlacementMaskRegistry(); this.uniqueIds = new Object2ObjectOpenHashMap<>(); @@ -41,22 +40,16 @@ public class SeedStringResource implements SeedResource { return prefix + this.uniqueIds.computeIfAbsent(prefix, k -> new AtomicInteger(0)).getAndIncrement(); } + @Nonnull public WorldGenPrefabLoader getLoader() { return this.loader; } - public void setPrefabStore(@Nonnull PrefabStoreRoot prefabStore) { - if (prefabStore != this.loader.getStore()) { - LogUtil.getLogger().at(Level.INFO).log("Set prefab-store to: %s", prefabStore.name()); - this.loader = new WorldGenPrefabLoader(prefabStore, this.dataFolder); - } - } - - public void setDataFolder(@Nonnull Path dataFolder) { - if (!dataFolder.equals(this.dataFolder)) { - LogUtil.getLogger().at(Level.INFO).log("Set data-folder to: %s", dataFolder); - this.dataFolder = dataFolder; - this.loader = new WorldGenPrefabLoader(this.loader.getStore(), dataFolder); + public void setPrefabConfig(@Nonnull WorldGenConfig config, @Nonnull PrefabStoreRoot prefabStore) { + if (config != this.config || prefabStore != this.loader.getStore()) { + LogUtil.getLogger().at(Level.INFO).log("Set prefab-loader config: path=%s, store=%s", config.path(), prefabStore.name()); + this.config = config; + this.loader = new WorldGenPrefabLoader(prefabStore, config); } } diff --git a/src/com/hypixel/hytale/server/worldgen/WorldGenConfig.java b/src/com/hypixel/hytale/server/worldgen/WorldGenConfig.java new file mode 100644 index 00000000..56cbe901 --- /dev/null +++ b/src/com/hypixel/hytale/server/worldgen/WorldGenConfig.java @@ -0,0 +1,12 @@ +package com.hypixel.hytale.server.worldgen; + +import com.hypixel.hytale.common.semver.Semver; +import com.hypixel.hytale.procedurallib.file.FileIO; +import java.nio.file.Path; +import javax.annotation.Nonnull; + +public record WorldGenConfig(@Nonnull Path path, @Nonnull String name, @Nonnull Semver version) { + public WorldGenConfig withOverride(@Nonnull Path path) { + return FileIO.equals(this.path, path) ? this : new WorldGenConfig(path, this.name, this.version); + } +} diff --git a/src/com/hypixel/hytale/server/worldgen/loader/AssetFileSystem.java b/src/com/hypixel/hytale/server/worldgen/loader/AssetFileSystem.java new file mode 100644 index 00000000..61e2c223 --- /dev/null +++ b/src/com/hypixel/hytale/server/worldgen/loader/AssetFileSystem.java @@ -0,0 +1,122 @@ +package com.hypixel.hytale.server.worldgen.loader; + +import com.hypixel.hytale.assetstore.AssetPack; +import com.hypixel.hytale.builtin.worldgen.FeatureFlags; +import com.hypixel.hytale.builtin.worldgen.WorldGenPlugin; +import com.hypixel.hytale.procedurallib.file.AssetLoader; +import com.hypixel.hytale.procedurallib.file.AssetPath; +import com.hypixel.hytale.procedurallib.file.FileIO; +import com.hypixel.hytale.procedurallib.file.FileIOSystem; +import com.hypixel.hytale.server.core.asset.AssetModule; +import com.hypixel.hytale.server.worldgen.WorldGenConfig; +import it.unimi.dsi.fastutil.Hash.Strategy; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.function.Predicate; +import javax.annotation.Nonnull; + +public class AssetFileSystem implements FileIOSystem { + private static final Strategy PATH_STRATEGY = new Strategy() { + public int hashCode(Path o) { + return FileIO.hashCode(o); + } + + public boolean equals(Path a, Path b) { + return FileIO.equals(a, b); + } + }; + private final Path root; + private final FileIOSystem.PathArray packRoots; + private final Object2ObjectMap files = new Object2ObjectOpenCustomHashMap<>(PATH_STRATEGY); + private final Object2ObjectMap> resources = new Object2ObjectOpenHashMap<>(); + + public AssetFileSystem(@Nonnull WorldGenConfig config) { + Path root = AssetModule.get().getBaseAssetPack().getRoot(); + Path assetPath = FileIO.relativize(config.path(), root); + this.root = root; + this.packRoots = new FileIOSystem.PathArray(getAssetRoots(config, packRoot -> FileIO.exists(packRoot, assetPath))); + } + + @Nonnull + @Override + public Path baseRoot() { + return this.root; + } + + @Nonnull + @Override + public FileIOSystem.PathArray roots() { + return this.packRoots; + } + + @Nonnull + @Override + public AssetPath resolve(@Nonnull Path path) { + Path relPath = FileIO.relativize(path, this.root); + AssetPath assetPath = this.files.get(relPath); + if (assetPath == null) { + assetPath = FileIOSystem.super.resolve(path); + this.files.put(relPath, assetPath); + } + + return assetPath; + } + + @Nonnull + @Override + public T load(@Nonnull AssetPath path, @Nonnull AssetLoader loader) throws IOException { + AssetFileSystem.Resource resource = this.resources.get(path); + if (resource == null) { + T value = FileIOSystem.super.load(path, loader); + resource = new AssetFileSystem.Resource<>(value, loader.type()); + this.resources.put(path, resource); + } else if (resource.type() != loader.type()) { + throw new IllegalStateException("Resource type mismatch: expected " + loader.type() + " but found " + resource.type); + } + + return loader.type().cast(resource.value); + } + + @Override + public void close() { + this.files.clear(); + this.resources.clear(); + FileIO.closeFileIOSystem(this); + } + + public static Path[] getAssetRoots(@Nonnull WorldGenConfig config, @Nonnull Predicate filter) { + AssetModule assets = AssetModule.get(); + List packs = assets.getAssetPacks(); + ObjectArrayList roots = new ObjectArrayList<>(packs.size()); + Path versionsDir = WorldGenPlugin.getVersionsPath(); + + for (int i = packs.size() - 1; i >= 1; i--) { + AssetPack pack = packs.get(i); + if (!FileIO.startsWith(pack.getRoot(), versionsDir) && filter.test(pack.getRoot())) { + roots.add(packs.get(i).getRoot()); + } + } + + if (FeatureFlags.VERSION_OVERRIDES) { + for (int ix = packs.size() - 1; ix >= 1; ix--) { + AssetPack pack = packs.get(ix); + if (FileIO.startsWith(pack.getRoot(), versionsDir) + && pack.getManifest().getVersion().compareTo(config.version()) <= 0 + && filter.test(pack.getRoot())) { + roots.add(packs.get(ix).getRoot()); + } + } + } + + roots.add(packs.getFirst().getRoot()); + return roots.toArray(Path[]::new); + } + + public record Resource(@Nonnull T value, @Nonnull Class type) { + } +} diff --git a/src/com/hypixel/hytale/server/worldgen/loader/ChunkGeneratorJsonLoader.java b/src/com/hypixel/hytale/server/worldgen/loader/ChunkGeneratorJsonLoader.java index 1723cde2..2f54a052 100644 --- a/src/com/hypixel/hytale/server/worldgen/loader/ChunkGeneratorJsonLoader.java +++ b/src/com/hypixel/hytale/server/worldgen/loader/ChunkGeneratorJsonLoader.java @@ -3,16 +3,18 @@ package com.hypixel.hytale.server.worldgen.loader; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; import com.hypixel.hytale.common.map.IWeightedMap; import com.hypixel.hytale.common.map.WeightedMap; import com.hypixel.hytale.common.util.ArrayUtil; import com.hypixel.hytale.math.util.FastRandom; import com.hypixel.hytale.math.vector.Vector2i; +import com.hypixel.hytale.procedurallib.file.FileIO; +import com.hypixel.hytale.procedurallib.file.FileIOSystem; +import com.hypixel.hytale.procedurallib.json.JsonLoader; import com.hypixel.hytale.procedurallib.json.Loader; import com.hypixel.hytale.procedurallib.json.SeedString; import com.hypixel.hytale.server.worldgen.SeedStringResource; +import com.hypixel.hytale.server.worldgen.WorldGenConfig; import com.hypixel.hytale.server.worldgen.chunk.ChunkGenerator; import com.hypixel.hytale.server.worldgen.chunk.MaskProvider; import com.hypixel.hytale.server.worldgen.loader.climate.ClimateMaskJsonLoader; @@ -26,8 +28,12 @@ import java.nio.file.Path; import javax.annotation.Nonnull; public class ChunkGeneratorJsonLoader extends Loader { - public ChunkGeneratorJsonLoader(SeedString seed, Path dataFolder) { - super(seed, dataFolder); + @Nonnull + private final WorldGenConfig config; + + public ChunkGeneratorJsonLoader(@Nonnull SeedString seed, @Nonnull WorldGenConfig config) { + super(seed, config.path()); + this.config = config; } @Nonnull @@ -39,18 +45,24 @@ public class ChunkGeneratorJsonLoader extends Loader { + public static final AssetLoader IMAGE_LOADER = new AssetLoader() { + @Override + public Class type() { + return BufferedImage.class; + } + + @Nonnull + public BufferedImage load(@Nonnull InputStream in) throws IOException { + return ImageIO.read(new BufferedInputStream(in)); + } + }; protected final Path file; protected final Vector2i zoomSize; protected final Vector2i worldOffset; @@ -42,7 +56,7 @@ public class MaskProviderJsonLoader extends JsonLoader cache; - public WorldGenPrefabLoader(@Nonnull PrefabStoreRoot store, @Nonnull Path dataFolder) { - Path storePath = PrefabStoreRoot.resolvePrefabStore(store, dataFolder); + public WorldGenPrefabLoader(@Nonnull PrefabStoreRoot store, @Nonnull WorldGenConfig config) { + Path storePath = PrefabStoreRoot.resolvePrefabStore(store, config.path()); + this.root = storePath; this.store = store; - this.prefabLoader = new PrefabLoader(storePath); - this.cache = new TimeoutCache<>(30L, TimeUnit.SECONDS, SneakyThrow.sneakyFunction(key -> { - List suppliers = new ArrayList<>(); - this.resolve(key, path -> suppliers.add(new WorldGenPrefabSupplier(this, key, path))); - return suppliers.toArray(WorldGenPrefabSupplier[]::new); - }), null); + this.prefabLoaders = getPrefabLoaders(config, storePath); + this.cache = new TimeoutCache<>(30L, TimeUnit.SECONDS, SneakyThrow.sneakyFunction(this::compute), null); } @Nonnull @@ -39,15 +44,78 @@ public class WorldGenPrefabLoader { } public Path getRootFolder() { - return this.prefabLoader.getRootFolder(); + return this.root; } @Nullable - public WorldGenPrefabSupplier[] get(String prefabName) { + public WorldGenPrefabSupplier[] get(@Nonnull String prefabName) { return this.cache.get(prefabName); } - private void resolve(@Nonnull String prefabName, @Nonnull Consumer consumer) throws IOException { - this.prefabLoader.resolvePrefabs(prefabName, consumer); + private WorldGenPrefabSupplier[] compute(@Nonnull String key) throws IOException { + WorldGenPrefabSupplier[] var9; + try (WorldGenPrefabLoader.PrefabPathCollector collector = ChunkGenerator.getResource().prefabCollector) { + collector.key = key; + collector.loader = this; + + for (PrefabLoader loader : this.prefabLoaders) { + collector.root = loader.getRootFolder(); + loader.resolvePrefabs(key, collector); + } + + if (collector.list.isEmpty()) { + throw new Error("Failed to find prefab: " + key); + } + + var9 = collector.result(); + } + + return var9; + } + + private static PrefabLoader[] getPrefabLoaders(@Nonnull WorldGenConfig config, @Nonnull Path prefabStorePath) { + AssetModule assets = AssetModule.get(); + Path root = assets.getBaseAssetPack().getRoot(); + Path assetPath = FileIO.relativize(prefabStorePath, root); + Path[] roots = AssetFileSystem.getAssetRoots(config, packRoot -> FileIO.exists(packRoot, assetPath)); + PrefabLoader[] loaders = new PrefabLoader[roots.length]; + + for (int i = 0; i < roots.length; i++) { + loaders[i] = new PrefabLoader(FileIO.append(roots[i], assetPath)); + } + + return loaders; + } + + public static class PrefabPathCollector implements Consumer, AutoCloseable { + private final ObjectSet visited = new ObjectOpenCustomHashSet<>(FileIO.PATH_STRATEGY); + private final ObjectList list = new ObjectArrayList<>(); + @Nullable + private transient String key = null; + @Nullable + private transient Path root = null; + @Nullable + private transient WorldGenPrefabLoader loader = null; + + public void accept(@Nonnull Path path) { + if (this.key != null && this.loader != null && this.root != null) { + Path assetPath = FileIO.relativize(path, this.root); + if (this.visited.add(assetPath)) { + this.list.add(new WorldGenPrefabSupplier(this.loader, this.key, path)); + } + } + } + + @Override + public void close() { + this.visited.clear(); + this.list.clear(); + this.key = null; + this.loader = null; + } + + public WorldGenPrefabSupplier[] result() { + return this.list.toArray(WorldGenPrefabSupplier[]::new); + } } } diff --git a/src/com/hypixel/hytale/server/worldgen/loader/ZonesJsonLoader.java b/src/com/hypixel/hytale/server/worldgen/loader/ZonesJsonLoader.java index 4869e9b3..27374a9a 100644 --- a/src/com/hypixel/hytale/server/worldgen/loader/ZonesJsonLoader.java +++ b/src/com/hypixel/hytale/server/worldgen/loader/ZonesJsonLoader.java @@ -1,8 +1,8 @@ package com.hypixel.hytale.server.worldgen.loader; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; +import com.google.gson.JsonObject; +import com.hypixel.hytale.procedurallib.file.FileIO; +import com.hypixel.hytale.procedurallib.json.JsonLoader; import com.hypixel.hytale.procedurallib.json.Loader; import com.hypixel.hytale.procedurallib.json.SeedString; import com.hypixel.hytale.server.worldgen.SeedStringResource; @@ -11,7 +11,6 @@ import com.hypixel.hytale.server.worldgen.loader.context.FileLoadingContext; import com.hypixel.hytale.server.worldgen.loader.context.ZoneFileContext; import com.hypixel.hytale.server.worldgen.loader.zone.ZoneJsonLoader; import com.hypixel.hytale.server.worldgen.zone.Zone; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Map.Entry; import javax.annotation.Nonnull; @@ -33,12 +32,12 @@ public class ZonesJsonLoader extends Loader { for (Entry zoneEntry : zoneRegistry) { ZoneFileContext zoneContext = zoneEntry.getValue(); - try (JsonReader reader = new JsonReader(Files.newBufferedReader(zoneContext.getPath().resolve("Zone.json")))) { - JsonElement zoneJson = JsonParser.parseReader(reader); + try { + JsonObject zoneJson = FileIO.load(zoneContext.getPath().resolve("Zone.json"), JsonLoader.JSON_OBJ_LOADER); Zone zone = new ZoneJsonLoader(this.seed, this.dataFolder, zoneJson, zoneContext).load(); zones[index++] = zone; - } catch (Throwable var12) { - throw new Error(String.format("Error while loading zone \"%s\" for world generator from file.", zoneContext.getPath().toString()), var12); + } catch (Throwable var9) { + throw new Error(String.format("Error while loading zone \"%s\" for world generator from file.", zoneContext.getPath().toString()), var9); } } diff --git a/src/com/hypixel/hytale/server/worldgen/loader/cave/CaveGeneratorJsonLoader.java b/src/com/hypixel/hytale/server/worldgen/loader/cave/CaveGeneratorJsonLoader.java index 2b8791e8..053cc895 100644 --- a/src/com/hypixel/hytale/server/worldgen/loader/cave/CaveGeneratorJsonLoader.java +++ b/src/com/hypixel/hytale/server/worldgen/loader/cave/CaveGeneratorJsonLoader.java @@ -2,15 +2,14 @@ package com.hypixel.hytale.server.worldgen.loader.cave; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; +import com.hypixel.hytale.procedurallib.file.AssetPath; +import com.hypixel.hytale.procedurallib.file.FileIO; import com.hypixel.hytale.procedurallib.json.JsonLoader; import com.hypixel.hytale.procedurallib.json.SeedString; import com.hypixel.hytale.server.worldgen.SeedStringResource; import com.hypixel.hytale.server.worldgen.cave.CaveGenerator; import com.hypixel.hytale.server.worldgen.cave.CaveType; import com.hypixel.hytale.server.worldgen.loader.context.ZoneFileContext; -import java.nio.file.Files; import java.nio.file.Path; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -28,18 +27,17 @@ public class CaveGeneratorJsonLoader extends JsonLoader extends JsonLoader { } @Nonnull - public static BiomeFileContext.Type getBiomeType(@Nonnull Path path) { - String name = path.getFileName().toString(); + public static BiomeFileContext.Type getBiomeType(@Nonnull AssetPath path) { + String name = path.getFileName(); for (BiomeFileContext.Type type : BiomeFileContext.Type.values()) { if (name.startsWith(type.prefix) && name.endsWith(type.suffix)) { diff --git a/src/com/hypixel/hytale/server/worldgen/loader/context/FileContextLoader.java b/src/com/hypixel/hytale/server/worldgen/loader/context/FileContextLoader.java index 145464e1..76dddba9 100644 --- a/src/com/hypixel/hytale/server/worldgen/loader/context/FileContextLoader.java +++ b/src/com/hypixel/hytale/server/worldgen/loader/context/FileContextLoader.java @@ -1,26 +1,28 @@ package com.hypixel.hytale.server.worldgen.loader.context; -import com.google.gson.JsonParser; +import com.google.gson.JsonObject; import com.hypixel.hytale.logger.HytaleLogger; +import com.hypixel.hytale.procedurallib.file.AssetPath; +import com.hypixel.hytale.procedurallib.file.FileIO; +import com.hypixel.hytale.procedurallib.json.JsonLoader; import com.hypixel.hytale.server.worldgen.prefab.PrefabCategory; -import com.hypixel.hytale.server.worldgen.util.LogUtil; -import java.io.BufferedReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; import java.util.Comparator; +import java.util.List; import java.util.Set; -import java.util.function.BiPredicate; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; import java.util.logging.Level; -import java.util.stream.Stream; import javax.annotation.Nonnull; public class FileContextLoader { - private static final Comparator ZONES_ORDER = Comparator.comparing(Path::getFileName); - private static final Comparator BIOME_ORDER = Comparator.comparing(BiomeFileContext::getBiomeType).thenComparing(Path::getFileName); - private static final BiPredicate ZONE_FILTER = (path, attributes) -> Files.isDirectory(path); - private static final BiPredicate BIOME_FILTER = (path, attributes) -> isValidBiomeFile(path); + private static final Comparator ZONES_ORDER = AssetPath.COMPARATOR; + private static final Comparator BIOME_ORDER = Comparator.comparing(BiomeFileContext::getBiomeType).thenComparing(AssetPath.COMPARATOR); + private static final UnaryOperator DISABLED_FILE = FileContextLoader::getDisabledFilePath; + private static final Predicate ZONE_FILE_MATCHER = FileContextLoader::isValidZoneFile; + private static final Predicate BIOME_FILE_MATCHER = FileContextLoader::isValidBiomeFile; private final Path dataFolder; private final Set zoneRequirement; @@ -34,24 +36,25 @@ public class FileContextLoader { FileLoadingContext context = new FileLoadingContext(this.dataFolder); Path zonesFolder = this.dataFolder.resolve("Zones"); - try (Stream stream = Files.find(zonesFolder, 1, ZONE_FILTER)) { - stream.sorted(ZONES_ORDER).forEach(path -> { - String zoneName = path.getFileName().toString(); - if (zoneName.startsWith("!")) { - LogUtil.getLogger().at(Level.INFO).log("Zone \"%s\" is disabled. Remove \"!\" from folder name to enable it.", zoneName); - } else if (this.zoneRequirement.contains(zoneName)) { - ZoneFileContext zone = loadZoneContext(zoneName, path, context); + try { + List files = FileIO.list(zonesFolder, ZONE_FILE_MATCHER, DISABLED_FILE); + files.sort(ZONES_ORDER); + + for (AssetPath path : files) { + String zoneName = path.getFileName(); + if (this.zoneRequirement.contains(zoneName)) { + ZoneFileContext zone = loadZoneContext(zoneName, path.filepath(), context); context.getZones().register(zoneName, zone); } - }); + } } catch (IOException var9) { HytaleLogger.getLogger().at(Level.SEVERE).withCause(var9).log("Failed to load zones"); } try { validateZones(context, this.zoneRequirement); - } catch (Error var6) { - throw new Error("Failed to validate zones!", var6); + } catch (Error var8) { + throw new Error("Failed to validate zones!", var8); } loadPrefabCategories(this.dataFolder, context); @@ -59,14 +62,13 @@ public class FileContextLoader { } protected static void loadPrefabCategories(@Nonnull Path folder, @Nonnull FileLoadingContext context) { - Path path = folder.resolve("PrefabCategories.json"); - if (Files.exists(path)) { + AssetPath path = FileIO.resolve(folder.resolve("PrefabCategories.json")); + if (FileIO.exists(path)) { try { - try (BufferedReader reader = Files.newBufferedReader(path)) { - PrefabCategory.parse(JsonParser.parseReader(reader), context.getPrefabCategories()::register); - } - } catch (IOException var8) { - throw new Error("Failed to open Categories.json", var8); + JsonObject json = FileIO.load(path, JsonLoader.JSON_OBJ_LOADER); + PrefabCategory.parse(json, context.getPrefabCategories()::register); + } catch (IOException var4) { + throw new Error("Failed to open Categories.json", var4); } } } @@ -74,36 +76,38 @@ public class FileContextLoader { @Nonnull protected static ZoneFileContext loadZoneContext(String name, @Nonnull Path folder, @Nonnull FileLoadingContext context) { try { - ZoneFileContext var5; - try (Stream stream = Files.find(folder, 1, BIOME_FILTER)) { - ZoneFileContext zone = context.createZone(name, folder); - stream.sorted(BIOME_ORDER).forEach(path -> { - BiomeFileContext.Type type = BiomeFileContext.getBiomeType(path); - String biomeName = parseName(path, type); - BiomeFileContext biome = zone.createBiome(biomeName, path, type); - zone.getBiomes(type).register(biomeName, biome); - }); - var5 = zone; + ZoneFileContext zone = context.createZone(name, folder); + List files = FileIO.list(folder, BIOME_FILE_MATCHER, DISABLED_FILE); + files.sort(BIOME_ORDER); + + for (AssetPath path : files) { + BiomeFileContext.Type type = BiomeFileContext.getBiomeType(path); + String biomeName = parseName(path, type); + BiomeFileContext biome = zone.createBiome(biomeName, path.filepath(), type); + zone.getBiomes(type).register(biomeName, biome); } - return var5; - } catch (IOException var8) { - throw new Error(String.format("Failed to list files in: %s", folder), var8); + return zone; + } catch (IOException var10) { + throw new Error(String.format("Failed to list files in: %s", folder), var10); } } - protected static int compareBiomePaths(@Nonnull Path a, @Nonnull Path b) { - BiomeFileContext.Type typeA = BiomeFileContext.getBiomeType(a); - BiomeFileContext.Type typeB = BiomeFileContext.getBiomeType(b); - int result = typeA.compareTo(typeB); - return result != 0 ? result : a.getFileName().compareTo(b.getFileName()); + @Nonnull + protected static AssetPath getDisabledFilePath(@Nonnull AssetPath path) { + String filename = path.getFileName(); + return filename.startsWith("!") ? path.rename(filename.substring(1)) : path; } - protected static boolean isValidBiomeFile(@Nonnull Path path) { - if (Files.isDirectory(path)) { + protected static boolean isValidZoneFile(@Nonnull AssetPath path) { + return Files.isDirectory(path.filepath()) && Files.exists(path.filepath().resolve("Zone.json")); + } + + protected static boolean isValidBiomeFile(@Nonnull AssetPath path) { + if (Files.isDirectory(path.filepath())) { return false; } else { - String filename = path.getFileName().toString(); + String filename = path.getFileName(); for (BiomeFileContext.Type type : BiomeFileContext.Type.values()) { if (filename.endsWith(type.getSuffix()) && filename.startsWith(type.getPrefix())) { @@ -122,8 +126,8 @@ public class FileContextLoader { } @Nonnull - private static String parseName(@Nonnull Path path, @Nonnull BiomeFileContext.Type type) { - String filename = path.getFileName().toString(); + private static String parseName(@Nonnull AssetPath path, @Nonnull BiomeFileContext.Type type) { + String filename = path.getFileName(); int start = type.getPrefix().length(); int end = filename.length() - type.getSuffix().length(); return filename.substring(start, end); @@ -132,7 +136,7 @@ public class FileContextLoader { public interface Constants { int ZONE_SEARCH_DEPTH = 1; int BIOME_SEARCH_DEPTH = 1; - String IDENTIFIER_DISABLE_ZONE = "!"; + String IDENTIFIER_DISABLE = "!"; String INFO_ZONE_IS_DISABLED = "Zone \"%s\" is disabled. Remove \"!\" from folder name to enable it."; String ERROR_LIST_FILES = "Failed to list files in: %s"; String ERROR_ZONE_VALIDATION = "Failed to validate zones!"; diff --git a/src/com/hypixel/hytale/server/worldgen/loader/zone/ZoneBiomesJsonLoader.java b/src/com/hypixel/hytale/server/worldgen/loader/zone/ZoneBiomesJsonLoader.java index a095f482..eec14aeb 100644 --- a/src/com/hypixel/hytale/server/worldgen/loader/zone/ZoneBiomesJsonLoader.java +++ b/src/com/hypixel/hytale/server/worldgen/loader/zone/ZoneBiomesJsonLoader.java @@ -1,10 +1,9 @@ package com.hypixel.hytale.server.worldgen.loader.zone; import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; import com.hypixel.hytale.common.map.IWeightedMap; import com.hypixel.hytale.common.map.WeightedMap; +import com.hypixel.hytale.procedurallib.file.FileIO; import com.hypixel.hytale.procedurallib.json.JsonLoader; import com.hypixel.hytale.procedurallib.json.SeedString; import com.hypixel.hytale.server.worldgen.SeedStringResource; @@ -12,7 +11,6 @@ import com.hypixel.hytale.server.worldgen.biome.TileBiome; import com.hypixel.hytale.server.worldgen.loader.biome.TileBiomeJsonLoader; import com.hypixel.hytale.server.worldgen.loader.context.BiomeFileContext; import com.hypixel.hytale.server.worldgen.loader.context.ZoneFileContext; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Map.Entry; import javax.annotation.Nonnull; @@ -43,15 +41,10 @@ public class ZoneBiomesJsonLoader extends JsonLoader biomeEntry : this.zoneContext.getCustomBiomes()) { BiomeFileContext biomeContext = biomeEntry.getValue(); - try (JsonReader reader = new JsonReader(Files.newBufferedReader(biomeContext.getPath()))) { - JsonElement biomeJson = JsonParser.parseReader(reader); + try { + JsonElement biomeJson = FileIO.load(biomeContext.getPath(), JsonLoader.JSON_OBJ_LOADER); CustomBiome biome = new CustomBiomeJsonLoader(this.seed, this.dataFolder, biomeJson, biomeContext, this.tileBiomes).load(); CustomBiomeGenerator reference = biome.getCustomBiomeGenerator(); if (reference == null) { @@ -49,9 +47,9 @@ public class ZoneCustomBiomesJsonLoader extends JsonLoader