diff --git a/build.gradle.kts b/build.gradle.kts index b38a1545..7f6485b3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ repositories { dependencies { if (Os.isFamily(Os.FAMILY_WINDOWS)) { - implementation(files("${System.getenv("APPDATA")}/Hytale/install/release/package/game/latest/Server/HytaleServer.jar")) + implementation(files("${System.getenv("APPDATA")}/Hytale/install/pre-release/package/game/latest/Server/HytaleServer.jar")) } } diff --git a/src/com/hypixel/hytale/LateMain.java b/src/com/hypixel/hytale/LateMain.java index d2e60391..087a7462 100644 --- a/src/com/hypixel/hytale/LateMain.java +++ b/src/com/hypixel/hytale/LateMain.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.logger.sentry.SkipSentryException; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.HytaleServerConfig; import com.hypixel.hytale.server.core.Options; +import com.hypixel.hytale.server.core.console.ConsoleModule; import io.sentry.Sentry; import java.util.Map.Entry; import java.util.logging.Level; @@ -16,6 +17,7 @@ public class LateMain { try { if (!Options.parse(args)) { HytaleLogger.init(); + ConsoleModule.initializeTerminal(); HytaleFileHandler.INSTANCE.enable(); HytaleLogger.replaceStd(); HytaleLoggerBackend.LOG_LEVEL_LOADER = name -> { diff --git a/src/com/hypixel/hytale/builtin/adventure/camera/CameraPlugin.java b/src/com/hypixel/hytale/builtin/adventure/camera/CameraPlugin.java index a922b754..f5523935 100644 --- a/src/com/hypixel/hytale/builtin/adventure/camera/CameraPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/camera/CameraPlugin.java @@ -10,16 +10,21 @@ import com.hypixel.hytale.builtin.adventure.camera.asset.viewbobbing.ViewBobbing import com.hypixel.hytale.builtin.adventure.camera.command.CameraEffectCommand; import com.hypixel.hytale.builtin.adventure.camera.interaction.CameraShakeInteraction; import com.hypixel.hytale.builtin.adventure.camera.system.CameraEffectSystem; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.protocol.MovementType; import com.hypixel.hytale.server.core.asset.HytaleAssetStore; import com.hypixel.hytale.server.core.asset.type.camera.CameraEffect; +import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap; 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.PlayerRef; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class CameraPlugin extends JavaPlugin { + @Nonnull private static final String CODEC_CAMERA_SHAKE = "CameraShake"; public CameraPlugin(@Nonnull JavaPluginInit init) { @@ -54,6 +59,8 @@ public class CameraPlugin extends JavaPlugin { .build() ); this.getCommandRegistry().registerCommand(new CameraEffectCommand()); - this.getEntityStoreRegistry().registerSystem(new CameraEffectSystem()); + ComponentType playerRefComponentType = PlayerRef.getComponentType(); + ComponentType entityStatMapComponentType = EntityStatMap.getComponentType(); + this.getEntityStoreRegistry().registerSystem(new CameraEffectSystem(playerRefComponentType, entityStatMapComponentType)); } } 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> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Map assets) { return toCachedPacket(UpdateType.Init, assetMap, assets); } @Nonnull - protected Packet generateUpdatePacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Map loadedAssets) { + protected ToClientPacket generateUpdatePacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Map loadedAssets) { return toCachedPacket(UpdateType.AddOrUpdate, assetMap, loadedAssets); } @Nonnull - protected Packet generateRemovePacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Set removed) { + protected ToClientPacket generateRemovePacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Set removed) { Int2ObjectOpenHashMap profiles = new Int2ObjectOpenHashMap<>(); for (String key : removed) { @@ -39,7 +39,9 @@ public class CameraShakePacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map assets) { + protected static ToClientPacket 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..cecfedc9 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 @@ -3,7 +3,7 @@ package com.hypixel.hytale.builtin.adventure.camera.asset.viewbobbing; import com.hypixel.hytale.assetstore.AssetMap; import com.hypixel.hytale.protocol.CachedPacket; import com.hypixel.hytale.protocol.MovementType; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateViewBobbing; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -16,19 +16,19 @@ import javax.annotation.Nonnull; public class ViewBobbingPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull @Override - public Packet generateInitPacket(AssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(AssetMap assetMap, @Nonnull Map assets) { return toCachedPacket(UpdateType.Init, assets); } @Nonnull @Override - protected Packet generateUpdatePacket(AssetMap assetMap, @Nonnull Map loadedAssets) { + protected ToClientPacket generateUpdatePacket(AssetMap assetMap, @Nonnull Map loadedAssets) { return toCachedPacket(UpdateType.AddOrUpdate, loadedAssets); } @Nonnull @Override - protected Packet generateRemovePacket(AssetMap assetMap, @Nonnull Set removed) { + protected ToClientPacket generateRemovePacket(AssetMap assetMap, @Nonnull Set removed) { UpdateViewBobbing packet = new UpdateViewBobbing(); packet.type = UpdateType.Remove; packet.profiles = new EnumMap<>(MovementType.class); @@ -41,7 +41,7 @@ public class ViewBobbingPacketGenerator extends SimpleAssetPacketGenerator assets) { + protected static ToClientPacket 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/camera/system/CameraEffectSystem.java b/src/com/hypixel/hytale/builtin/adventure/camera/system/CameraEffectSystem.java index 56811f1a..92480723 100644 --- a/src/com/hypixel/hytale/builtin/adventure/camera/system/CameraEffectSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/camera/system/CameraEffectSystem.java @@ -23,10 +23,19 @@ import javax.annotation.Nullable; public class CameraEffectSystem extends DamageEventSystem { @Nonnull - private static final ComponentType PLAYER_REF_COMPONENT_TYPE = PlayerRef.getComponentType(); - private static final ComponentType ENTITY_STAT_MAP_COMPONENT_TYPE = EntityStatMap.getComponentType(); + private final ComponentType playerRefComponentType; @Nonnull - private static final Query QUERY = Query.and(PLAYER_REF_COMPONENT_TYPE, ENTITY_STAT_MAP_COMPONENT_TYPE); + private final ComponentType entityStatMapComponentType; + @Nonnull + private final Query query; + + public CameraEffectSystem( + @Nonnull ComponentType playerRefComponentType, @Nonnull ComponentType entityStatMapComponentType + ) { + this.playerRefComponentType = playerRefComponentType; + this.entityStatMapComponentType = entityStatMapComponentType; + this.query = Query.and(playerRefComponentType, entityStatMapComponentType); + } @Nullable @Override @@ -37,7 +46,7 @@ public class CameraEffectSystem extends DamageEventSystem { @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } public void handle( @@ -47,7 +56,7 @@ public class CameraEffectSystem extends DamageEventSystem { @Nonnull CommandBuffer commandBuffer, @Nonnull Damage damage ) { - EntityStatMap entityStatMapComponent = archetypeChunk.getComponent(index, ENTITY_STAT_MAP_COMPONENT_TYPE); + EntityStatMap entityStatMapComponent = archetypeChunk.getComponent(index, this.entityStatMapComponentType); assert entityStatMapComponent != null; @@ -55,7 +64,7 @@ public class CameraEffectSystem extends DamageEventSystem { if (healthStat != null) { float health = healthStat.getMax() - healthStat.getMin(); if (!(health <= 0.0F)) { - PlayerRef playerRefComponent = archetypeChunk.getComponent(index, PLAYER_REF_COMPONENT_TYPE); + PlayerRef playerRefComponent = archetypeChunk.getComponent(index, this.playerRefComponentType); assert playerRefComponent != null; diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/FarmingPlugin.java b/src/com/hypixel/hytale/builtin/adventure/farming/FarmingPlugin.java index 6adcf927..bb9deae9 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; @@ -31,10 +32,15 @@ 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.item.config.ItemDropList; import com.hypixel.hytale.server.core.asset.type.weather.config.Weather; +import com.hypixel.hytale.server.core.entity.UUIDComponent; +import com.hypixel.hytale.server.core.modules.block.BlockModule; 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.chunk.section.BlockSection; +import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection; import com.hypixel.hytale.server.core.universe.world.events.ChunkPreLoadProcessEvent; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; @@ -60,28 +66,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 +104,34 @@ 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); + ComponentType blockStateInfoComponentType = BlockModule.BlockStateInfo.getComponentType(); + ComponentType blockSectionComponentType = BlockSection.getComponentType(); + ComponentType chunkSectionComponentType = ChunkSection.getComponentType(); + ComponentType uuidComponentType = UUIDComponent.getComponentType(); + chunkStoreRegistry.registerSystem(new FarmingSystems.OnSoilAdded(blockStateInfoComponentType, this.tiledSoilBlockComponentType)); + chunkStoreRegistry.registerSystem(new FarmingSystems.OnFarmBlockAdded(blockStateInfoComponentType, this.farmingBlockComponentType)); + chunkStoreRegistry.registerSystem( + new FarmingSystems.Ticking( + blockSectionComponentType, + chunkSectionComponentType, + this.farmingBlockComponentType, + this.tiledSoilBlockComponentType, + this.coopBlockStateComponentType + ) + ); + chunkStoreRegistry.registerSystem(new FarmingSystems.MigrateFarming()); + chunkStoreRegistry.registerSystem(new FarmingSystems.OnCoopAdded(blockStateInfoComponentType, this.coopBlockStateComponentType)); + entityStoreRegistry.registerSystem(new FarmingSystems.CoopResidentEntitySystem(this.coopResidentComponentType, uuidComponentType)); + entityStoreRegistry.registerSystem(new FarmingSystems.CoopResidentTicking(this.coopResidentComponentType)); 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..41adae04 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,54 @@ 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(); + @Nonnull + private final ComponentType coopResidentComponentType; + @Nonnull + private final ComponentType uuidComponentType; + public CoopResidentEntitySystem( + @Nonnull ComponentType coopResidentComponentType, + @Nonnull ComponentType uuidComponentType + ) { + this.coopResidentComponentType = coopResidentComponentType; + this.uuidComponentType = uuidComponentType; + } + + @Nonnull @Override public Query getQuery() { - return componentType; + return this.coopResidentComponentType; } @Override @@ -109,26 +129,26 @@ public class FarmingSystems { @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { if (reason != RemoveReason.UNLOAD) { - UUIDComponent uuidComponent = commandBuffer.getComponent(ref, UUIDComponent.getComponentType()); + UUIDComponent uuidComponent = commandBuffer.getComponent(ref, this.uuidComponentType); if (uuidComponent != null) { UUID uuid = uuidComponent.getUuid(); - CoopResidentComponent coopResidentComponent = commandBuffer.getComponent(ref, componentType); + CoopResidentComponent coopResidentComponent = commandBuffer.getComponent(ref, this.coopResidentComponentType); 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 +171,17 @@ public class FarmingSystems { } public static class CoopResidentTicking extends EntityTickingSystem { - private static final ComponentType componentType = CoopResidentComponent.getComponentType(); + @Nonnull + private final ComponentType coopResidentComponentType; + public CoopResidentTicking(@Nonnull ComponentType coopResidentComponentType) { + this.coopResidentComponentType = coopResidentComponentType; + } + + @Nonnull @Override public Query getQuery() { - return componentType; + return this.coopResidentComponentType; } @Override @@ -166,11 +192,12 @@ public class FarmingSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - CoopResidentComponent coopResidentComponent = archetypeChunk.getComponent(index, CoopResidentComponent.getComponentType()); - if (coopResidentComponent != null) { - if (coopResidentComponent.getMarkedForDespawn()) { - commandBuffer.removeEntity(archetypeChunk.getReferenceTo(index), RemoveReason.REMOVE); - } + CoopResidentComponent coopResidentComponent = archetypeChunk.getComponent(index, this.coopResidentComponentType); + + assert coopResidentComponent != null; + + if (coopResidentComponent.getMarkedForDespawn()) { + commandBuffer.removeEntity(archetypeChunk.getReferenceTo(index), RemoveReason.REMOVE); } } } @@ -200,32 +227,47 @@ public class FarmingSystems { } public static class OnCoopAdded extends RefSystem { - private static final Query QUERY = Query.and(BlockModule.BlockStateInfo.getComponentType(), CoopBlock.getComponentType()); + @Nonnull + private final ComponentType blockStateInfoComponentType; + @Nonnull + private final ComponentType coopBlockComponentType; + @Nonnull + private final Query query; + + public OnCoopAdded( + @Nonnull ComponentType blockStateInfoComponentType, + @Nonnull ComponentType coopBlockComponentType + ) { + this.blockStateInfoComponentType = blockStateInfoComponentType; + this.coopBlockComponentType = coopBlockComponentType; + this.query = Query.and(blockStateInfoComponentType, coopBlockComponentType); + } @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, this.coopBlockComponentType); - 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, this.blockStateInfoComponentType); - 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,147 +276,188 @@ 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, this.coopBlockComponentType); - 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, this.blockStateInfoComponentType); - 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); } } - @Nullable + @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } } public static class OnFarmBlockAdded extends RefSystem { - private static final Query QUERY = Query.and(BlockModule.BlockStateInfo.getComponentType(), FarmingBlock.getComponentType()); + @Nonnull + private final ComponentType blockStateInfoComponentType; + @Nonnull + private final ComponentType farmingBlockComponentType; + @Nonnull + private final Query query; + + public OnFarmBlockAdded( + @Nonnull ComponentType blockStateInfoComponentType, + @Nonnull ComponentType farmingBlockComponentType + ) { + this.blockStateInfoComponentType = blockStateInfoComponentType; + this.farmingBlockComponentType = farmingBlockComponentType; + this.query = Query.and(blockStateInfoComponentType, farmingBlockComponentType); + } @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, this.farmingBlockComponentType); - assert farmingBlock != null; + assert farmingBlockComponent != null; - BlockModule.BlockStateInfo info = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, this.blockStateInfoComponentType); - 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 @@ -383,51 +466,67 @@ public class FarmingSystems { ) { } - @Nullable + @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } } public static class OnSoilAdded extends RefSystem { - private static final Query QUERY = Query.and(BlockModule.BlockStateInfo.getComponentType(), TilledSoilBlock.getComponentType()); + @Nonnull + private final ComponentType blockStateInfoComponentType; + @Nonnull + private final ComponentType tilledSoilBlockComponentType; + @Nonnull + private final Query query; + + public OnSoilAdded( + @Nonnull ComponentType blockStateInfoComponentType, + @Nonnull ComponentType tilledSoilBlockComponentType + ) { + this.blockStateInfoComponentType = blockStateInfoComponentType; + this.tilledSoilBlockComponentType = tilledSoilBlockComponentType; + this.query = Query.and(blockStateInfoComponentType, tilledSoilBlockComponentType); + } @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, this.tilledSoilBlockComponentType); - assert soil != null; + assert soilComponent != null; - BlockModule.BlockStateInfo info = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, this.blockStateInfoComponentType); - 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); } } @@ -437,15 +536,41 @@ public class FarmingSystems { ) { } - @Nullable + @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } } public static class Ticking extends EntityTickingSystem { - private static final Query QUERY = Query.and(BlockSection.getComponentType(), ChunkSection.getComponentType()); + @Nonnull + private final ComponentType blockSectionComponentType; + @Nonnull + private final ComponentType chunkSectionComponentType; + @Nonnull + private final ComponentType farmingBlockComponentType; + @Nonnull + private final ComponentType tilledSoilBlockComponentType; + @Nonnull + private final ComponentType coopBlockComponentType; + @Nonnull + private final Query query; + + public Ticking( + @Nonnull ComponentType blockSectionComponentType, + @Nonnull ComponentType chunkSectionComponentType, + @Nonnull ComponentType farmingBlockComponentType, + @Nonnull ComponentType tilledSoilBlockComponentType, + @Nonnull ComponentType coopBlockComponentType + ) { + this.blockSectionComponentType = blockSectionComponentType; + this.chunkSectionComponentType = chunkSectionComponentType; + this.farmingBlockComponentType = farmingBlockComponentType; + this.tilledSoilBlockComponentType = tilledSoilBlockComponentType; + this.coopBlockComponentType = coopBlockComponentType; + this.query = Query.and(blockSectionComponentType, chunkSectionComponentType); + } @Override public void tick( @@ -455,44 +580,50 @@ public class FarmingSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - BlockSection blocks = archetypeChunk.getComponent(index, BlockSection.getComponentType()); + BlockSection blockSectionComponent = archetypeChunk.getComponent(index, this.blockSectionComponentType); - 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, this.chunkSectionComponentType); - 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 farmingBlockComp = commandBuffer1.getComponent(blockRef, this.farmingBlockComponentType); + if (farmingBlockComp != null) { + FarmingUtil.tickFarming( + commandBuffer1, blockChunk, blockSectionComponent, ref, blockRef, farmingBlockComp, localX, localY, localZ, false + ); return BlockTickStrategy.SLEEP; } else { - TilledSoilBlock soil = commandBuffer1.getComponent(blockRef, TilledSoilBlock.getComponentType()); - if (soil != null) { - tickSoil(commandBuffer1, blockComponentChunk1, blockRef, soil); + TilledSoilBlock tilledSoilBlockComp = commandBuffer1.getComponent(blockRef, this.tilledSoilBlockComponentType); + if (tilledSoilBlockComp != null) { + tickSoil(commandBuffer1, blockRef, tilledSoilBlockComp); return BlockTickStrategy.SLEEP; } else { - CoopBlock coop = commandBuffer1.getComponent(blockRef, CoopBlock.getComponentType()); - if (coop != null) { - tickCoop(commandBuffer1, blockComponentChunk1, blockRef, coop); + CoopBlock coopBlockComp = commandBuffer1.getComponent(blockRef, this.coopBlockComponentType); + if (coopBlockComp != null) { + tickCoop(commandBuffer1, blockRef, coopBlockComp); return BlockTickStrategy.SLEEP; } else { return BlockTickStrategy.IGNORED; @@ -506,122 +637,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,15 +789,15 @@ 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); } } } - @Nullable + @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/farming/FarmingUtil.java b/src/com/hypixel/hytale/builtin/adventure/farming/FarmingUtil.java index 0b100ead..a4034352 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); + } } } } @@ -168,22 +172,22 @@ public class FarmingUtil { } } - public static void harvest( + public static boolean 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); - } + return world.getGameplayConfig().getWorldConfig().isBlockGatheringAllowed() + ? harvest0(componentAccessor, ref, blockType, rotationIndex, blockPosition) + : false; } @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; } } @@ -208,24 +212,19 @@ public class FarmingUtil { @Nonnull Vector3i blockPosition ) { FarmingData farmingConfig = blockType.getFarming(); + boolean isFarmable = true; if (farmingConfig == null || farmingConfig.getStages() == null) { - return false; - } else if (blockType.getGathering().getHarvest() == null) { + isFarmable = false; + } + + if (blockType.getGathering().getHarvest() == null) { return false; } else { World world = store.getExternalData().getWorld(); Vector3d centerPosition = new Vector3d(); blockType.getBlockCenter(rotationIndex, centerPosition); centerPosition.add(blockPosition); - if (farmingConfig.getStageSetAfterHarvest() == null) { - giveDrops(store, ref, centerPosition, blockType); - WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(blockPosition.x, blockPosition.z)); - if (chunk != null) { - chunk.breakBlock(blockPosition.x, blockPosition.y, blockPosition.z); - } - - return true; - } else { + if (isFarmable && farmingConfig.getStageSetAfterHarvest() != null) { giveDrops(store, ref, centerPosition, blockType); Map stageSets = farmingConfig.getStages(); FarmingStageData[] stages = stageSets.get(farmingConfig.getStartingStageSet()); @@ -285,7 +284,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); @@ -302,6 +302,14 @@ public class FarmingUtil { return false; } } + } else { + giveDrops(store, ref, centerPosition, blockType); + WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(blockPosition.x, blockPosition.z)); + if (chunk != null) { + chunk.breakBlock(blockPosition.x, blockPosition.y, blockPosition.z); + } + + return true; } } } @@ -312,6 +320,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..a123a185 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 @@ -1,6 +1,5 @@ package com.hypixel.hytale.builtin.adventure.farming.config.stages; -import com.hypixel.hytale.assetstore.AssetPack; import com.hypixel.hytale.assetstore.AssetRegistry; import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap; import com.hypixel.hytale.builtin.adventure.farming.states.FarmingBlock; @@ -13,13 +12,13 @@ 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; import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.BlockMaterial; -import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.Rotation; import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple; @@ -37,20 +36,24 @@ import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection; import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; 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 +80,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 +94,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 +146,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 +359,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 +375,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 +423,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) @@ -354,14 +453,12 @@ public class PrefabFarmingStageData extends FarmingStageData { @Nonnull public Path getResolvedPath() { - for (AssetPack pack : AssetModule.get().getAssetPacks()) { - Path assetPath = pack.getRoot().resolve("Server").resolve("Prefabs").resolve(this.path); - if (Files.exists(assetPath)) { - return assetPath; - } + Path assetPath = PrefabStore.get().findAssetPrefabPath(this.path); + if (assetPath == null) { + throw new IllegalStateException("Invalid prefab path: " + this.path); + } else { + return assetPath; } - - return PrefabStore.get().getAssetPrefabsPath().resolve(this.path); } @Nonnull 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..e8e94f27 100644 --- a/src/com/hypixel/hytale/builtin/adventure/farming/interactions/HarvestCropInteraction.java +++ b/src/com/hypixel/hytale/builtin/adventure/farming/interactions/HarvestCropInteraction.java @@ -1,11 +1,14 @@ package com.hypixel.hytale.builtin.adventure.farming.interactions; import com.hypixel.hytale.builtin.adventure.farming.FarmingUtil; +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.vector.Vector3i; +import com.hypixel.hytale.protocol.InteractionState; import com.hypixel.hytale.protocol.InteractionType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.entity.InteractionContext; @@ -22,11 +25,21 @@ 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 ) .documentation("Harvests the resources from the target farmable block.") + .appendInherited( + new KeyedCodec<>("RequireNotBroken", Codec.BOOLEAN), + (interaction, s) -> interaction.requireNotBroken = s, + interaction -> interaction.requireNotBroken, + (interaction, parent) -> interaction.requireNotBroken = parent.requireNotBroken + ) + .documentation("If true, the interaction will fail if the held item is broken (durability = 0).") + .add() .build(); + protected boolean requireNotBroken = false; @Override protected void interactWithBlock( @@ -38,25 +51,31 @@ public class HarvestCropInteraction extends SimpleBlockInteraction { @Nonnull Vector3i targetBlock, @Nonnull CooldownHandler cooldownHandler ) { - Ref ref = context.getEntity(); - ChunkStore chunkStore = world.getChunkStore(); - long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); - Ref chunkRef = chunkStore.getChunkReference(chunkIndex); - if (chunkRef != null && chunkRef.isValid()) { - BlockChunk blockChunkComponent = chunkStore.getStore().getComponent(chunkRef, BlockChunk.getComponentType()); + if (this.requireNotBroken && itemInHand != null && itemInHand.isBroken()) { + context.getState().state = InteractionState.Failed; + } else { + Ref ref = context.getEntity(); + ChunkStore chunkStore = world.getChunkStore(); + long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); + Ref chunkRef = chunkStore.getChunkReference(chunkIndex); + if (chunkRef != null && chunkRef.isValid()) { + BlockChunk blockChunkComponent = chunkStore.getStore().getComponent(chunkRef, BlockChunk.getComponentType()); - assert blockChunkComponent != null; + assert blockChunkComponent != null; - BlockSection section = blockChunkComponent.getSectionAtBlockY(targetBlock.y); - if (section != null) { - WorldChunk worldChunkComponent = chunkStore.getStore().getComponent(chunkRef, WorldChunk.getComponentType()); + BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(targetBlock.y); + if (blockSection != null) { + WorldChunk worldChunkComponent = chunkStore.getStore().getComponent(chunkRef, WorldChunk.getComponentType()); - assert worldChunkComponent != null; + assert worldChunkComponent != null; - BlockType blockType = worldChunkComponent.getBlockType(targetBlock); - if (blockType != null) { - int rotationIndex = section.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z); - FarmingUtil.harvest(world, commandBuffer, ref, blockType, rotationIndex, targetBlock); + BlockType blockType = worldChunkComponent.getBlockType(targetBlock); + if (blockType != null) { + int rotationIndex = blockSection.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z); + if (!FarmingUtil.harvest(world, commandBuffer, ref, blockType, rotationIndex, targetBlock)) { + context.getState().state = InteractionState.Failed; + } + } } } } 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..4ff8eecd 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/MemoriesPlugin.java @@ -40,6 +40,7 @@ import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.windows.Window; import com.hypixel.hytale.server.core.io.PacketHandler; +import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entity.player.PlayerSystems; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.server.OpenCustomUIInteraction; @@ -69,9 +70,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 @@ -95,9 +101,16 @@ public class MemoriesPlugin extends JavaPlugin { OpenCustomUIInteraction.registerCustomPageSupplier(this, MemoriesUnlockedPage.class, "MemoriesUnlocked", new MemoriesUnlockedPageSuplier()); Window.CLIENT_REQUESTABLE_WINDOW_TYPES.put(WindowType.Memories, MemoriesWindow::new); this.playerMemoriesComponentType = entityStoreRegistry.registerComponent(PlayerMemories.class, "PlayerMemories", PlayerMemories.CODEC); + ComponentType playerComponentType = Player.getComponentType(); + ComponentType playerRefComponentType = PlayerRef.getComponentType(); + ComponentType transformComponentType = TransformComponent.getComponentType(); NPCMemoryProvider npcMemoryProvider = new NPCMemoryProvider(); this.registerMemoryProvider(npcMemoryProvider); - entityStoreRegistry.registerSystem(new NPCMemory.GatherMemoriesSystem(npcMemoryProvider.getCollectionRadius())); + entityStoreRegistry.registerSystem( + new NPCMemory.GatherMemoriesSystem( + transformComponentType, playerComponentType, playerRefComponentType, this.playerMemoriesComponentType, npcMemoryProvider.getCollectionRadius() + ) + ); for (MemoryProvider provider : this.providers) { BuilderCodec codec = (BuilderCodec)provider.getCodec(); @@ -105,11 +118,11 @@ public class MemoriesPlugin extends JavaPlugin { } this.getEventRegistry().register(AllNPCsLoadedEvent.class, event -> this.onAssetsLoad()); - entityStoreRegistry.registerSystem(new MemoriesPlugin.PlayerAddedSystem()); + entityStoreRegistry.registerSystem(new MemoriesPlugin.PlayerAddedSystem(playerComponentType, playerRefComponentType, this.playerMemoriesComponentType)); this.getCodecRegistry(Interaction.CODEC).register("SetMemoriesCapacity", SetMemoriesCapacityInteraction.class, SetMemoriesCapacityInteraction.CODEC); this.getCodecRegistry(GameplayConfig.PLUGIN_CODEC).register(MemoriesGameplayConfig.class, "Memories", MemoriesGameplayConfig.CODEC); this.getCodecRegistry(Interaction.CODEC).register("MemoriesCondition", MemoriesConditionInteraction.class, MemoriesConditionInteraction.CODEC); - entityStoreRegistry.registerSystem(new TempleRespawnPlayersSystem()); + entityStoreRegistry.registerSystem(new TempleRespawnPlayersSystem(playerRefComponentType, transformComponentType)); this.getCodecRegistry(GameplayConfig.PLUGIN_CODEC).register(ForgottenTempleConfig.class, "ForgottenTemple", ForgottenTempleConfig.CODEC); } @@ -169,6 +182,7 @@ public class MemoriesPlugin extends JavaPlugin { this.providers.add(memoryProvider); } + @Nonnull public Map> getAllMemories() { return this.allMemories; } @@ -299,6 +313,7 @@ public class MemoriesPlugin extends JavaPlugin { } public static class MemoriesPluginConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MemoriesPlugin.MemoriesPluginConfig.class, MemoriesPlugin.MemoriesPluginConfig::new ) @@ -321,7 +336,24 @@ public class MemoriesPlugin extends JavaPlugin { @Nonnull private final Set> dependencies = Set.of(new SystemDependency<>(Order.AFTER, PlayerSystems.PlayerSpawnedSystem.class)); @Nonnull - private final Query query = Query.and(Player.getComponentType(), PlayerRef.getComponentType()); + private final ComponentType playerComponentType; + @Nonnull + private final ComponentType playerRefComponentType; + @Nonnull + private final ComponentType playerMemoriesComponentType; + @Nonnull + private final Query query; + + public PlayerAddedSystem( + @Nonnull ComponentType playerComponentType, + @Nonnull ComponentType playerRefComponentType, + @Nonnull ComponentType playerMemoriesComponentType + ) { + this.playerComponentType = playerComponentType; + this.playerRefComponentType = playerRefComponentType; + this.playerMemoriesComponentType = playerMemoriesComponentType; + this.query = Query.and(playerComponentType, playerRefComponentType); + } @Nonnull @Override @@ -339,15 +371,15 @@ public class MemoriesPlugin extends JavaPlugin { public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); + Player playerComponent = store.getComponent(ref, this.playerComponentType); assert playerComponent != null; - PlayerRef playerRefComponent = store.getComponent(ref, PlayerRef.getComponentType()); + PlayerRef playerRefComponent = store.getComponent(ref, this.playerRefComponentType); assert playerRefComponent != null; - PlayerMemories playerMemoriesComponent = store.getComponent(ref, PlayerMemories.getComponentType()); + PlayerMemories playerMemoriesComponent = store.getComponent(ref, this.playerMemoriesComponentType); boolean isFeatureUnlockedByPlayer = playerMemoriesComponent != null; PacketHandler playerConnection = playerRefComponent.getPacketHandler(); playerConnection.writeNoCache(new UpdateMemoriesFeatureStatus(isFeatureUnlockedByPlayer)); @@ -361,6 +393,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 +404,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..821be62d 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 @@ -13,6 +13,7 @@ import com.hypixel.hytale.codec.validation.Validators; import com.hypixel.hytale.component.AddReason; 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.Ref; import com.hypixel.hytale.component.Store; @@ -34,7 +35,6 @@ import com.hypixel.hytale.server.core.modules.entity.component.TransformComponen import com.hypixel.hytale.server.core.modules.entity.item.ItemComponent; import com.hypixel.hytale.server.core.modules.entity.item.PickupItemComponent; import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId; -import com.hypixel.hytale.server.core.modules.i18n.I18nModule; 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; @@ -53,18 +53,14 @@ 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()) .add() .append(new KeyedCodec<>("TranslationKey", Codec.STRING), (npcMemory, s) -> npcMemory.memoryTitleKey = s, npcMemory -> npcMemory.memoryTitleKey) .add() - .append( - new KeyedCodec<>("IsMemoriesNameOverridden", Codec.BOOLEAN), - (npcMemory, aBoolean) -> npcMemory.isMemoriesNameOverridden = aBoolean, - npcMemory -> npcMemory.isMemoriesNameOverridden - ) - .add() .append( new KeyedCodec<>("CapturedTimestamp", Codec.LONG), (npcMemory, aDouble) -> npcMemory.capturedTimestamp = aDouble, @@ -83,10 +79,8 @@ public class NPCMemory extends Memory { npcMemory -> npcMemory.foundLocationGeneralNameKey ) .add() - .afterDecode(NPCMemory::processConfig) .build(); private String npcRole; - private boolean isMemoriesNameOverridden; private long capturedTimestamp; private String foundLocationZoneNameKey; private String foundLocationGeneralNameKey; @@ -95,11 +89,9 @@ public class NPCMemory extends Memory { private NPCMemory() { } - public NPCMemory(@Nonnull String npcRole, @Nonnull String nameTranslationKey, boolean isMemoriesNameOverridden) { + public NPCMemory(@Nonnull String npcRole, @Nonnull String nameTranslationKey) { this.npcRole = npcRole; this.memoryTitleKey = nameTranslationKey; - this.isMemoriesNameOverridden = isMemoriesNameOverridden; - this.processConfig(); } @Override @@ -119,25 +111,12 @@ 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"; } - public void processConfig() { - if (this.isMemoriesNameOverridden) { - this.memoryTitleKey = "server.npcRoles." + this.npcRole + ".name"; - if (I18nModule.get().getMessage("en-US", this.memoryTitleKey) == null) { - this.memoryTitleKey = "server.memories.names." + this.npcRole; - } - } - - if (this.memoryTitleKey == null || this.memoryTitleKey.isEmpty()) { - this.memoryTitleKey = "server.npcRoles." + this.npcRole + ".name"; - } - } - @Nonnull @Override public Message getUndiscoveredTooltipText() { @@ -157,6 +136,7 @@ public class NPCMemory extends Memory { return this.foundLocationZoneNameKey; } + @Nonnull public Message getLocationMessage() { if (this.foundLocationGeneralNameKey != null) { return Message.translation(this.foundLocationGeneralNameKey); @@ -166,30 +146,28 @@ 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)) { return false; } else { NPCMemory npcMemory = (NPCMemory)o; - return this.isMemoriesNameOverridden == npcMemory.isMemoriesNameOverridden && Objects.equals(this.npcRole, npcMemory.npcRole); + return Objects.equals(this.npcRole, npcMemory.npcRole); } } @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + Objects.hashCode(this.npcRole); - return 31 * result + Boolean.hashCode(this.isMemoriesNameOverridden); + return 31 * result + Objects.hashCode(this.npcRole); } + @Nonnull @Override public String toString() { return "NPCMemory{npcRole='" + this.npcRole - + "', isMemoriesNameOverride=" - + this.isMemoriesNameOverridden + "', capturedTimestamp=" + this.capturedTimestamp + "', foundLocationZoneNameKey='" @@ -199,12 +177,29 @@ 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() - ); + private final ComponentType transformComponentType; + @Nonnull + private final ComponentType playerComponentType; + @Nonnull + private final ComponentType playerRefComponentType; + @Nonnull + private final ComponentType playerMemoriesComponentType; + @Nonnull + private final Query query; private final double radius; - public GatherMemoriesSystem(double radius) { + public GatherMemoriesSystem( + @Nonnull ComponentType transformComponentType, + @Nonnull ComponentType playerComponentType, + @Nonnull ComponentType playerRefComponentType, + @Nonnull ComponentType playerMemoriesComponentType, + double radius + ) { + this.transformComponentType = transformComponentType; + this.playerComponentType = playerComponentType; + this.playerRefComponentType = playerRefComponentType; + this.playerMemoriesComponentType = playerMemoriesComponentType; + this.query = Query.and(transformComponentType, playerComponentType, playerRefComponentType, playerMemoriesComponentType); this.radius = radius; } @@ -216,12 +211,12 @@ public class NPCMemory extends Memory { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - Player playerComponent = archetypeChunk.getComponent(index, Player.getComponentType()); + Player playerComponent = archetypeChunk.getComponent(index, this.playerComponentType); assert playerComponent != null; if (playerComponent.getGameMode() == GameMode.Adventure) { - TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + TransformComponent transformComponent = archetypeChunk.getComponent(index, this.transformComponentType); assert transformComponent != null; @@ -230,13 +225,13 @@ public class NPCMemory extends Memory { ObjectList> results = SpatialResource.getThreadLocalReferenceList(); npcSpatialResource.getSpatialStructure().collect(position, this.radius, results); if (!results.isEmpty()) { - PlayerRef playerRefComponent = archetypeChunk.getComponent(index, PlayerRef.getComponentType()); + PlayerRef playerRefComponent = archetypeChunk.getComponent(index, this.playerRefComponentType); assert playerRefComponent != null; Ref ref = archetypeChunk.getReferenceTo(index); MemoriesPlugin memoriesPlugin = MemoriesPlugin.get(); - PlayerMemories playerMemoriesComponent = archetypeChunk.getComponent(index, PlayerMemories.getComponentType()); + PlayerMemories playerMemoriesComponent = archetypeChunk.getComponent(index, this.playerMemoriesComponentType); assert playerMemoriesComponent != null; @@ -248,29 +243,22 @@ 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()) { - temp.isMemoriesNameOverridden = role.isMemoriesNameOverriden(); - temp.npcRole = temp.isMemoriesNameOverridden ? role.getMemoriesNameOverride() : npcComponent.getRoleName(); + if (role != null && role.isMemory()) { + String memoriesNameOverride = role.getMemoriesNameOverride(); + temp.npcRole = memoriesNameOverride != null && !memoriesNameOverride.isEmpty() ? memoriesNameOverride : npcComponent.getRoleName(); temp.memoryTitleKey = role.getNameTranslationKey(); temp.capturedTimestamp = System.currentTimeMillis(); temp.foundLocationGeneralNameKey = foundLocationZoneNameKey; - if (!memoriesPlugin.hasRecordedMemory(temp)) { - temp.processConfig(); - if (playerMemoriesComponent.recordMemory(temp)) { - NotificationUtil.sendNotification( - playerRefComponent.getPacketHandler(), - Message.translation("server.memories.general.collected").param("memoryTitle", Message.translation(temp.getTitle())), - null, - "NotificationIcons/MemoriesIcon.png" - ); - temp = new NPCMemory(); - TransformComponent npcTransformComponent = commandBuffer.getComponent(npcRef, TransformComponent.getComponentType()); - - assert npcTransformComponent != null; - + if (!memoriesPlugin.hasRecordedMemory(temp) && playerMemoriesComponent.recordMemory(temp)) { + NotificationUtil.sendNotification( + playerRefComponent.getPacketHandler(), + Message.translation("server.memories.general.collected").param("memoryTitle", Message.translation(temp.getTitle())), + null, + "NotificationIcons/MemoriesIcon.png" + ); + temp = new NPCMemory(); + TransformComponent npcTransformComponent = commandBuffer.getComponent(npcRef, TransformComponent.getComponentType()); + if (npcTransformComponent != null) { MemoriesGameplayConfig memoriesGameplayConfig = MemoriesGameplayConfig.get(store.getExternalData().getWorld().getGameplayConfig()); if (memoriesGameplayConfig != null) { ItemStack memoryItemStack = new ItemStack(memoriesGameplayConfig.getMemoriesCatchItemId()); @@ -301,7 +289,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 +308,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 +326,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); + } } } } @@ -347,7 +337,7 @@ public class NPCMemory extends Memory { @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/memories/memories/npc/NPCMemoryProvider.java b/src/com/hypixel/hytale/builtin/adventure/memories/memories/npc/NPCMemoryProvider.java index 551e6bf7..37446185 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/memories/npc/NPCMemoryProvider.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/memories/npc/NPCMemoryProvider.java @@ -42,9 +42,9 @@ public class NPCMemoryProvider extends MemoryProvider { String translationKey = getNPCNameTranslationKey(builder); NPCMemory memory; if (memoriesNameOverride != null && !memoriesNameOverride.isEmpty()) { - memory = new NPCMemory(memoriesNameOverride, translationKey, true); + memory = new NPCMemory(memoriesNameOverride, translationKey); } else { - memory = new NPCMemory(builderInfo.getKeyName(), translationKey, false); + memory = new NPCMemory(builderInfo.getKeyName(), translationKey); } allMemories.computeIfAbsent(category, s -> new HashSet<>()).add(memory); 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..9e4b057a 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..4ab9fc19 100644 --- a/src/com/hypixel/hytale/builtin/adventure/memories/temple/TempleRespawnPlayersSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/memories/temple/TempleRespawnPlayersSystem.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.builtin.adventure.memories.temple; import com.hypixel.hytale.component.ArchetypeChunk; import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; @@ -18,13 +19,22 @@ import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.spawn.ISpawnProvider; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class TempleRespawnPlayersSystem extends DelayedEntitySystem { - public static final Query QUERY = Query.and(PlayerRef.getComponentType(), TransformComponent.getComponentType()); + @Nonnull + private final ComponentType playerRefComponentType; + @Nonnull + private final ComponentType transformComponentType; + @Nonnull + private final Query query; - public TempleRespawnPlayersSystem() { + public TempleRespawnPlayersSystem( + @Nonnull ComponentType playerRefComponentType, @Nonnull ComponentType transformComponentType + ) { super(1.0F); + this.playerRefComponentType = playerRefComponentType; + this.transformComponentType = transformComponentType; + this.query = Query.and(playerRefComponentType, transformComponentType); } @Override @@ -39,7 +49,7 @@ public class TempleRespawnPlayersSystem extends DelayedEntitySystem GameplayConfig gameplayConfig = world.getGameplayConfig(); ForgottenTempleConfig config = gameplayConfig.getPluginConfig().get(ForgottenTempleConfig.class); if (config != null) { - TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + TransformComponent transformComponent = archetypeChunk.getComponent(index, this.transformComponentType); assert transformComponent != null; @@ -50,15 +60,18 @@ public class TempleRespawnPlayersSystem extends DelayedEntitySystem Transform spawnTransform = spawnProvider.getSpawnPoint(ref, commandBuffer); Teleport teleportComponent = Teleport.createForPlayer(null, spawnTransform); commandBuffer.addComponent(ref, Teleport.getComponentType(), teleportComponent); - PlayerRef playerRef = archetypeChunk.getComponent(index, PlayerRef.getComponentType()); - SoundUtil.playSoundEvent2dToPlayer(playerRef, config.getRespawnSoundIndex(), SoundCategory.SFX); + PlayerRef playerRefComponent = archetypeChunk.getComponent(index, this.playerRefComponentType); + + assert playerRefComponent != null; + + SoundUtil.playSoundEvent2dToPlayer(playerRefComponent, config.getRespawnSoundIndex(), SoundCategory.SFX); } } } - @Nullable + @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } } 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..b447c559 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/NPCObjectivesPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/NPCObjectivesPlugin.java @@ -23,6 +23,8 @@ 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.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; @@ -33,8 +35,10 @@ 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 com.hypixel.hytale.server.npc.NPCPlugin; +import com.hypixel.hytale.server.npc.entities.NPCEntity; import com.hypixel.hytale.server.spawning.assets.spawnmarker.config.SpawnMarker; import com.hypixel.hytale.server.spawning.assets.spawns.config.BeaconNPCSpawn; +import com.hypixel.hytale.server.spawning.beacons.LegacySpawnBeaconEntity; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -56,45 +60,45 @@ 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 + ); + this.killTrackerResourceType = entityStoreRegistry.registerResource(KillTrackerResource.class, KillTrackerResource::new); + ComponentType legacySpawnBeaconEntityComponentType = LegacySpawnBeaconEntity.getComponentType(); + ComponentType npcEntityComponentType = NPCEntity.getComponentType(); + entityStoreRegistry.registerSystem(new SpawnBeaconCheckRemovalSystem(legacySpawnBeaconEntityComponentType)); + entityStoreRegistry.registerSystem(new KillTrackerSystem(npcEntityComponentType, this.killTrackerResourceType)); NPCPlugin.get() .registerCoreComponentType("CompleteTask", BuilderActionCompleteTask::new) .registerCoreComponentType("StartObjective", BuilderActionStartObjective::new) @@ -114,48 +118,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..a535e2a8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/KillTrackerSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/KillTrackerSystem.java @@ -3,35 +3,55 @@ package com.hypixel.hytale.builtin.adventure.npcobjectives.systems; import com.hypixel.hytale.builtin.adventure.npcobjectives.resources.KillTrackerResource; import com.hypixel.hytale.builtin.adventure.npcobjectives.transaction.KillTaskTransaction; import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.ResourceType; 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; import com.hypixel.hytale.server.npc.entities.NPCEntity; import java.util.List; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class KillTrackerSystem extends DeathSystems.OnDeathSystem { - @Nullable + @Nonnull + private final ComponentType npcEntityComponentType; + @Nonnull + private final ResourceType killTrackerResourceType; + + public KillTrackerSystem( + @Nonnull ComponentType npcEntityComponentType, @Nonnull ResourceType killTrackerResourceType + ) { + this.npcEntityComponentType = npcEntityComponentType; + this.killTrackerResourceType = killTrackerResourceType; + } + + @Nonnull @Override public Query getQuery() { - return NPCEntity.getComponentType(); + return this.npcEntityComponentType; } 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, this.npcEntityComponentType); - 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(this.killTrackerResourceType); + 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/systems/SpawnBeaconCheckRemovalSystem.java b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/SpawnBeaconCheckRemovalSystem.java index 81bec396..32f9a8de 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/SpawnBeaconCheckRemovalSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcobjectives/systems/SpawnBeaconCheckRemovalSystem.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.builtin.adventure.npcobjectives.systems; import com.hypixel.hytale.builtin.adventure.objectives.ObjectivePlugin; import com.hypixel.hytale.component.AddReason; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.RemoveReason; import com.hypixel.hytale.component.Store; @@ -11,18 +12,24 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.spawning.beacons.LegacySpawnBeaconEntity; import java.util.UUID; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class SpawnBeaconCheckRemovalSystem extends HolderSystem { - @Nullable + @Nonnull + private final ComponentType legacySpawnBeaconEntityComponentType; + + public SpawnBeaconCheckRemovalSystem(@Nonnull ComponentType legacySpawnBeaconEntityComponentType) { + this.legacySpawnBeaconEntityComponentType = legacySpawnBeaconEntityComponentType; + } + + @Nonnull @Override public Query getQuery() { - return LegacySpawnBeaconEntity.getComponentType(); + return this.legacySpawnBeaconEntityComponentType; } @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - LegacySpawnBeaconEntity spawnBeaconComponent = holder.getComponent(LegacySpawnBeaconEntity.getComponentType()); + LegacySpawnBeaconEntity spawnBeaconComponent = holder.getComponent(this.legacySpawnBeaconEntityComponentType); assert spawnBeaconComponent != null; 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..99239864 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationHolderSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationHolderSystem.java @@ -17,13 +17,16 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; public class NPCReputationHolderSystem extends HolderSystem { + @Nonnull private final ComponentType reputationGroupComponentType; + @Nonnull private final ComponentType npcEntityComponentType; @Nonnull private final Query query; public NPCReputationHolderSystem( - ComponentType reputationGroupComponentType, ComponentType npcEntityComponentType + @Nonnull ComponentType reputationGroupComponentType, + @Nonnull ComponentType npcEntityComponentType ) { this.reputationGroupComponentType = reputationGroupComponentType; this.npcEntityComponentType = npcEntityComponentType; @@ -38,8 +41,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..d33d0e2b 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcreputation/NPCReputationPlugin.java @@ -1,8 +1,14 @@ 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.component.ComponentType; +import com.hypixel.hytale.component.ResourceType; +import com.hypixel.hytale.server.core.entity.entities.Player; 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.blackboard.Blackboard; import com.hypixel.hytale.server.npc.entities.NPCEntity; import javax.annotation.Nonnull; @@ -13,7 +19,12 @@ 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(); + ResourceType blackboardResourceType = Blackboard.getResourceType(); + ComponentType playerComponentType = Player.getComponentType(); + ComponentType reputationGroupComponentType = ReputationGroupComponent.getComponentType(); + ComponentType npcEntityComponentType = NPCEntity.getComponentType(); + entityStoreRegistry.registerSystem(new ReputationAttitudeSystem(blackboardResourceType, playerComponentType)); + entityStoreRegistry.registerSystem(new NPCReputationHolderSystem(reputationGroupComponentType, npcEntityComponentType)); } } diff --git a/src/com/hypixel/hytale/builtin/adventure/npcreputation/ReputationAttitudeSystem.java b/src/com/hypixel/hytale/builtin/adventure/npcreputation/ReputationAttitudeSystem.java index 423ecdb6..2d6ec966 100644 --- a/src/com/hypixel/hytale/builtin/adventure/npcreputation/ReputationAttitudeSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/npcreputation/ReputationAttitudeSystem.java @@ -1,6 +1,7 @@ package com.hypixel.hytale.builtin.adventure.npcreputation; import com.hypixel.hytale.builtin.adventure.reputation.ReputationPlugin; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.system.StoreSystem; @@ -11,14 +12,24 @@ import com.hypixel.hytale.server.npc.blackboard.view.attitude.AttitudeView; import javax.annotation.Nonnull; public class ReputationAttitudeSystem extends StoreSystem { - private final ResourceType resourceType = Blackboard.getResourceType(); + @Nonnull + private final ResourceType blackboardResourceType; + @Nonnull + private final ComponentType playerComponentType; + + public ReputationAttitudeSystem( + @Nonnull ResourceType blackboardResourceType, @Nonnull ComponentType playerComponentType + ) { + this.blackboardResourceType = blackboardResourceType; + this.playerComponentType = playerComponentType; + } @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) -> { - Player playerComponent = store.getComponent(targetRef, Player.getComponentType()); + Blackboard blackboardResource = store.getResource(this.blackboardResourceType); + AttitudeView attitudeView = blackboardResource.getView(AttitudeView.class, 0L); + attitudeView.registerProvider(100, (ref, role, targetRef, accessor) -> { + Player playerComponent = store.getComponent(targetRef, this.playerComponentType); 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..173131ef 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/ObjectivePlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/ObjectivePlugin.java @@ -45,10 +45,12 @@ import com.hypixel.hytale.builtin.adventure.objectives.task.ReachLocationTask; import com.hypixel.hytale.builtin.adventure.objectives.task.TreasureMapObjectiveTask; import com.hypixel.hytale.builtin.adventure.objectives.task.UseBlockObjectiveTask; import com.hypixel.hytale.builtin.adventure.objectives.task.UseEntityObjectiveTask; +import com.hypixel.hytale.builtin.weather.components.WeatherTracker; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.common.util.ArrayUtil; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.ResourceType; @@ -56,6 +58,7 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.AndQuery; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.spatial.SpatialResource; +import com.hypixel.hytale.event.EventRegistry; import com.hypixel.hytale.function.function.TriFunction; import com.hypixel.hytale.math.vector.Vector3f; import com.hypixel.hytale.protocol.packets.assets.TrackOrUpdateObjective; @@ -71,7 +74,6 @@ import com.hypixel.hytale.server.core.asset.type.item.config.ItemDropList; 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.asset.type.weather.config.Weather; -import com.hypixel.hytale.server.core.entity.LivingEntity; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerConfigData; @@ -83,9 +85,11 @@ import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; import com.hypixel.hytale.server.core.modules.entity.component.PersistentModel; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; +import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId; 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.prefab.PrefabCopyableComponent; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.universe.datastore.DataStoreProvider; @@ -110,15 +114,20 @@ 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; private ComponentType reachLocationMarkerComponentType; private ComponentType objectiveLocationMarkerComponentType; + @Nullable private ObjectiveDataStore objectiveDataStore; public static ObjectivePlugin get() { @@ -137,6 +146,7 @@ public class ObjectivePlugin extends JavaPlugin { return this.objectiveLocationMarkerModel; } + @Nullable public ObjectiveDataStore getObjectiveDataStore() { return this.objectiveDataStore; } @@ -144,6 +154,8 @@ public class ObjectivePlugin extends JavaPlugin { @Override protected void setup() { instance = this; + EventRegistry eventRegistry = this.getEventRegistry(); + ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); AssetRegistry.register( ((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder( ObjectiveAsset.class, new DefaultAssetMap() @@ -185,10 +197,10 @@ public class ObjectivePlugin extends JavaPlugin { .build() ); this.objectiveDataStore = new ObjectiveDataStore(this.config.get().getDataStoreProvider().create(Objective.CODEC)); - this.reachLocationMarkerComponentType = this.getEntityStoreRegistry() - .registerComponent(ReachLocationMarker.class, "ReachLocationMarker", ReachLocationMarker.CODEC); - this.objectiveLocationMarkerComponentType = this.getEntityStoreRegistry() - .registerComponent(ObjectiveLocationMarker.class, "ObjectiveLocation", ObjectiveLocationMarker.CODEC); + this.reachLocationMarkerComponentType = entityStoreRegistry.registerComponent(ReachLocationMarker.class, "ReachLocationMarker", ReachLocationMarker.CODEC); + this.objectiveLocationMarkerComponentType = entityStoreRegistry.registerComponent( + ObjectiveLocationMarker.class, "ObjectiveLocation", ObjectiveLocationMarker.CODEC + ); this.registerTask( "Craft", CraftObjectiveTaskAsset.class, CraftObjectiveTaskAsset.CODEC, CraftObjectiveTask.class, CraftObjectiveTask.CODEC, CraftObjectiveTask::new ); @@ -231,46 +243,64 @@ public class ObjectivePlugin extends JavaPlugin { this.registerCompletion( "ClearObjectiveItems", ClearObjectiveItemsCompletionAsset.class, ClearObjectiveItemsCompletionAsset.CODEC, ClearObjectiveItemsCompletion::new ); - this.getEventRegistry().register(LoadedAssetsEvent.class, ObjectiveLineAsset.class, this::onObjectiveLineAssetLoaded); - this.getEventRegistry().register(LoadedAssetsEvent.class, ObjectiveAsset.class, this::onObjectiveAssetLoaded); - this.getEventRegistry().register(PlayerDisconnectEvent.class, this::onPlayerDisconnect); - this.getEventRegistry().register(LoadedAssetsEvent.class, ObjectiveLocationMarkerAsset.class, ObjectivePlugin::onObjectiveLocationMarkerChange); - this.getEventRegistry().register(LoadedAssetsEvent.class, ModelAsset.class, this::onModelAssetChange); - this.getEventRegistry().registerGlobal(LivingEntityInventoryChangeEvent.class, this::onLivingEntityInventoryChange); - this.getEventRegistry().registerGlobal(AddWorldEvent.class, this::onWorldAdded); + eventRegistry.register(LoadedAssetsEvent.class, ObjectiveLineAsset.class, this::onObjectiveLineAssetLoaded); + eventRegistry.register(LoadedAssetsEvent.class, ObjectiveAsset.class, this::onObjectiveAssetLoaded); + eventRegistry.register(PlayerDisconnectEvent.class, this::onPlayerDisconnect); + eventRegistry.register(LoadedAssetsEvent.class, ObjectiveLocationMarkerAsset.class, ObjectivePlugin::onObjectiveLocationMarkerChange); + eventRegistry.register(LoadedAssetsEvent.class, ModelAsset.class, this::onModelAssetChange); + eventRegistry.registerGlobal(LivingEntityInventoryChangeEvent.class, this::onLivingEntityInventoryChange); + eventRegistry.registerGlobal(AddWorldEvent.class, this::onWorldAdded); this.getCommandRegistry().registerCommand(new ObjectiveCommand()); EntityModule entityModule = EntityModule.get(); ComponentType playerRefComponentType = PlayerRef.getComponentType(); ResourceType, EntityStore>> playerSpatialComponent = entityModule.getPlayerSpatialResourceType(); - this.getEntityStoreRegistry().registerSystem(new ReachLocationMarkerSystems.EntityAdded(this.reachLocationMarkerComponentType)); - this.getEntityStoreRegistry().registerSystem(new ReachLocationMarkerSystems.EnsureNetworkSendable()); - this.getEntityStoreRegistry().registerSystem(new ReachLocationMarkerSystems.Ticking(this.reachLocationMarkerComponentType, playerSpatialComponent)); - this.getEntityStoreRegistry().registerSystem(new ObjectiveLocationMarkerSystems.EnsureNetworkSendableSystem()); - this.getEntityStoreRegistry().registerSystem(new ObjectiveLocationMarkerSystems.InitSystem(this.objectiveLocationMarkerComponentType)); - this.getEntityStoreRegistry() - .registerSystem( - new ObjectiveLocationMarkerSystems.TickingSystem(this.objectiveLocationMarkerComponentType, playerRefComponentType, playerSpatialComponent) - ); + ComponentType networkIdComponentType = NetworkId.getComponentType(); + ComponentType transformComponentType = TransformComponent.getComponentType(); + ComponentType uuidComponentType = UUIDComponent.getComponentType(); + ComponentType weatherTrackerComponentType = WeatherTracker.getComponentType(); + ComponentType modelComponentType = ModelComponent.getComponentType(); + ComponentType prefabCopyableComponentType = PrefabCopyableComponent.getComponentType(); + entityStoreRegistry.registerSystem(new ReachLocationMarkerSystems.EntityAdded(this.reachLocationMarkerComponentType, transformComponentType)); + entityStoreRegistry.registerSystem(new ReachLocationMarkerSystems.EnsureNetworkSendable(this.reachLocationMarkerComponentType, networkIdComponentType)); + entityStoreRegistry.registerSystem( + new ReachLocationMarkerSystems.Ticking(this.reachLocationMarkerComponentType, playerSpatialComponent, transformComponentType, uuidComponentType) + ); + entityStoreRegistry.registerSystem( + new ObjectiveLocationMarkerSystems.EnsureNetworkSendableSystem(this.objectiveLocationMarkerComponentType, networkIdComponentType) + ); + entityStoreRegistry.registerSystem( + new ObjectiveLocationMarkerSystems.InitSystem( + this.objectiveLocationMarkerComponentType, modelComponentType, transformComponentType, prefabCopyableComponentType + ) + ); + entityStoreRegistry.registerSystem( + new ObjectiveLocationMarkerSystems.TickingSystem( + this.objectiveLocationMarkerComponentType, + playerRefComponentType, + playerSpatialComponent, + transformComponentType, + weatherTrackerComponentType, + uuidComponentType + ) + ); CommonObjectiveHistoryData.CODEC.register("Objective", ObjectiveHistoryData.class, ObjectiveHistoryData.CODEC); CommonObjectiveHistoryData.CODEC.register("ObjectiveLine", ObjectiveLineHistoryData.class, ObjectiveLineHistoryData.CODEC); ObjectiveRewardHistoryData.CODEC.register("Item", ItemObjectiveRewardHistoryData.class, ItemObjectiveRewardHistoryData.CODEC); - this.objectiveHistoryComponentType = this.getEntityStoreRegistry() - .registerComponent(ObjectiveHistoryComponent.class, "ObjectiveHistory", ObjectiveHistoryComponent.CODEC); - this.getEntityStoreRegistry().registerSystem(new ObjectivePlayerSetupSystem(this.objectiveHistoryComponentType, Player.getComponentType())); - this.getEntityStoreRegistry().registerSystem(new ObjectiveItemEntityRemovalSystem()); + this.objectiveHistoryComponentType = entityStoreRegistry.registerComponent( + ObjectiveHistoryComponent.class, "ObjectiveHistory", ObjectiveHistoryComponent.CODEC + ); + entityStoreRegistry.registerSystem(new ObjectivePlayerSetupSystem(this.objectiveHistoryComponentType, Player.getComponentType())); + entityStoreRegistry.registerSystem(new ObjectiveItemEntityRemovalSystem()); this.getCodecRegistry(Interaction.CODEC).register("StartObjective", StartObjectiveInteraction.class, StartObjectiveInteraction.CODEC); this.getCodecRegistry(Interaction.CODEC).register("CanBreakRespawnPoint", CanBreakRespawnPointInteraction.class, CanBreakRespawnPointInteraction.CODEC); BlockStateModule.get().registerBlockState(TreasureChestState.class, "TreasureChest", TreasureChestState.CODEC); this.getCodecRegistry(GameplayConfig.PLUGIN_CODEC).register(ObjectiveGameplayConfig.class, "Objective", ObjectiveGameplayConfig.CODEC); - this.getEntityStoreRegistry() - .registerSystem( - new EntityModule.TangibleMigrationSystem(Query.or(ObjectiveLocationMarker.getComponentType(), ReachLocationMarker.getComponentType())), true - ); - this.getEntityStoreRegistry() - .registerSystem( - new EntityModule.HiddenFromPlayerMigrationSystem(Query.or(ObjectiveLocationMarker.getComponentType(), ReachLocationMarker.getComponentType())), - true - ); + entityStoreRegistry.registerSystem( + new EntityModule.TangibleMigrationSystem(Query.or(ObjectiveLocationMarker.getComponentType(), ReachLocationMarker.getComponentType())), true + ); + entityStoreRegistry.registerSystem( + new EntityModule.HiddenFromPlayerMigrationSystem(Query.or(ObjectiveLocationMarker.getComponentType(), ReachLocationMarker.getComponentType())), true + ); } @Override @@ -280,13 +310,17 @@ public class ObjectivePlugin extends JavaPlugin { throw new IllegalStateException(String.format("Default objective location marker model '%s' not found", "Objective_Location_Marker")); } else { this.objectiveLocationMarkerModel = Model.createUnitScaleModel(modelAsset); - HytaleServer.SCHEDULED_EXECUTOR.scheduleWithFixedDelay(() -> this.objectiveDataStore.saveToDiskAllObjectives(), 5L, 5L, TimeUnit.MINUTES); + if (this.objectiveDataStore != null) { + HytaleServer.SCHEDULED_EXECUTOR.scheduleWithFixedDelay(() -> this.objectiveDataStore.saveToDiskAllObjectives(), 5L, 5L, TimeUnit.MINUTES); + } } } @Override protected void shutdown() { - this.objectiveDataStore.saveToDiskAllObjectives(); + if (this.objectiveDataStore != null) { + this.objectiveDataStore.saveToDiskAllObjectives(); + } } public ComponentType getReachLocationMarkerComponentType() { @@ -305,10 +339,12 @@ public class ObjectivePlugin extends JavaPlugin { Codec implementationCodec, TriFunction generator ) { - ObjectiveTaskAsset.CODEC.register(id, assetClass, assetCodec); - ObjectiveTask.CODEC.register(id, implementationClass, implementationCodec); - this.taskGenerators.put(assetClass, generator); - this.objectiveDataStore.registerTaskRef(implementationClass); + if (this.objectiveDataStore != null) { + ObjectiveTaskAsset.CODEC.register(id, assetClass, assetCodec); + ObjectiveTask.CODEC.register(id, implementationClass, implementationCodec); + this.taskGenerators.put(assetClass, generator); + this.objectiveDataStore.registerTaskRef(implementationClass); + } } public void registerCompletion( @@ -342,79 +378,90 @@ public class ObjectivePlugin extends JavaPlugin { @Nullable UUID markerUUID, @Nonnull Store store ) { - ObjectiveAsset asset = ObjectiveAsset.getAssetMap().getAsset(objectiveId); - if (asset == null) { - this.getLogger().at(Level.WARNING).log("Failed to find objective asset '%s'", objectiveId); - return null; - } else if (markerUUID == null && !asset.isValidForPlayer()) { - this.getLogger().at(Level.WARNING).log("Objective %s can't be used for Player", asset.getId()); + if (this.objectiveDataStore == null) { return null; } else { - Objective objective = new Objective(asset, objectiveUUID, playerUUIDs, worldUUID, markerUUID); - boolean setupResult = objective.setup(store); - Message assetTitleMessage = Message.translation(asset.getTitleKey()); - if (!setupResult || !this.objectiveDataStore.addObjective(objective.getObjectiveUUID(), objective)) { - this.getLogger().at(Level.WARNING).log("Failed to start objective %s", asset.getId()); - if (objective.getPlayerUUIDs() == null) { - return null; - } else { - objective.forEachParticipant(participantReference -> { - PlayerRef playerRefComponent = store.getComponent(participantReference, PlayerRef.getComponentType()); - if (playerRefComponent != null) { - playerRefComponent.sendMessage(Message.translation("server.modules.objective.start.failed").param("title", assetTitleMessage)); - } - }); - return null; - } - } else if (objective.getPlayerUUIDs() == null) { - return objective; + ObjectiveAsset asset = ObjectiveAsset.getAssetMap().getAsset(objectiveId); + if (asset == null) { + this.getLogger().at(Level.WARNING).log("Failed to find objective asset '%s'", objectiveId); + return null; + } else if (markerUUID == null && !asset.isValidForPlayer()) { + this.getLogger().at(Level.WARNING).log("Objective %s can't be used for Player", asset.getId()); + return null; } else { - TrackOrUpdateObjective trackObjectivePacket = new TrackOrUpdateObjective(objective.toPacket()); - String objectiveAssetId = asset.getId(); - objective.forEachParticipant(participantReference -> { - Player playerComponent = store.getComponent(participantReference, Player.getComponentType()); - if (playerComponent != null) { - if (!this.canPlayerDoObjective(playerComponent, objectiveAssetId)) { - playerComponent.sendMessage(Message.translation("server.modules.objective.playerAlreadyDoingObjective").param("title", assetTitleMessage)); - } else { + Objective objective = new Objective(asset, objectiveUUID, playerUUIDs, worldUUID, markerUUID); + boolean setupResult = objective.setup(store); + Message assetTitleMessage = Message.translation(asset.getTitleKey()); + if (!setupResult || !this.objectiveDataStore.addObjective(objective.getObjectiveUUID(), objective)) { + this.getLogger().at(Level.WARNING).log("Failed to start objective %s", asset.getId()); + if (objective.getPlayerUUIDs() == null) { + return null; + } else { + objective.forEachParticipant(participantReference -> { PlayerRef playerRefComponent = store.getComponent(participantReference, PlayerRef.getComponentType()); - - assert playerRefComponent != null; - - UUIDComponent uuidComponent = store.getComponent(participantReference, UUIDComponent.getComponentType()); - - assert uuidComponent != null; - - objective.addActivePlayerUUID(uuidComponent.getUuid()); - PlayerConfigData playerConfigData = playerComponent.getPlayerConfigData(); - HashSet activeObjectiveUUIDs = new HashSet<>(playerConfigData.getActiveObjectiveUUIDs()); - 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); - } + if (playerRefComponent != null) { + playerRefComponent.sendMessage(Message.translation("server.modules.objective.start.failed").param("title", assetTitleMessage)); + } + }); + return null; } - }); - objective.markDirty(); - return objective; + } else if (objective.getPlayerUUIDs() == null) { + return objective; + } else { + TrackOrUpdateObjective trackObjectivePacket = new TrackOrUpdateObjective(objective.toPacket()); + String objectiveAssetId = asset.getId(); + objective.forEachParticipant( + participantReference -> { + Player playerComponent = store.getComponent(participantReference, Player.getComponentType()); + if (playerComponent != null) { + if (!this.canPlayerDoObjective(playerComponent, objectiveAssetId)) { + playerComponent.sendMessage( + Message.translation("server.modules.objective.playerAlreadyDoingObjective").param("title", assetTitleMessage) + ); + } else { + PlayerRef playerRefComponent = store.getComponent(participantReference, PlayerRef.getComponentType()); + + assert playerRefComponent != null; + + UUIDComponent uuidComponent = store.getComponent(participantReference, UUIDComponent.getComponentType()); + + assert uuidComponent != null; + + objective.addActivePlayerUUID(uuidComponent.getUuid()); + PlayerConfigData playerConfigData = playerComponent.getPlayerConfigData(); + HashSet activeObjectiveUUIDs = new HashSet<>(playerConfigData.getActiveObjectiveUUIDs()); + activeObjectiveUUIDs.add(objective.getObjectiveUUID()); + playerConfigData.setActiveObjectiveUUIDs(activeObjectiveUUIDs); + playerRefComponent.sendMessage(Message.translation("server.modules.objective.start.success").param("title", assetTitleMessage)); + playerRefComponent.getPacketHandler().writeNoCache(trackObjectivePacket); + } + } + } + ); + objective.markDirty(); + return objective; + } } } } public boolean canPlayerDoObjective(@Nonnull Player player, @Nonnull String objectiveAssetId) { - Set activeObjectiveUUIDs = player.getPlayerConfigData().getActiveObjectiveUUIDs(); - if (activeObjectiveUUIDs == null) { - return true; + if (this.objectiveDataStore == null) { + return false; } else { - for (UUID objectiveUUID : activeObjectiveUUIDs) { - Objective objective = this.objectiveDataStore.getObjective(objectiveUUID); - if (objective != null && objective.getObjectiveId().equals(objectiveAssetId)) { - return false; + Set activeObjectiveUUIDs = player.getPlayerConfigData().getActiveObjectiveUUIDs(); + if (activeObjectiveUUIDs == null) { + return true; + } else { + for (UUID objectiveUUID : activeObjectiveUUIDs) { + Objective objective = this.objectiveDataStore.getObjective(objectiveUUID); + if (objective != null && objective.getObjectiveId().equals(objectiveAssetId)) { + return false; + } } - } - return true; + return true; + } } } @@ -469,56 +516,62 @@ public class ObjectivePlugin extends JavaPlugin { } public boolean canPlayerDoObjectiveLine(@Nonnull Player player, @Nonnull String objectiveLineId) { - Set activeObjectiveUUIDs = player.getPlayerConfigData().getActiveObjectiveUUIDs(); - if (activeObjectiveUUIDs == null) { - return true; + if (this.objectiveDataStore == null) { + return false; } else { - for (UUID objectiveUUID : activeObjectiveUUIDs) { - Objective objective = this.objectiveDataStore.getObjective(objectiveUUID); - if (objective != null) { - ObjectiveLineHistoryData objectiveLineHistoryData = objective.getObjectiveLineHistoryData(); - if (objectiveLineHistoryData != null && objectiveLineId.equals(objectiveLineHistoryData.getId())) { - return false; + Set activeObjectiveUUIDs = player.getPlayerConfigData().getActiveObjectiveUUIDs(); + if (activeObjectiveUUIDs == null) { + return true; + } else { + for (UUID objectiveUUID : activeObjectiveUUIDs) { + Objective objective = this.objectiveDataStore.getObjective(objectiveUUID); + if (objective != null) { + ObjectiveLineHistoryData objectiveLineHistoryData = objective.getObjectiveLineHistoryData(); + if (objectiveLineHistoryData != null && objectiveLineId.equals(objectiveLineHistoryData.getId())) { + return false; + } } } - } - return true; + return true; + } } } public void objectiveCompleted(@Nonnull Objective objective, @Nonnull Store store) { - for (UUID playerUUID : objective.getPlayerUUIDs()) { - this.untrackObjectiveForPlayer(objective, playerUUID); - } + if (this.objectiveDataStore != null) { + for (UUID playerUUID : objective.getPlayerUUIDs()) { + this.untrackObjectiveForPlayer(objective, playerUUID); + } - UUID objectiveUUID = objective.getObjectiveUUID(); - this.objectiveDataStore.removeObjective(objectiveUUID); - if (this.objectiveDataStore.removeFromDisk(objectiveUUID.toString())) { - ObjectiveLineAsset objectiveLineAsset = objective.getObjectiveLineAsset(); - if (objectiveLineAsset == null) { - this.storeObjectiveHistoryData(objective); - } else { - ObjectiveLineHistoryData objectiveLineHistoryData = objective.getObjectiveLineHistoryData(); - - assert objectiveLineHistoryData != null; - - objectiveLineHistoryData.addObjectiveHistoryData(objective.getObjectiveHistoryData()); - String nextObjectiveId = objectiveLineAsset.getNextObjectiveId(objective.getObjectiveId()); - if (nextObjectiveId != null) { - Objective newObjective = this.startObjective( - nextObjectiveId, objectiveUUID, objective.getPlayerUUIDs(), objective.getWorldUUID(), objective.getMarkerUUID(), store - ); - if (newObjective != null) { - newObjective.setObjectiveLineHistoryData(objectiveLineHistoryData); - newObjective.checkTaskSetCompletion(store); - } + UUID objectiveUUID = objective.getObjectiveUUID(); + this.objectiveDataStore.removeObjective(objectiveUUID); + if (this.objectiveDataStore.removeFromDisk(objectiveUUID.toString())) { + ObjectiveLineAsset objectiveLineAsset = objective.getObjectiveLineAsset(); + if (objectiveLineAsset == null) { + this.storeObjectiveHistoryData(objective); } else { - this.storeObjectiveLineHistoryData(objectiveLineHistoryData, objective.getPlayerUUIDs()); - String[] nextObjectiveLineIds = objectiveLineHistoryData.getNextObjectiveLineIds(); - if (nextObjectiveLineIds != null) { - for (String nextObjectiveLineId : nextObjectiveLineIds) { - this.startObjectiveLine(store, nextObjectiveLineId, objective.getPlayerUUIDs(), objective.getWorldUUID(), objective.getMarkerUUID()); + ObjectiveLineHistoryData objectiveLineHistoryData = objective.getObjectiveLineHistoryData(); + + assert objectiveLineHistoryData != null; + + objectiveLineHistoryData.addObjectiveHistoryData(objective.getObjectiveHistoryData()); + String nextObjectiveId = objectiveLineAsset.getNextObjectiveId(objective.getObjectiveId()); + if (nextObjectiveId != null) { + Objective newObjective = this.startObjective( + nextObjectiveId, objectiveUUID, objective.getPlayerUUIDs(), objective.getWorldUUID(), objective.getMarkerUUID(), store + ); + if (newObjective != null) { + newObjective.setObjectiveLineHistoryData(objectiveLineHistoryData); + newObjective.checkTaskSetCompletion(store); + } + } else { + this.storeObjectiveLineHistoryData(objectiveLineHistoryData, objective.getPlayerUUIDs()); + String[] nextObjectiveLineIds = objectiveLineHistoryData.getNextObjectiveLineIds(); + if (nextObjectiveLineIds != null) { + for (String nextObjectiveLineId : nextObjectiveLineIds) { + this.startObjectiveLine(store, nextObjectiveLineId, objective.getPlayerUUIDs(), objective.getWorldUUID(), objective.getMarkerUUID()); + } } } } @@ -587,118 +640,130 @@ public class ObjectivePlugin extends JavaPlugin { } public void cancelObjective(@Nonnull UUID objectiveUUID, @Nonnull Store store) { - Objective objective = this.objectiveDataStore.loadObjective(objectiveUUID, store); - if (objective != null) { - objective.cancel(); + if (this.objectiveDataStore != null) { + Objective objective = this.objectiveDataStore.loadObjective(objectiveUUID, store); + if (objective != null) { + objective.cancel(); - for (UUID playerUUID : objective.getPlayerUUIDs()) { - this.untrackObjectiveForPlayer(objective, playerUUID); + for (UUID playerUUID : objective.getPlayerUUIDs()) { + this.untrackObjectiveForPlayer(objective, playerUUID); + } + + this.objectiveDataStore.removeObjective(objectiveUUID); + this.objectiveDataStore.removeFromDisk(objectiveUUID.toString()); } - - this.objectiveDataStore.removeObjective(objectiveUUID); - this.objectiveDataStore.removeFromDisk(objectiveUUID.toString()); } } public void untrackObjectiveForPlayer(@Nonnull Objective objective, @Nonnull UUID playerUUID) { - UUID objectiveUUID = objective.getObjectiveUUID(); - ObjectiveTask[] currentTasks = objective.getCurrentTasks(); - - for (ObjectiveTask task : currentTasks) { - if (task instanceof UseEntityObjectiveTask) { - this.objectiveDataStore.removeEntityTaskForPlayer(objectiveUUID, ((UseEntityObjectiveTask)task).getAsset().getTaskId(), playerUUID); - } - } - - PlayerRef playerRef = Universe.get().getPlayer(playerUUID); - if (playerRef != null) { - Player player = playerRef.getComponent(Player.getComponentType()); - HashSet activeObjectiveUUIDs = new HashSet<>(player.getPlayerConfigData().getActiveObjectiveUUIDs()); - activeObjectiveUUIDs.remove(objectiveUUID); - player.getPlayerConfigData().setActiveObjectiveUUIDs(activeObjectiveUUIDs); - playerRef.getPacketHandler().writeNoCache(new UntrackObjective(objectiveUUID)); - } - } - - public void addPlayerToExistingObjective(@Nonnull Store store, @Nonnull UUID playerUUID, @Nonnull UUID objectiveUUID) { - Objective objective = this.objectiveDataStore.loadObjective(objectiveUUID, store); - if (objective != null) { - objective.addActivePlayerUUID(playerUUID); - ObjectiveDataStore objectiveDataStore = get().getObjectiveDataStore(); + if (this.objectiveDataStore != null) { + UUID objectiveUUID = objective.getObjectiveUUID(); ObjectiveTask[] currentTasks = objective.getCurrentTasks(); for (ObjectiveTask task : currentTasks) { - if (task instanceof UseEntityObjectiveTask) { - objectiveDataStore.addEntityTaskForPlayer(playerUUID, ((UseEntityObjectiveTask)task).getAsset().getTaskId(), objectiveUUID); + if (task instanceof UseEntityObjectiveTask useEntityObjectiveTask) { + this.objectiveDataStore.removeEntityTaskForPlayer(objectiveUUID, useEntityObjectiveTask.getAsset().getTaskId(), playerUUID); } } PlayerRef playerRef = Universe.get().getPlayer(playerUUID); - if (playerRef != null && playerRef.isValid()) { - Ref playerReference = playerRef.getReference(); - if (playerReference != null && playerReference.isValid()) { - Player playerComponent = store.getComponent(playerReference, Player.getComponentType()); + if (playerRef != null) { + Player player = playerRef.getComponent(Player.getComponentType()); + HashSet activeObjectiveUUIDs = new HashSet<>(player.getPlayerConfigData().getActiveObjectiveUUIDs()); + activeObjectiveUUIDs.remove(objectiveUUID); + player.getPlayerConfigData().setActiveObjectiveUUIDs(activeObjectiveUUIDs); + playerRef.getPacketHandler().writeNoCache(new UntrackObjective(objectiveUUID)); + } + } + } - assert playerComponent != null; + public void addPlayerToExistingObjective(@Nonnull Store store, @Nonnull UUID playerUUID, @Nonnull UUID objectiveUUID) { + if (this.objectiveDataStore != null) { + Objective objective = this.objectiveDataStore.loadObjective(objectiveUUID, store); + if (objective != null) { + objective.addActivePlayerUUID(playerUUID); + ObjectiveDataStore objectiveDataStore = get().getObjectiveDataStore(); + ObjectiveTask[] currentTasks = objective.getCurrentTasks(); - HashSet activeObjectiveUUIDs = new HashSet<>(playerComponent.getPlayerConfigData().getActiveObjectiveUUIDs()); - activeObjectiveUUIDs.add(objectiveUUID); - playerComponent.getPlayerConfigData().setActiveObjectiveUUIDs(activeObjectiveUUIDs); - playerRef.getPacketHandler().writeNoCache(new TrackOrUpdateObjective(objective.toPacket())); + for (ObjectiveTask task : currentTasks) { + if (task instanceof UseEntityObjectiveTask) { + objectiveDataStore.addEntityTaskForPlayer(playerUUID, ((UseEntityObjectiveTask)task).getAsset().getTaskId(), objectiveUUID); + } + } + + PlayerRef playerRef = Universe.get().getPlayer(playerUUID); + if (playerRef != null && playerRef.isValid()) { + Ref playerReference = playerRef.getReference(); + if (playerReference != null && playerReference.isValid()) { + Player playerComponent = store.getComponent(playerReference, Player.getComponentType()); + + assert playerComponent != null; + + HashSet activeObjectiveUUIDs = new HashSet<>(playerComponent.getPlayerConfigData().getActiveObjectiveUUIDs()); + activeObjectiveUUIDs.add(objectiveUUID); + playerComponent.getPlayerConfigData().setActiveObjectiveUUIDs(activeObjectiveUUIDs); + playerRef.getPacketHandler().writeNoCache(new TrackOrUpdateObjective(objective.toPacket())); + } } } } } public void removePlayerFromExistingObjective(@Nonnull Store store, @Nonnull UUID playerUUID, @Nonnull UUID objectiveUUID) { - Objective objective = this.objectiveDataStore.loadObjective(objectiveUUID, store); - if (objective != null) { - objective.removeActivePlayerUUID(playerUUID); - if (objective.getActivePlayerUUIDs().isEmpty()) { - this.objectiveDataStore.saveToDisk(objectiveUUID.toString(), objective); - this.objectiveDataStore.unloadObjective(objectiveUUID); - } + if (this.objectiveDataStore != null) { + Objective objective = this.objectiveDataStore.loadObjective(objectiveUUID, store); + if (objective != null) { + objective.removeActivePlayerUUID(playerUUID); + if (objective.getActivePlayerUUIDs().isEmpty()) { + this.objectiveDataStore.saveToDisk(objectiveUUID.toString(), objective); + this.objectiveDataStore.unloadObjective(objectiveUUID); + } - this.untrackObjectiveForPlayer(objective, playerUUID); + this.untrackObjectiveForPlayer(objective, playerUUID); + } } } private 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()) { - UUID playerUUID = playerRef.getUuid(); - this.getLogger().at(Level.INFO).log("Checking objectives for disconnecting player '" + playerRef.getUsername() + "' (" + playerUUID + ")"); - Player playerComponent = store.getComponent(ref, Player.getComponentType()); - if (playerComponent != null) { - Set activeObjectiveUUIDs = playerComponent.getPlayerConfigData().getActiveObjectiveUUIDs(); - if (activeObjectiveUUIDs == null) { - this.getLogger().at(Level.INFO).log("No active objectives found for player '" + playerRef.getUsername() + "' (" + playerUUID + ")"); - } else { - this.getLogger() - .at(Level.INFO) - .log("Processing " + activeObjectiveUUIDs.size() + " active objectives for '" + playerRef.getUsername() + "' (" + playerUUID + ")"); + if (this.objectiveDataStore != null) { + 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()) { + UUID playerUUID = playerRef.getUuid(); + this.getLogger().at(Level.INFO).log("Checking objectives for disconnecting player '" + playerRef.getUsername() + "' (" + playerUUID + ")"); + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + Set activeObjectiveUUIDs = playerComponent.getPlayerConfigData().getActiveObjectiveUUIDs(); + if (activeObjectiveUUIDs == null) { + this.getLogger().at(Level.INFO).log("No active objectives found for player '" + playerRef.getUsername() + "' (" + playerUUID + ")"); + } else { + this.getLogger() + .at(Level.INFO) + .log( + "Processing " + activeObjectiveUUIDs.size() + " active objectives for '" + playerRef.getUsername() + "' (" + playerUUID + ")" + ); - for (UUID objectiveUUID : activeObjectiveUUIDs) { - Objective objective = this.objectiveDataStore.getObjective(objectiveUUID); - if (objective != null) { - objective.removeActivePlayerUUID(playerUUID); - if (objective.getActivePlayerUUIDs().isEmpty()) { - this.objectiveDataStore.saveToDisk(objectiveUUID.toString(), objective); - this.objectiveDataStore.unloadObjective(objectiveUUID); + for (UUID objectiveUUID : activeObjectiveUUIDs) { + Objective objective = this.objectiveDataStore.getObjective(objectiveUUID); + if (objective != null) { + objective.removeActivePlayerUUID(playerUUID); + if (objective.getActivePlayerUUIDs().isEmpty()) { + this.objectiveDataStore.saveToDisk(objectiveUUID.toString(), objective); + this.objectiveDataStore.unloadObjective(objectiveUUID); + } } } } } } } - } - ); + ); + } } } @@ -728,7 +793,11 @@ public class ObjectivePlugin extends JavaPlugin { } private void onObjectiveAssetLoaded(@Nonnull LoadedAssetsEvent> event) { - this.objectiveDataStore.getObjectiveCollection().forEach(objective -> objective.reloadObjectiveAsset(event.getLoadedAssets())); + if (this.objectiveDataStore != null) { + for (Objective objective : this.objectiveDataStore.getObjectiveCollection()) { + objective.reloadObjectiveAsset(event.getLoadedAssets()); + } + } } private static void onObjectiveLocationMarkerChange( @@ -785,6 +854,8 @@ public class ObjectivePlugin extends JavaPlugin { oldModel.getGradientId(), oldModel.getEyeHeight(), oldModel.getCrouchOffset(), + oldModel.getSittingOffset(), + oldModel.getSleepingOffset(), oldModel.getAnimationSetMap(), oldModel.getCamera(), oldModel.getLight(), @@ -815,43 +886,47 @@ public class ObjectivePlugin extends JavaPlugin { } private void onLivingEntityInventoryChange(@Nonnull LivingEntityInventoryChangeEvent event) { - LivingEntity entity = event.getEntity(); - if (entity instanceof Player player) { - Set activeObjectiveUUIDs = player.getPlayerConfigData().getActiveObjectiveUUIDs(); - if (!activeObjectiveUUIDs.isEmpty()) { - Set inventoryItemObjectiveUUIDs = null; - CombinedItemContainer inventory = entity.getInventory().getCombinedHotbarFirst(); + if (this.objectiveDataStore != null) { + if (event.getEntity() instanceof Player player) { + Set activeObjectiveUUIDs = player.getPlayerConfigData().getActiveObjectiveUUIDs(); + if (!activeObjectiveUUIDs.isEmpty()) { + Set inventoryItemObjectiveUUIDs = null; + CombinedItemContainer inventory = player.getInventory().getCombinedHotbarFirst(); - for (short i = 0; i < inventory.getCapacity(); i++) { - ItemStack itemStack = inventory.getItemStack(i); - if (!ItemStack.isEmpty(itemStack)) { - UUID objectiveUUID = itemStack.getFromMetadataOrNull(StartObjectiveInteraction.OBJECTIVE_UUID); - if (objectiveUUID != null) { - if (inventoryItemObjectiveUUIDs == null) { - inventoryItemObjectiveUUIDs = new HashSet<>(activeObjectiveUUIDs); + for (short i = 0; i < inventory.getCapacity(); i++) { + ItemStack itemStack = inventory.getItemStack(i); + if (!ItemStack.isEmpty(itemStack)) { + UUID objectiveUUID = itemStack.getFromMetadataOrNull(StartObjectiveInteraction.OBJECTIVE_UUID); + if (objectiveUUID != null) { + if (inventoryItemObjectiveUUIDs == null) { + inventoryItemObjectiveUUIDs = new HashSet<>(activeObjectiveUUIDs); + } + + inventoryItemObjectiveUUIDs.add(objectiveUUID); } - - inventoryItemObjectiveUUIDs.add(objectiveUUID); } } - } - for (UUID activeObjectiveUUID : activeObjectiveUUIDs) { - if (inventoryItemObjectiveUUIDs == null || !inventoryItemObjectiveUUIDs.contains(activeObjectiveUUID)) { - Objective objective = this.objectiveDataStore.getObjective(activeObjectiveUUID); - if (objective != null) { - ObjectiveAsset objectiveAsset = objective.getObjectiveAsset(); - if (objectiveAsset != null && objectiveAsset.isRemoveOnItemDrop()) { - Ref reference = entity.getReference(); - Store store = reference.getStore(); - World world = store.getExternalData().getWorld(); - world.execute(() -> { - UUIDComponent uuidComponent = store.getComponent(reference, UUIDComponent.getComponentType()); + Ref reference = player.getReference(); + if (reference != null && reference.isValid()) { + Store store = reference.getStore(); + World world = store.getExternalData().getWorld(); - assert uuidComponent != null; + for (UUID activeObjectiveUUID : activeObjectiveUUIDs) { + if (inventoryItemObjectiveUUIDs == null || !inventoryItemObjectiveUUIDs.contains(activeObjectiveUUID)) { + Objective objective = this.objectiveDataStore.getObjective(activeObjectiveUUID); + if (objective != null) { + ObjectiveAsset objectiveAsset = objective.getObjectiveAsset(); + if (objectiveAsset != null && objectiveAsset.isRemoveOnItemDrop()) { + world.execute(() -> { + UUIDComponent uuidComponent = store.getComponent(reference, UUIDComponent.getComponentType()); - get().removePlayerFromExistingObjective(store, uuidComponent.getUuid(), activeObjectiveUUID); - }); + assert uuidComponent != null; + + get().removePlayerFromExistingObjective(store, uuidComponent.getUuid(), activeObjectiveUUID); + }); + } + } } } } @@ -860,33 +935,37 @@ public class ObjectivePlugin extends JavaPlugin { } } - private void onWorldAdded(AddWorldEvent event) { + private void onWorldAdded(@Nonnull AddWorldEvent event) { event.getWorld().getWorldMapManager().addMarkerProvider("objectives", ObjectiveMarkerProvider.INSTANCE); } @Nonnull public String getObjectiveDataDump() { StringBuilder sb = new StringBuilder("Objective Data\n"); - - for (Objective objective : this.objectiveDataStore.getObjectiveCollection()) { - sb.append("Objective ID: ") - .append(objective.getObjectiveId()) - .append("\n\t") - .append("UUID: ") - .append(objective.getObjectiveUUID()) - .append("\n\t") - .append("Players: ") - .append(Arrays.toString(objective.getPlayerUUIDs().toArray())) - .append("\n\t") - .append("Active players: ") - .append(Arrays.toString(objective.getActivePlayerUUIDs().toArray())) - .append("\n\n"); + if (this.objectiveDataStore != null) { + for (Objective objective : this.objectiveDataStore.getObjectiveCollection()) { + sb.append("Objective ID: ") + .append(objective.getObjectiveId()) + .append("\n\t") + .append("UUID: ") + .append(objective.getObjectiveUUID()) + .append("\n\t") + .append("Players: ") + .append(Arrays.toString(objective.getPlayerUUIDs().toArray())) + .append("\n\t") + .append("Active players: ") + .append(Arrays.toString(objective.getActivePlayerUUIDs().toArray())) + .append("\n\n"); + } + } else { + sb.append("Objective data store is not initialized.\n"); } return sb.toString(); } 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/ObjectiveCompleteCommand.java b/src/com/hypixel/hytale/builtin/adventure/objectives/commands/ObjectiveCompleteCommand.java index e48b11f7..264c24a0 100644 --- a/src/com/hypixel/hytale/builtin/adventure/objectives/commands/ObjectiveCompleteCommand.java +++ b/src/com/hypixel/hytale/builtin/adventure/objectives/commands/ObjectiveCompleteCommand.java @@ -76,7 +76,7 @@ public class ObjectiveCompleteCommand extends AbstractCommandCollection { String objectiveId = this.objectiveArg.get(context); Objective objective = ObjectiveCompleteCommand.getObjectiveFromId(ref, objectiveId, store); if (objective == null) { - context.sendMessage(ObjectiveCompleteCommand.MESSAGE_COMMANDS_OBJECTIVE_OBJECTIVE_NOT_FOUND); + context.sendMessage(ObjectiveCompleteCommand.MESSAGE_COMMANDS_OBJECTIVE_OBJECTIVE_NOT_FOUND.param("id", objectiveId)); } else { ObjectiveTask[] tasks = objective.getCurrentTasks(); if (tasks == null) { @@ -114,7 +114,7 @@ public class ObjectiveCompleteCommand extends AbstractCommandCollection { int taskIndex = this.taskIndexArg.get(context); Objective objective = ObjectiveCompleteCommand.getObjectiveFromId(ref, objectiveId, store); if (objective == null) { - context.sendMessage(ObjectiveCompleteCommand.MESSAGE_COMMANDS_OBJECTIVE_OBJECTIVE_NOT_FOUND); + context.sendMessage(ObjectiveCompleteCommand.MESSAGE_COMMANDS_OBJECTIVE_OBJECTIVE_NOT_FOUND.param("id", objectiveId)); } else { ObjectiveTask[] tasks = objective.getCurrentTasks(); if (taskIndex >= tasks.length) { @@ -146,7 +146,7 @@ public class ObjectiveCompleteCommand extends AbstractCommandCollection { String objectiveId = this.objectiveArg.get(context); Objective objective = ObjectiveCompleteCommand.getObjectiveFromId(ref, objectiveId, store); if (objective == null) { - context.sendMessage(ObjectiveCompleteCommand.MESSAGE_COMMANDS_OBJECTIVE_OBJECTIVE_NOT_FOUND); + context.sendMessage(ObjectiveCompleteCommand.MESSAGE_COMMANDS_OBJECTIVE_OBJECTIVE_NOT_FOUND.param("id", objectiveId)); } else { ObjectiveTask[] tasks = objective.getCurrentTasks(); if (tasks != null && tasks.length != 0) { 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..ed0f426b 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 @@ -57,11 +57,21 @@ import javax.annotation.Nullable; public class ObjectiveLocationMarkerSystems { public static class EnsureNetworkSendableSystem extends HolderSystem { @Nonnull - private final Query query = Query.and(ObjectiveLocationMarker.getComponentType(), Query.not(NetworkId.getComponentType())); + private final ComponentType networkIdComponentType; + @Nonnull + private final Query query; + + public EnsureNetworkSendableSystem( + @Nonnull ComponentType objectiveLocationMarkerComponentType, + @Nonnull ComponentType networkIdComponentType + ) { + this.networkIdComponentType = networkIdComponentType; + this.query = Query.and(objectiveLocationMarkerComponentType, Query.not(networkIdComponentType)); + } @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - holder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId())); + holder.addComponent(this.networkIdComponentType, new NetworkId(store.getExternalData().takeNextNetworkId())); } @Override @@ -83,13 +93,21 @@ public class ObjectiveLocationMarkerSystems { @Nonnull private final ComponentType transformComponentType; @Nonnull + private final ComponentType prefabCopyableComponentType; + @Nonnull private final Query query; - public InitSystem(@Nonnull ComponentType objectiveLocationMarkerComponent) { + public InitSystem( + @Nonnull ComponentType objectiveLocationMarkerComponent, + @Nonnull ComponentType modelComponentType, + @Nonnull ComponentType transformComponentType, + @Nonnull ComponentType prefabCopyableComponentType + ) { this.objectiveLocationMarkerComponent = objectiveLocationMarkerComponent; - this.modelComponentType = ModelComponent.getComponentType(); - this.transformComponentType = TransformComponent.getComponentType(); - this.query = Query.and(objectiveLocationMarkerComponent, this.modelComponentType, this.transformComponentType); + this.modelComponentType = modelComponentType; + this.transformComponentType = transformComponentType; + this.prefabCopyableComponentType = prefabCopyableComponentType; + this.query = Query.and(objectiveLocationMarkerComponent, modelComponentType, transformComponentType); } @Nonnull @@ -159,6 +177,8 @@ public class ObjectiveLocationMarkerSystems { model.getGradientId(), model.getEyeHeight(), model.getCrouchOffset(), + model.getSittingOffset(), + model.getSleepingOffset(), model.getAnimationSetMap(), model.getCamera(), model.getLight(), @@ -171,7 +191,7 @@ public class ObjectiveLocationMarkerSystems { ) ) ); - commandBuffer.ensureComponent(ref, PrefabCopyableComponent.getComponentType()); + commandBuffer.ensureComponent(ref, this.prefabCopyableComponentType); } } @@ -201,11 +221,11 @@ public class ObjectiveLocationMarkerSystems { @Nonnull private final ComponentType playerRefComponentType; @Nonnull - private final ComponentType transformComponentType = TransformComponent.getComponentType(); + private final ComponentType transformComponentType; @Nonnull - private final ComponentType weatherTrackerComponentType = WeatherTracker.getComponentType(); + private final ComponentType weatherTrackerComponentType; @Nonnull - private final ComponentType uuidComponentType = UUIDComponent.getComponentType(); + private final ComponentType uuidComponentType; @Nonnull private final ResourceType, EntityStore>> playerSpatialComponent; @Nonnull @@ -216,12 +236,18 @@ public class ObjectiveLocationMarkerSystems { public TickingSystem( @Nonnull ComponentType objectiveLocationMarkerComponentType, @Nonnull ComponentType playerRefComponentType, - @Nonnull ResourceType, EntityStore>> playerSpatialComponent + @Nonnull ResourceType, EntityStore>> playerSpatialComponent, + @Nonnull ComponentType transformComponentType, + @Nonnull ComponentType weatherTrackerComponentType, + @Nonnull ComponentType uuidComponentType ) { this.objectiveLocationMarkerComponentType = objectiveLocationMarkerComponentType; this.playerRefComponentType = playerRefComponentType; + this.transformComponentType = transformComponentType; + this.weatherTrackerComponentType = weatherTrackerComponentType; + this.uuidComponentType = uuidComponentType; this.playerSpatialComponent = playerSpatialComponent; - this.query = Archetype.of(objectiveLocationMarkerComponentType, this.transformComponentType, this.uuidComponentType); + this.query = Archetype.of(objectiveLocationMarkerComponentType, transformComponentType, uuidComponentType); this.dependencies = Set.of(new SystemDependency<>(Order.AFTER, PlayerSpatialSystem.class, OrderPriority.CLOSEST)); } @@ -278,33 +304,30 @@ public class ObjectiveLocationMarkerSystems { this.setupMarker(store, objectiveLocationMarkerComponent, entityReference, position, uuid, commandBuffer); } else if (!activeObjective.isCompleted()) { SpatialResource, EntityStore> spatialResource = store.getResource(this.playerSpatialComponent); - ObjectList> playerReferences = SpatialResource.getThreadLocalReferenceList(); - objectiveLocationMarkerComponent.area.getPlayersInExitArea(spatialResource, playerReferences, position); - HashSet playersInExitArea = new HashSet<>(playerReferences.size()); - PlayerRef[] playersInEntryArea = new PlayerRef[playerReferences.size()]; + ObjectList> playerRefs = SpatialResource.getThreadLocalReferenceList(); + objectiveLocationMarkerComponent.area.getPlayersInExitArea(spatialResource, playerRefs, position); + HashSet playersInExitArea = new HashSet<>(playerRefs.size()); + PlayerRef[] playersInEntryArea = new PlayerRef[playerRefs.size()]; int playersInEntryAreaSize = 0; - 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; + for (Ref playerRef : playerRefs) { + PlayerRef playerRefComponent = commandBuffer.getComponent(playerRef, this.playerRefComponentType); + if (playerRefComponent != null) { + UUIDComponent playerUuidComponent = commandBuffer.getComponent(playerRef, this.uuidComponentType); + if (playerUuidComponent != null) { + TransformComponent playerTransformComponent = commandBuffer.getComponent(playerRef, this.transformComponentType); + if (playerTransformComponent != null) { + WeatherTracker playerWeatherTrackerComponent = commandBuffer.getComponent(playerRef, this.weatherTrackerComponentType); + if (playerWeatherTrackerComponent != null + && isPlayerInSpecificEnvironment( + objectiveLocationMarkerComponent, playerWeatherTrackerComponent, playerTransformComponent, commandBuffer + )) { + playersInExitArea.add(playerUuidComponent.getUuid()); + if (objectiveLocationMarkerComponent.area.isPlayerInEntryArea(playerTransformComponent.getPosition(), position)) { + playersInEntryArea[playersInEntryAreaSize++] = playerRefComponent; + } + } + } } } } @@ -440,13 +463,13 @@ public class ObjectiveLocationMarkerSystems { private static boolean isPlayerInSpecificEnvironment( @Nonnull ObjectiveLocationMarker entity, @Nonnull WeatherTracker weatherTracker, - @Nonnull TransformComponent transform, + @Nonnull TransformComponent transformComponent, @Nonnull ComponentAccessor componentAccessor ) { if (entity.environmentIndexes == null) { return true; } else { - weatherTracker.updateEnvironment(transform, componentAccessor); + weatherTracker.updateEnvironment(transformComponent, componentAccessor); int environmentIndex = weatherTracker.getEnvironmentId(); return Arrays.binarySearch(entity.environmentIndexes, environmentIndex) >= 0; } @@ -456,8 +479,8 @@ public class ObjectiveLocationMarkerSystems { ObjectiveDataStore objectiveDataStore = ObjectivePlugin.get().getObjectiveDataStore(); for (ObjectiveTask task : entity.getActiveObjective().getCurrentTasks()) { - if (task instanceof UseEntityObjectiveTask) { - String taskId = ((UseEntityObjectiveTask)task).getAsset().getTaskId(); + if (task instanceof UseEntityObjectiveTask useEntityObjectiveTask) { + String taskId = useEntityObjectiveTask.getAsset().getTaskId(); objectiveDataStore.removeEntityTaskForPlayer(entity.activeObjectiveUUID, taskId, playerUUID); } } 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..b9cf40d2 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,15 +38,29 @@ 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 { - private final Query query = Query.and(ReachLocationMarker.getComponentType(), Query.not(NetworkId.getComponentType())); + @Nonnull + private final ComponentType networkIdComponentType; + @Nonnull + private final Query query; + + public EnsureNetworkSendable( + @Nonnull ComponentType reachLocationMarkerComponentType, + @Nonnull ComponentType networkIdComponentType + ) { + this.networkIdComponentType = networkIdComponentType; + this.query = Query.and(reachLocationMarkerComponentType, Query.not(networkIdComponentType)); + } @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - holder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId())); + int nextNetworkId = store.getExternalData().takeNextNetworkId(); + holder.addComponent(this.networkIdComponentType, new NetworkId(nextNetworkId)); } @Override @@ -61,15 +75,20 @@ public class ReachLocationMarkerSystems { } public static class EntityAdded extends RefSystem { + @Nonnull private final ComponentType reachLocationMarkerComponent; + @Nonnull private final ComponentType transformComponentType; @Nonnull private final Query query; - public EntityAdded(ComponentType reachLocationMarkerComponent) { + public EntityAdded( + @Nonnull ComponentType reachLocationMarkerComponent, + @Nonnull ComponentType transformComponentType + ) { this.reachLocationMarkerComponent = reachLocationMarkerComponent; - this.transformComponentType = TransformComponent.getComponentType(); - this.query = Query.and(reachLocationMarkerComponent, this.transformComponentType); + this.transformComponentType = transformComponentType; + this.query = Query.and(reachLocationMarkerComponent, transformComponentType); } @Nonnull @@ -109,23 +128,30 @@ public class ReachLocationMarkerSystems { } public static class Ticking extends EntityTickingSystem { + @Nonnull private final ComponentType reachLocationMarkerComponent; + @Nonnull private final ComponentType transformComponentType; + @Nonnull private final ResourceType, EntityStore>> playerSpatialComponent; - private final ComponentType uuidComponentType = UUIDComponent.getComponentType(); + @Nonnull + private final ComponentType uuidComponentType; @Nonnull private final Query query; @Nonnull private final Set> dependencies; public Ticking( - ComponentType reachLocationMarkerComponent, - ResourceType, EntityStore>> playerSpatialComponent + @Nonnull ComponentType reachLocationMarkerComponent, + @Nonnull ResourceType, EntityStore>> playerSpatialComponent, + @Nonnull ComponentType transformComponentType, + @Nonnull ComponentType uuidComponentType ) { this.reachLocationMarkerComponent = reachLocationMarkerComponent; - this.transformComponentType = TransformComponent.getComponentType(); + this.transformComponentType = transformComponentType; + this.uuidComponentType = uuidComponentType; this.playerSpatialComponent = playerSpatialComponent; - this.query = Query.and(reachLocationMarkerComponent, this.transformComponentType); + this.query = Query.and(reachLocationMarkerComponent, transformComponentType); this.dependencies = Set.of(new SystemDependency<>(Order.AFTER, PlayerSpatialSystem.class, OrderPriority.CLOSEST)); } @@ -184,16 +210,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..55f29570 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(); @@ -264,7 +242,7 @@ public abstract class ObjectiveTask implements NetworkSerializer 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/stash/StashGameplayConfig.java b/src/com/hypixel/hytale/builtin/adventure/stash/StashGameplayConfig.java index 0492443a..4bf9ec21 100644 --- a/src/com/hypixel/hytale/builtin/adventure/stash/StashGameplayConfig.java +++ b/src/com/hypixel/hytale/builtin/adventure/stash/StashGameplayConfig.java @@ -8,7 +8,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class StashGameplayConfig { + @Nonnull public static final String ID = "Stash"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(StashGameplayConfig.class, StashGameplayConfig::new) .appendInherited( new KeyedCodec<>("ClearContainerDropList", Codec.BOOLEAN), diff --git a/src/com/hypixel/hytale/builtin/adventure/stash/StashPlugin.java b/src/com/hypixel/hytale/builtin/adventure/stash/StashPlugin.java index 150b2d61..aac5b86a 100644 --- a/src/com/hypixel/hytale/builtin/adventure/stash/StashPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/stash/StashPlugin.java @@ -38,6 +38,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class StashPlugin extends JavaPlugin { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public StashPlugin(@Nonnull JavaPluginInit init) { @@ -95,18 +96,19 @@ public class StashPlugin extends JavaPlugin { } private static class StashSystem extends RefSystem { - private final ComponentType componentType; + @Nonnull + private final ComponentType itemContainerStateComponentType; @Nonnull private final Set> dependencies; - public StashSystem(ComponentType componentType) { - this.componentType = componentType; + public StashSystem(@Nonnull ComponentType itemContainerStateComponentType) { + this.itemContainerStateComponentType = itemContainerStateComponentType; this.dependencies = Set.of(new SystemDependency<>(Order.AFTER, BlockStateModule.LegacyBlockStateRefSystem.class)); } @Override public Query getQuery() { - return this.componentType; + return this.itemContainerStateComponentType; } @Override @@ -115,9 +117,13 @@ public class StashPlugin extends JavaPlugin { ) { World world = store.getExternalData().getWorld(); if (world.getWorldConfig().getGameMode() != GameMode.Creative) { + ItemContainerState itemContainerStateComponent = store.getComponent(ref, this.itemContainerStateComponentType); + + assert itemContainerStateComponent != null; + StashGameplayConfig stashGameplayConfig = StashGameplayConfig.getOrDefault(world.getGameplayConfig()); boolean clearContainerDropList = stashGameplayConfig.isClearContainerDropList(); - StashPlugin.stash(store.getComponent(ref, this.componentType), clearContainerDropList); + StashPlugin.stash(itemContainerStateComponent, clearContainerDropList); } } diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/TeleporterPlugin.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/TeleporterPlugin.java index 1c2a55db..c019b288 100644 --- a/src/com/hypixel/hytale/builtin/adventure/teleporter/TeleporterPlugin.java +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/TeleporterPlugin.java @@ -6,9 +6,11 @@ import com.hypixel.hytale.builtin.adventure.teleporter.interaction.server.UsedTe import com.hypixel.hytale.builtin.adventure.teleporter.page.TeleporterSettingsPageSupplier; import com.hypixel.hytale.builtin.adventure.teleporter.system.ClearUsedTeleporterSystem; import com.hypixel.hytale.builtin.adventure.teleporter.system.CreateWarpWhenTeleporterPlacedSystem; +import com.hypixel.hytale.builtin.adventure.teleporter.system.TurnOffTeleportersSystem; import com.hypixel.hytale.builtin.teleport.TeleportPlugin; import com.hypixel.hytale.component.AddReason; import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.RemoveReason; @@ -16,10 +18,17 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.RefSystem; +import com.hypixel.hytale.server.core.modules.block.BlockModule; +import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; +import com.hypixel.hytale.server.core.modules.entity.teleport.PendingTeleport; +import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport; +import com.hypixel.hytale.server.core.modules.entity.teleport.TeleportRecord; +import com.hypixel.hytale.server.core.modules.interaction.components.PlacedByInteractionComponent; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction; 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.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; @@ -41,12 +50,31 @@ public class TeleporterPlugin extends JavaPlugin { @Override protected void setup() { - this.teleporterComponentType = this.getChunkStoreRegistry().registerComponent(Teleporter.class, "Teleporter", Teleporter.CODEC); - this.getChunkStoreRegistry().registerSystem(new TeleporterPlugin.TeleporterOwnedWarpRefChangeSystem()); - this.getChunkStoreRegistry().registerSystem(new TeleporterPlugin.TeleporterOwnedWarpRefSystem()); - this.getChunkStoreRegistry().registerSystem(new CreateWarpWhenTeleporterPlacedSystem()); - this.usedTeleporterComponentType = this.getEntityStoreRegistry().registerComponent(UsedTeleporter.class, UsedTeleporter::new); - this.getEntityStoreRegistry().registerSystem(new ClearUsedTeleporterSystem()); + ComponentRegistryProxy chunkStoreRegistry = this.getChunkStoreRegistry(); + ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); + this.teleporterComponentType = chunkStoreRegistry.registerComponent(Teleporter.class, "Teleporter", Teleporter.CODEC); + ComponentType placedByInteractionComponentType = PlacedByInteractionComponent.getComponentType(); + ComponentType blockStateInfoComponentType = BlockModule.BlockStateInfo.getComponentType(); + ComponentType playerRefComponentType = PlayerRef.getComponentType(); + ComponentType transformComponentType = TransformComponent.getComponentType(); + ComponentType teleportRecordComponentType = TeleportRecord.getComponentType(); + ComponentType teleportComponentType = Teleport.getComponentType(); + ComponentType pendingTeleportComponentType = PendingTeleport.getComponentType(); + chunkStoreRegistry.registerSystem(new TeleporterPlugin.TeleporterOwnedWarpRefChangeSystem(this.teleporterComponentType)); + chunkStoreRegistry.registerSystem(new TeleporterPlugin.TeleporterOwnedWarpRefSystem(this.teleporterComponentType)); + chunkStoreRegistry.registerSystem(new TurnOffTeleportersSystem()); + this.getChunkStoreRegistry() + .registerSystem( + new CreateWarpWhenTeleporterPlacedSystem( + placedByInteractionComponentType, this.teleporterComponentType, blockStateInfoComponentType, playerRefComponentType + ) + ); + this.usedTeleporterComponentType = entityStoreRegistry.registerComponent(UsedTeleporter.class, UsedTeleporter::new); + entityStoreRegistry.registerSystem( + new ClearUsedTeleporterSystem( + this.usedTeleporterComponentType, transformComponentType, teleportRecordComponentType, teleportComponentType, pendingTeleportComponentType + ) + ); this.getCodecRegistry(Interaction.CODEC).register("Teleporter", TeleporterInteraction.class, TeleporterInteraction.CODEC); this.getCodecRegistry(OpenCustomUIInteraction.PAGE_CODEC) .register("Teleporter", TeleporterSettingsPageSupplier.class, TeleporterSettingsPageSupplier.CODEC); @@ -61,10 +89,17 @@ public class TeleporterPlugin extends JavaPlugin { } private static class TeleporterOwnedWarpRefChangeSystem extends RefChangeSystem { + @Nonnull + private final ComponentType teleporterComponentType; + + public TeleporterOwnedWarpRefChangeSystem(@Nonnull ComponentType teleporterComponentType) { + this.teleporterComponentType = teleporterComponentType; + } + @Nonnull @Override public ComponentType componentType() { - return Teleporter.getComponentType(); + return this.teleporterComponentType; } public void onComponentAdded( @@ -79,11 +114,13 @@ public class TeleporterPlugin extends JavaPlugin { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - String ownedWarp = oldComponent.getOwnedWarp(); - if (ownedWarp != null && !ownedWarp.isEmpty() && !ownedWarp.equals(newComponent.getOwnedWarp())) { - TeleportPlugin.get().getWarps().remove(ownedWarp.toLowerCase()); - TeleportPlugin.get().saveWarps(); - oldComponent.setOwnedWarp(null); + if (oldComponent != null) { + String ownedWarp = oldComponent.getOwnedWarp(); + if (ownedWarp != null && !ownedWarp.isEmpty() && !ownedWarp.equals(newComponent.getOwnedWarp())) { + TeleportPlugin.get().getWarps().remove(ownedWarp.toLowerCase()); + TeleportPlugin.get().saveWarps(); + oldComponent.setOwnedWarp(null); + } } } @@ -106,20 +143,17 @@ public class TeleporterPlugin extends JavaPlugin { } private static class TeleporterOwnedWarpRefSystem extends RefSystem { - public static final ComponentType COMPONENT_TYPE = Teleporter.getComponentType(); + @Nonnull + private final ComponentType teleporterComponentType; + + public TeleporterOwnedWarpRefSystem(@Nonnull ComponentType teleporterComponentType) { + this.teleporterComponentType = teleporterComponentType; + } @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - switch (reason) { - case LOAD: - Teleporter component = commandBuffer.getComponent(ref, COMPONENT_TYPE); - String ownedWarp = component.getOwnedWarp(); - if (ownedWarp != null && !ownedWarp.isEmpty() && !TeleportPlugin.get().getWarps().containsKey(ownedWarp.toLowerCase())) { - } - case SPAWN: - } } @Override @@ -127,19 +161,24 @@ public class TeleporterPlugin extends JavaPlugin { @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { if (reason == RemoveReason.REMOVE) { - Teleporter component = commandBuffer.getComponent(ref, COMPONENT_TYPE); - String ownedWarp = component.getOwnedWarp(); + Teleporter teleporterComponent = commandBuffer.getComponent(ref, this.teleporterComponentType); + if (teleporterComponent == null) { + return; + } + + String ownedWarp = teleporterComponent.getOwnedWarp(); if (ownedWarp != null && !ownedWarp.isEmpty()) { TeleportPlugin.get().getWarps().remove(ownedWarp.toLowerCase()); TeleportPlugin.get().saveWarps(); - component.setOwnedWarp(null); + teleporterComponent.setOwnedWarp(null); } } } + @Nonnull @Override public Query getQuery() { - return COMPONENT_TYPE; + return this.teleporterComponentType; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/component/Teleporter.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/component/Teleporter.java index 86cc8ff1..18dea2c1 100644 --- a/src/com/hypixel/hytale/builtin/adventure/teleporter/component/Teleporter.java +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/component/Teleporter.java @@ -22,6 +22,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class Teleporter implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(Teleporter.class, Teleporter::new) .append(new KeyedCodec<>("World", Codec.UUID_BINARY), (teleporter, uuid) -> teleporter.worldUuid = uuid, teleporter -> teleporter.worldUuid) .add() @@ -43,6 +44,8 @@ public class Teleporter implements Component { .documentation("The ID of the Word list to select default warp names from") .add() .build(); + public static final String ACTIVATE_STATE = "Active"; + public static final String INACTIVE_STATE = "default"; @Nullable private UUID worldUuid; @Nullable @@ -51,6 +54,7 @@ public class Teleporter implements Component { @Nullable private String warp; @Deprecated + @Nullable private String ownedWarp; private boolean isCustomName; private String warpNameWordListKey; @@ -94,11 +98,12 @@ public class Teleporter implements Component { this.warp = warp != null && !warp.isEmpty() ? warp : null; } + @Nullable public String getOwnedWarp() { return this.ownedWarp; } - public void setOwnedWarp(String ownedWarp) { + public void setOwnedWarp(@Nullable String ownedWarp) { this.ownedWarp = ownedWarp; } 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..801be16b 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 @@ -12,6 +12,7 @@ import com.hypixel.hytale.component.spatial.SpatialResource; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3i; +import com.hypixel.hytale.protocol.InteractionState; import com.hypixel.hytale.protocol.InteractionType; import com.hypixel.hytale.protocol.WaitForDataFrom; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; @@ -23,7 +24,6 @@ import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entity.teleport.PendingTeleport; import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport; -import com.hypixel.hytale.server.core.modules.entity.teleport.TeleportRecord; import com.hypixel.hytale.server.core.modules.interaction.interaction.CooldownHandler; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.client.SimpleBlockInteraction; import com.hypixel.hytale.server.core.universe.world.ParticleUtil; @@ -33,7 +33,6 @@ 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.storage.EntityStore; import it.unimi.dsi.fastutil.objects.ObjectList; -import java.time.Duration; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -69,7 +68,6 @@ public class TeleporterInteraction extends SimpleBlockInteraction { .documentation("Upon reaching the warp destination, how far away one has to move along the Y axis in order to use another Teleporter.") .add() .build(); - private static final Duration TELEPORTER_GLOBAL_COOLDOWN = Duration.ofMillis(100L); @Nullable private String particle; private double clearoutXZ = 1.3; @@ -90,67 +88,95 @@ public class TeleporterInteraction extends SimpleBlockInteraction { @Nullable ItemStack itemInHand, @Nonnull Vector3i targetBlock, @Nonnull CooldownHandler cooldownHandler + ) { + boolean result = this.interact(world, commandBuffer, context, targetBlock); + if (!result) { + context.getState().state = InteractionState.Failed; + } + } + + private boolean interact( + @Nonnull World world, @Nonnull CommandBuffer commandBuffer, @Nonnull InteractionContext context, @Nonnull Vector3i targetBlock ) { ChunkStore chunkStore = world.getChunkStore(); long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.getX(), targetBlock.getZ()); BlockComponentChunk blockComponentChunk = chunkStore.getChunkComponent(chunkIndex, BlockComponentChunk.getComponentType()); - if (blockComponentChunk != null) { + if (blockComponentChunk == null) { + return false; + } else { int blockIndex = ChunkUtil.indexBlockInColumn(targetBlock.x, targetBlock.y, targetBlock.z); Ref blockRef = blockComponentChunk.getEntityReference(blockIndex); if (blockRef != null && blockRef.isValid()) { BlockModule.BlockStateInfo blockStateInfoComponent = blockRef.getStore().getComponent(blockRef, BlockModule.BlockStateInfo.getComponentType()); - if (blockStateInfoComponent != null) { + if (blockStateInfoComponent == null) { + return false; + } else { Ref chunkRef = blockStateInfoComponent.getChunkRef(); - if (chunkRef != null || chunkRef.isValid()) { + if (!chunkRef.isValid()) { + return false; + } else { Teleporter teleporter = chunkStore.getStore().getComponent(blockRef, Teleporter.getComponentType()); - if (teleporter != null) { + if (teleporter == null) { + return false; + } else { Ref ref = context.getEntity(); Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType()); - if (playerComponent == null || !playerComponent.isWaitingForClientReady()) { + if (playerComponent != null && playerComponent.isWaitingForClientReady()) { + return false; + } else { Archetype archetype = commandBuffer.getArchetype(ref); - if (!archetype.contains(Teleport.getComponentType()) && !archetype.contains(PendingTeleport.getComponentType())) { - if (!archetype.contains(UsedTeleporter.getComponentType())) { - WorldChunk worldChunkComponent = chunkRef.getStore().getComponent(chunkRef, WorldChunk.getComponentType()); - if (worldChunkComponent != null) { - BlockType blockType = worldChunkComponent.getBlockType(targetBlock.x, targetBlock.y, targetBlock.z); - if (blockType != null) { - if (!teleporter.isValid()) { - String currentState = blockType.getStateForBlock(blockType); - if (!"default".equals(currentState)) { - BlockType variantBlockType = blockType.getBlockForState("default"); - if (variantBlockType != null) { - worldChunkComponent.setBlockInteractionState( - targetBlock.x, targetBlock.y, targetBlock.z, variantBlockType, "default", true - ); - } + if (archetype.contains(Teleport.getComponentType()) || archetype.contains(PendingTeleport.getComponentType())) { + return false; + } else if (archetype.contains(UsedTeleporter.getComponentType())) { + return false; + } else { + WorldChunk worldChunkComponent = chunkRef.getStore().getComponent(chunkRef, WorldChunk.getComponentType()); + if (worldChunkComponent == null) { + return false; + } else { + BlockType blockType = worldChunkComponent.getBlockType(targetBlock.x, targetBlock.y, targetBlock.z); + if (blockType == null) { + return false; + } else { + if (!teleporter.isValid()) { + String currentState = blockType.getStateForBlock(blockType); + if (!"default".equals(currentState)) { + BlockType variantBlockType = blockType.getBlockForState("default"); + if (variantBlockType != null) { + worldChunkComponent.setBlockInteractionState( + targetBlock.x, targetBlock.y, targetBlock.z, variantBlockType, "default", true + ); } } + } - TransformComponent transformComponent = commandBuffer.getComponent(ref, TransformComponent.getComponentType()); - if (transformComponent != null) { - Teleport teleportComponent = teleporter.toTeleport( - transformComponent.getPosition(), transformComponent.getRotation(), targetBlock + TransformComponent transformComponent = commandBuffer.getComponent(ref, TransformComponent.getComponentType()); + if (transformComponent == null) { + return false; + } else { + Teleport teleportComponent = teleporter.toTeleport( + transformComponent.getPosition(), transformComponent.getRotation(), targetBlock + ); + if (teleportComponent == null) { + return false; + } else { + commandBuffer.addComponent(ref, Teleport.getComponentType(), teleportComponent); + commandBuffer.addComponent( + ref, + UsedTeleporter.getComponentType(), + new UsedTeleporter(teleporter.getWorldUuid(), teleportComponent.getPosition(), this.clearoutXZ, this.clearoutY) ); - if (teleportComponent != null) { - TeleportRecord recorder = commandBuffer.getComponent(ref, TeleportRecord.getComponentType()); - if (recorder == null || recorder.hasElapsedSinceLastTeleport(TELEPORTER_GLOBAL_COOLDOWN)) { - commandBuffer.addComponent(ref, Teleport.getComponentType(), teleportComponent); - commandBuffer.addComponent( - ref, - UsedTeleporter.getComponentType(), - new UsedTeleporter(teleporter.getWorldUuid(), teleportComponent.getPosition(), this.clearoutXZ, this.clearoutY) - ); - if (this.particle != null) { - Vector3d particlePosition = transformComponent.getPosition(); - SpatialResource, EntityStore> playerSpatialResource = commandBuffer.getResource( - EntityModule.get().getPlayerSpatialResourceType() - ); - ObjectList> results = SpatialResource.getThreadLocalReferenceList(); - playerSpatialResource.getSpatialStructure().collect(particlePosition, 75.0, results); - ParticleUtil.spawnParticleEffect(this.particle, particlePosition, results, commandBuffer); - } - } + if (this.particle != null) { + Vector3d particlePosition = transformComponent.getPosition(); + SpatialResource, EntityStore> playerSpatialResource = commandBuffer.getResource( + EntityModule.get().getPlayerSpatialResourceType() + ); + ObjectList> results = SpatialResource.getThreadLocalReferenceList(); + playerSpatialResource.getSpatialStructure().collect(particlePosition, 75.0, results); + ParticleUtil.spawnParticleEffect(this.particle, particlePosition, results, commandBuffer); } + + return true; } } } @@ -160,6 +186,8 @@ public class TeleporterInteraction extends SimpleBlockInteraction { } } } + } else { + return false; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/page/TeleporterSettingsPage.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/page/TeleporterSettingsPage.java index 6fbc5caa..5880bad8 100644 --- a/src/com/hypixel/hytale/builtin/adventure/teleporter/page/TeleporterSettingsPage.java +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/page/TeleporterSettingsPage.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.builtin.adventure.teleporter.page; import com.hypixel.hytale.builtin.adventure.teleporter.component.Teleporter; import com.hypixel.hytale.builtin.adventure.teleporter.system.CreateWarpWhenTeleporterPlacedSystem; +import com.hypixel.hytale.builtin.adventure.teleporter.system.TurnOffTeleportersSystem; import com.hypixel.hytale.builtin.adventure.teleporter.util.CannedWarpNames; import com.hypixel.hytale.builtin.teleport.TeleportPlugin; import com.hypixel.hytale.builtin.teleport.Warp; @@ -11,14 +12,11 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.codecs.EnumCodec; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; -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.packets.interface_.CustomPageLifetime; import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType; import com.hypixel.hytale.protocol.packets.interface_.Page; import com.hypixel.hytale.server.core.Message; -import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.pages.InteractiveCustomUIPage; import com.hypixel.hytale.server.core.modules.block.BlockModule; @@ -35,24 +33,21 @@ import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.List; +import java.util.Objects; import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.compatqual.NullableDecl; public class TeleporterSettingsPage extends InteractiveCustomUIPage { @Nonnull private final Ref blockRef; private final TeleporterSettingsPage.Mode mode; - @Nullable - private final String activeState; - public TeleporterSettingsPage( - @Nonnull PlayerRef playerRef, @Nonnull Ref blockRef, TeleporterSettingsPage.Mode mode, @Nullable String activeState - ) { + public TeleporterSettingsPage(@Nonnull PlayerRef playerRef, @Nonnull Ref blockRef, TeleporterSettingsPage.Mode mode) { super(playerRef, CustomPageLifetime.CanDismissOrCloseThroughInteraction, TeleporterSettingsPage.PageEventData.CODEC); this.blockRef = blockRef; this.mode = mode; - this.activeState = activeState; } @Override @@ -103,16 +98,7 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage warps = new ObjectArrayList<>(); - warps.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.teleporter.noWarp"), "")); - - for (Warp warp : TeleportPlugin.get().getWarps().values()) { - if (!warp.getId().equalsIgnoreCase(teleporter.getOwnedWarp())) { - warps.add(new DropdownEntryInfo(LocalizableString.fromString(warp.getId()), warp.getId().toLowerCase())); - } - } - - commandBuilder.set("#WarpDropdown.Entries", warps); + commandBuilder.set("#WarpDropdown.Entries", getWarpsSortedById(teleporter.getOwnedWarp(), null)); commandBuilder.set("#WarpDropdown.Value", teleporter.getWarp() != null ? teleporter.getWarp() : ""); commandBuilder.set("#NewWarp.Value", teleporter.getOwnedWarp() != null ? teleporter.getOwnedWarp() : ""); eventBuilder.addEventBinding( @@ -138,16 +124,7 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage warps = new ObjectArrayList<>(); - warps.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.teleporter.noWarp"), "")); - - for (Warp warpx : TeleportPlugin.get().getWarps().values()) { - if (warpx.getWorld().equals(store.getExternalData().getWorld().getName()) && !warpx.getId().equalsIgnoreCase(teleporter.getOwnedWarp())) { - warps.add(new DropdownEntryInfo(LocalizableString.fromString(warpx.getId()), warpx.getId().toLowerCase())); - } - } - - commandBuilder.set("#WarpDropdown.Entries", warps); + commandBuilder.set("#WarpDropdown.Entries", getWarpsSortedById(teleporter.getOwnedWarp(), store.getExternalData().getWorld().getName())); commandBuilder.set("#WarpDropdown.Value", teleporter.getWarp() != null ? teleporter.getWarp() : ""); Message placeholder; if (teleporter.hasOwnedWarp() && !teleporter.isCustomName()) { @@ -169,109 +146,121 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage getWarpsSortedById(@NullableDecl String ownedWarpId, @NullableDecl String worldNameToFilter) { + List warps = new ObjectArrayList<>(); + warps.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.teleporter.noWarp"), "")); + ObjectArrayList sortedWarps = new ObjectArrayList<>(TeleportPlugin.get().getWarps().values()); + sortedWarps.sort((a, b) -> a.getId().compareToIgnoreCase(b.getId())); + + for (Warp warp : sortedWarps) { + if ((worldNameToFilter == null || warp.getWorld().equals(worldNameToFilter)) && !warp.getId().equalsIgnoreCase(ownedWarpId)) { + warps.add(new DropdownEntryInfo(LocalizableString.fromString(warp.getId()), warp.getId().toLowerCase())); + } + } + + return warps; + } + public void handleDataEvent(@Nonnull Ref ref, @Nonnull Store store, @Nonnull TeleporterSettingsPage.PageEventData data) { Player playerComponent = store.getComponent(ref, Player.getComponentType()); - - assert playerComponent != null; - - String language = this.playerRef.getLanguage(); - BlockModule.BlockStateInfo blockStateInfo = this.blockRef.getStore().getComponent(this.blockRef, BlockModule.BlockStateInfo.getComponentType()); - if (blockStateInfo == null) { - playerComponent.getPageManager().setPage(ref, store, Page.None); - } else { - Ref chunkRef = blockStateInfo.getChunkRef(); - if (!chunkRef.isValid()) { + if (playerComponent != null) { + String language = this.playerRef.getLanguage(); + BlockModule.BlockStateInfo blockStateInfo = this.blockRef.getStore().getComponent(this.blockRef, BlockModule.BlockStateInfo.getComponentType()); + if (blockStateInfo == null) { playerComponent.getPageManager().setPage(ref, store, Page.None); } else { - WorldChunk worldChunkComponent = chunkRef.getStore().getComponent(chunkRef, WorldChunk.getComponentType()); + Ref chunkRef = blockStateInfo.getChunkRef(); + if (!chunkRef.isValid()) { + playerComponent.getPageManager().setPage(ref, store, Page.None); + } else { + WorldChunk worldChunkComponent = chunkRef.getStore().getComponent(chunkRef, WorldChunk.getComponentType()); - assert worldChunkComponent != null; + assert worldChunkComponent != null; - int index = blockStateInfo.getIndex(); - int targetX = ChunkUtil.xFromBlockInColumn(index); - int targetY = ChunkUtil.yFromBlockInColumn(index); - int targetZ = ChunkUtil.zFromBlockInColumn(index); - new Vector3i(targetX, targetY, targetZ); - Teleporter teleporter = this.blockRef.getStore().getComponent(this.blockRef, Teleporter.getComponentType()); - String oldOwnedWarp = teleporter.getOwnedWarp(); - boolean customName = true; - if (data.ownedWarp == null || data.ownedWarp.isEmpty()) { - data.ownedWarp = CannedWarpNames.generateCannedWarpName(this.blockRef, language); - customName = false; - if (data.ownedWarp == null) { - UICommandBuilder commandBuilder = new UICommandBuilder(); - commandBuilder.set("#NewWarp.PlaceholderText", Message.translation("server.customUI.teleporter.warpNameRightHereHint")); - commandBuilder.set("#ErrorLabel.Text", Message.translation("server.customUI.teleporter.errorMissingWarpName")); - commandBuilder.set("#ErrorLabel.Visible", true); - this.sendUpdate(commandBuilder); - return; + Teleporter teleporterComponent = this.blockRef.getStore().getComponent(this.blockRef, Teleporter.getComponentType()); + if (teleporterComponent == null) { + playerComponent.getPageManager().setPage(ref, store, Page.None); + } else { + String oldOwnedWarp = teleporterComponent.getOwnedWarp(); + boolean customName = true; + if (data.warpName == null || data.warpName.isEmpty()) { + if (oldOwnedWarp == null) { + data.warpName = CannedWarpNames.generateCannedWarpName(this.blockRef, language); + customName = false; + } else { + data.warpName = oldOwnedWarp; + customName = teleporterComponent.isCustomName(); + } + + if (data.warpName == null) { + UICommandBuilder commandBuilder = new UICommandBuilder(); + commandBuilder.set("#NewWarp.PlaceholderText", Message.translation("server.customUI.teleporter.warpNameRightHereHint")); + commandBuilder.set("#ErrorLabel.Text", Message.translation("server.customUI.teleporter.errorMissingWarpName")); + commandBuilder.set("#ErrorLabel.Visible", true); + this.sendUpdate(commandBuilder); + return; + } + } + + if (!data.warpName.equalsIgnoreCase(oldOwnedWarp)) { + boolean alreadyExists = TeleportPlugin.get().getWarps().containsKey(data.warpName.toLowerCase()); + if (alreadyExists) { + UICommandBuilder commandBuilder = new UICommandBuilder(); + commandBuilder.set("#ErrorLabel.Text", Message.translation("server.customUI.teleporter.errorWarpAlreadyExists")); + commandBuilder.set("#ErrorLabel.Visible", true); + this.sendUpdate(commandBuilder); + return; + } + } + + if (oldOwnedWarp != null && !oldOwnedWarp.isEmpty()) { + TeleportPlugin.get().getWarps().remove(oldOwnedWarp.toLowerCase()); + } + + playerComponent.getPageManager().setPage(ref, store, Page.None); + String ownedWarpBefore = teleporterComponent.getOwnedWarp(); + String destinationWarpBefore = teleporterComponent.getWarp(); + CreateWarpWhenTeleporterPlacedSystem.createWarp(worldChunkComponent, blockStateInfo, data.warpName); + teleporterComponent.setOwnedWarp(data.warpName); + teleporterComponent.setIsCustomName(customName); + switch (this.mode) { + case FULL: + teleporterComponent.setWorldUuid(data.world != null && !data.world.isEmpty() ? UUID.fromString(data.world) : null); + Transform transform = new Transform(); + transform.getPosition().setX(data.x); + transform.getPosition().setY(data.y); + transform.getPosition().setZ(data.z); + transform.getRotation().setYaw(data.yaw); + transform.getRotation().setPitch(data.pitch); + transform.getRotation().setRoll(data.roll); + teleporterComponent.setTransform(transform); + teleporterComponent.setRelativeMask( + (byte)( + (data.xIsRelative ? 1 : 0) + | (data.yIsRelative ? 2 : 0) + | (data.zIsRelative ? 4 : 0) + | (data.yawIsRelative ? 8 : 0) + | (data.pitchIsRelative ? 16 : 0) + | (data.rollIsRelative ? 32 : 0) + | (data.isBlockRelative ? 64 : 0) + ) + ); + teleporterComponent.setWarp(data.destinationWarp != null && !data.destinationWarp.isEmpty() ? data.destinationWarp : null); + break; + case WARP: + teleporterComponent.setWorldUuid(null); + teleporterComponent.setTransform(null); + teleporterComponent.setWarp(data.destinationWarp != null && !data.destinationWarp.isEmpty() ? data.destinationWarp : null); + } + + boolean ownChanged = !Objects.equals(ownedWarpBefore, teleporterComponent.getOwnedWarp()); + boolean destinationChanged = !Objects.equals(destinationWarpBefore, teleporterComponent.getWarp()); + if (ownChanged || destinationChanged) { + World world = store.getExternalData().getWorld(); + TurnOffTeleportersSystem.updatePortalBlocksInWorld(world); + } } } - - if (!data.ownedWarp.equalsIgnoreCase(oldOwnedWarp)) { - boolean alreadyExists = TeleportPlugin.get().getWarps().containsKey(data.ownedWarp.toLowerCase()); - if (alreadyExists) { - UICommandBuilder commandBuilder = new UICommandBuilder(); - commandBuilder.set("#ErrorLabel.Text", Message.translation("server.customUI.teleporter.errorWarpAlreadyExists")); - commandBuilder.set("#ErrorLabel.Visible", true); - this.sendUpdate(commandBuilder); - return; - } - } - - if (oldOwnedWarp != null && !oldOwnedWarp.isEmpty()) { - TeleportPlugin.get().getWarps().remove(oldOwnedWarp.toLowerCase()); - } - - playerComponent.getPageManager().setPage(ref, store, Page.None); - CreateWarpWhenTeleporterPlacedSystem.createWarp(worldChunkComponent, blockStateInfo, data.ownedWarp); - teleporter.setOwnedWarp(data.ownedWarp); - teleporter.setIsCustomName(customName); - switch (this.mode) { - case FULL: - teleporter.setWorldUuid(data.world != null && !data.world.isEmpty() ? UUID.fromString(data.world) : null); - Transform transform = new Transform(); - transform.getPosition().setX(data.x); - transform.getPosition().setY(data.y); - transform.getPosition().setZ(data.z); - transform.getRotation().setYaw(data.yaw); - transform.getRotation().setPitch(data.pitch); - transform.getRotation().setRoll(data.roll); - teleporter.setTransform(transform); - teleporter.setRelativeMask( - (byte)( - (data.xIsRelative ? 1 : 0) - | (data.yIsRelative ? 2 : 0) - | (data.zIsRelative ? 4 : 0) - | (data.yawIsRelative ? 8 : 0) - | (data.pitchIsRelative ? 16 : 0) - | (data.rollIsRelative ? 32 : 0) - | (data.isBlockRelative ? 64 : 0) - ) - ); - teleporter.setWarp(data.warp != null && !data.warp.isEmpty() ? data.warp : null); - break; - case WARP: - teleporter.setWorldUuid(null); - teleporter.setTransform(null); - teleporter.setWarp(data.warp != null && !data.warp.isEmpty() ? data.warp : null); - } - - String newState = "default"; - if (teleporter.isValid()) { - newState = this.activeState != null ? this.activeState : "default"; - } - - BlockType blockType = worldChunkComponent.getBlockType(targetX, targetY, targetZ); - String currentState = blockType.getStateForBlock(blockType); - if (currentState == null || !currentState.equals(newState)) { - BlockType variantBlockType = blockType.getBlockForState(newState); - if (variantBlockType != null) { - worldChunkComponent.setBlockInteractionState(targetX, targetY, targetZ, variantBlockType, newState, true); - } - } - - blockStateInfo.markNeedsSaving(); } } } @@ -280,26 +269,44 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage CODEC = new EnumCodec<>(TeleporterSettingsPage.Mode.class); } public static class PageEventData { + @Nonnull public static final String KEY_BLOCK_RELATIVE = "@BlockRelative"; + @Nonnull public static final String KEY_X = "@X"; + @Nonnull public static final String KEY_Y = "@Y"; + @Nonnull public static final String KEY_Z = "@Z"; + @Nonnull public static final String KEY_X_IS_RELATIVE = "@XIsRelative"; + @Nonnull public static final String KEY_Y_IS_RELATIVE = "@YIsRelative"; + @Nonnull public static final String KEY_Z_IS_RELATIVE = "@ZIsRelative"; + @Nonnull public static final String KEY_YAW = "@Yaw"; + @Nonnull public static final String KEY_PITCH = "@Pitch"; + @Nonnull public static final String KEY_ROLL = "@Roll"; + @Nonnull public static final String KEY_YAW_IS_RELATIVE = "@YawIsRelative"; + @Nonnull public static final String KEY_PITCH_IS_RELATIVE = "@PitchIsRelative"; + @Nonnull public static final String KEY_ROLL_IS_RELATIVE = "@RollIsRelative"; + @Nonnull public static final String KEY_WORLD = "@World"; + @Nonnull public static final String KEY_WARP = "@Warp"; + @Nonnull public static final String KEY_NEW_WARP = "@NewWarp"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TeleporterSettingsPage.PageEventData.class, TeleporterSettingsPage.PageEventData::new ) @@ -353,9 +360,11 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage("@World", Codec.STRING), (pageEventData, o) -> pageEventData.world = o, pageEventData -> pageEventData.world) .add() - .append(new KeyedCodec<>("@Warp", Codec.STRING), (pageEventData, o) -> pageEventData.warp = o, pageEventData -> pageEventData.warp) + .append( + new KeyedCodec<>("@Warp", Codec.STRING), (pageEventData, o) -> pageEventData.destinationWarp = o, pageEventData -> pageEventData.destinationWarp + ) .add() - .append(new KeyedCodec<>("@NewWarp", Codec.STRING), (pageEventData, o) -> pageEventData.ownedWarp = o, pageEventData -> pageEventData.ownedWarp) + .append(new KeyedCodec<>("@NewWarp", Codec.STRING), (pageEventData, o) -> pageEventData.warpName = o, pageEventData -> pageEventData.warpName) .add() .build(); public boolean isBlockRelative; @@ -372,8 +381,8 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder( TeleporterSettingsPageSupplier.class, TeleporterSettingsPageSupplier::new ) @@ -41,23 +42,17 @@ public class TeleporterSettingsPageSupplier implements OpenCustomUIInteraction.C (supplier, parent) -> supplier.mode = parent.mode ) .add() - .appendInherited( - new KeyedCodec<>("ActiveState", Codec.STRING), - (supplier, o) -> supplier.activeState = o, - supplier -> supplier.activeState, - (supplier, parent) -> supplier.activeState = parent.activeState - ) - .add() .build(); private boolean create = true; private TeleporterSettingsPage.Mode mode = TeleporterSettingsPage.Mode.FULL; - @Nullable - private String activeState; @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 +61,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 +79,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) : null; } } } diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/system/ClearUsedTeleporterSystem.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/system/ClearUsedTeleporterSystem.java index d514097e..21841efb 100644 --- a/src/com/hypixel/hytale/builtin/adventure/teleporter/system/ClearUsedTeleporterSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/system/ClearUsedTeleporterSystem.java @@ -1,60 +1,117 @@ package com.hypixel.hytale.builtin.adventure.teleporter.system; import com.hypixel.hytale.builtin.adventure.teleporter.interaction.server.UsedTeleporter; +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.Ref; import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.component.dependency.Dependency; +import com.hypixel.hytale.component.dependency.Order; +import com.hypixel.hytale.component.dependency.SystemDependency; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.math.vector.Vector2d; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; +import com.hypixel.hytale.server.core.modules.entity.teleport.PendingTeleport; +import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport; +import com.hypixel.hytale.server.core.modules.entity.teleport.TeleportRecord; +import com.hypixel.hytale.server.core.modules.entity.teleport.TeleportSystems; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import java.time.Duration; +import java.util.Set; import java.util.UUID; -import javax.annotation.Nullable; -import org.checkerframework.checker.nullness.compatqual.NonNullDecl; -import org.checkerframework.checker.nullness.compatqual.NullableDecl; +import javax.annotation.Nonnull; public class ClearUsedTeleporterSystem extends EntityTickingSystem { + @Nonnull + public static final Duration TELEPORTER_GLOBAL_COOLDOWN = Duration.ofMillis(100L); + @Nonnull + private static final Set> DEPENDENCIES = Set.of(new SystemDependency<>(Order.AFTER, TeleportSystems.PlayerMoveSystem.class)); + @Nonnull + private final ComponentType usedTeleporterComponentType; + @Nonnull + private final ComponentType transformComponentType; + @Nonnull + private final ComponentType teleportRecordComponentType; + @Nonnull + private final ComponentType teleportComponentType; + @Nonnull + private final ComponentType pendingTeleportComponentType; + + public ClearUsedTeleporterSystem( + @Nonnull ComponentType usedTeleporterComponentType, + @Nonnull ComponentType transformComponentType, + @Nonnull ComponentType teleportRecordComponentType, + @Nonnull ComponentType teleportComponentType, + @Nonnull ComponentType pendingTeleportComponentType + ) { + this.usedTeleporterComponentType = usedTeleporterComponentType; + this.transformComponentType = transformComponentType; + this.teleportRecordComponentType = teleportRecordComponentType; + this.teleportComponentType = teleportComponentType; + this.pendingTeleportComponentType = pendingTeleportComponentType; + } + + @Nonnull + @Override + public Set> getDependencies() { + return DEPENDENCIES; + } + @Override public void tick( float dt, int index, - @NonNullDecl ArchetypeChunk archetypeChunk, - @NonNullDecl Store store, - @NonNullDecl CommandBuffer commandBuffer + @Nonnull ArchetypeChunk archetypeChunk, + @Nonnull Store store, + @Nonnull CommandBuffer commandBuffer ) { World world = store.getExternalData().getWorld(); - UsedTeleporter usedTeleporter = archetypeChunk.getComponent(index, UsedTeleporter.getComponentType()); - TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); - if (shouldClear(world, usedTeleporter, transformComponent)) { + if (this.shouldClear(world, index, archetypeChunk)) { Ref ref = archetypeChunk.getReferenceTo(index); - commandBuffer.removeComponent(ref, UsedTeleporter.getComponentType()); + commandBuffer.removeComponent(ref, this.usedTeleporterComponentType); } } - private static boolean shouldClear(World entityWorld, UsedTeleporter usedTeleporter, @Nullable TransformComponent transformComponent) { + private boolean shouldClear(@Nonnull World world, int index, @Nonnull ArchetypeChunk archetypeChunk) { + UsedTeleporter usedTeleporter = archetypeChunk.getComponent(index, this.usedTeleporterComponentType); + + assert usedTeleporter != null; + + TransformComponent transformComponent = archetypeChunk.getComponent(index, this.transformComponentType); + TeleportRecord teleportRecord = archetypeChunk.getComponent(index, this.teleportRecordComponentType); if (transformComponent == null) { return true; } else { - UUID destinationWorldUuid = usedTeleporter.getDestinationWorldUuid(); - if (destinationWorldUuid != null && !entityWorld.getWorldConfig().getUuid().equals(destinationWorldUuid)) { - return true; + Archetype archetype = archetypeChunk.getArchetype(); + if (!archetype.contains(this.teleportComponentType) && !archetype.contains(this.pendingTeleportComponentType)) { + if (teleportRecord != null && !teleportRecord.hasElapsedSinceLastTeleport(System.nanoTime(), TELEPORTER_GLOBAL_COOLDOWN)) { + return false; + } else { + UUID destinationWorldUuid = usedTeleporter.getDestinationWorldUuid(); + if (destinationWorldUuid != null && !world.getWorldConfig().getUuid().equals(destinationWorldUuid)) { + return true; + } else { + Vector3d entityPosition = transformComponent.getPosition(); + Vector3d destinationPosition = usedTeleporter.getDestinationPosition(); + double deltaY = Math.abs(entityPosition.y - destinationPosition.y); + double distanceXZsq = Vector2d.distanceSquared(entityPosition.x, entityPosition.z, destinationPosition.x, destinationPosition.z); + return deltaY > usedTeleporter.getClearOutY() || distanceXZsq > usedTeleporter.getClearOutXZ(); + } + } } else { - Vector3d entityPosition = transformComponent.getPosition(); - Vector3d destinationPosition = usedTeleporter.getDestinationPosition(); - double deltaY = Math.abs(entityPosition.y - destinationPosition.y); - double distanceXZsq = Vector2d.distanceSquared(entityPosition.x, entityPosition.z, destinationPosition.x, destinationPosition.z); - return deltaY > usedTeleporter.getClearOutY() || distanceXZsq > usedTeleporter.getClearOutXZ(); + return false; } } } - @NullableDecl + @Nonnull @Override public Query getQuery() { - return UsedTeleporter.getComponentType(); + return this.usedTeleporterComponentType; } } diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/system/CreateWarpWhenTeleporterPlacedSystem.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/system/CreateWarpWhenTeleporterPlacedSystem.java index 4f0debee..80ebef23 100644 --- a/src/com/hypixel/hytale/builtin/adventure/teleporter/system/CreateWarpWhenTeleporterPlacedSystem.java +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/system/CreateWarpWhenTeleporterPlacedSystem.java @@ -31,6 +31,30 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CreateWarpWhenTeleporterPlacedSystem extends RefChangeSystem { + @Nonnull + private final ComponentType placedByInteractionComponentType; + @Nonnull + private final ComponentType teleporterComponentType; + @Nonnull + private final ComponentType blockStateInfoComponentType; + @Nonnull + private final ComponentType playerRefComponentType; + @Nonnull + private final Query query; + + public CreateWarpWhenTeleporterPlacedSystem( + @Nonnull ComponentType placedByInteractionComponentType, + @Nonnull ComponentType teleporterComponentType, + @Nonnull ComponentType blockStateInfoComponentType, + @Nonnull ComponentType playerRefComponentType + ) { + this.placedByInteractionComponentType = placedByInteractionComponentType; + this.teleporterComponentType = teleporterComponentType; + this.blockStateInfoComponentType = blockStateInfoComponentType; + this.playerRefComponentType = playerRefComponentType; + this.query = Query.and(placedByInteractionComponentType, teleporterComponentType, blockStateInfoComponentType); + } + public void onComponentAdded( @Nonnull Ref ref, @Nonnull PlacedByInteractionComponent placedBy, @@ -42,21 +66,21 @@ public class CreateWarpWhenTeleporterPlacedSystem extends RefChangeSystem whoPlacedRef = entityStore.getRefFromUUID(whoPlacedUuid); if (whoPlacedRef != null && whoPlacedRef.isValid()) { - PlayerRef playerRefComponent = entityStore.getStore().getComponent(whoPlacedRef, PlayerRef.getComponentType()); + PlayerRef playerRefComponent = entityStore.getStore().getComponent(whoPlacedRef, this.playerRefComponentType); String language = playerRefComponent == null ? null : playerRefComponent.getLanguage(); if (language != null) { - BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, this.blockStateInfoComponentType); assert blockStateInfoComponent != null; Ref chunkRef = blockStateInfoComponent.getChunkRef(); - if (chunkRef != null && chunkRef.isValid()) { + if (chunkRef.isValid()) { WorldChunk worldChunk = chunkStore.getComponent(chunkRef, WorldChunk.getComponentType()); if (worldChunk != null) { String cannedName = CannedWarpNames.generateCannedWarpName(ref, language); if (cannedName != null) { createWarp(worldChunk, blockStateInfoComponent, cannedName); - Teleporter teleporterComponent = commandBuffer.getComponent(ref, Teleporter.getComponentType()); + Teleporter teleporterComponent = commandBuffer.getComponent(ref, this.teleporterComponentType); assert teleporterComponent != null; @@ -76,21 +100,20 @@ public class CreateWarpWhenTeleporterPlacedSystem extends RefChangeSystem componentType() { - return PlacedByInteractionComponent.getComponentType(); + return this.placedByInteractionComponentType; } - @Nullable + @Nonnull @Override public Query getQuery() { - return Query.and(PlacedByInteractionComponent.getComponentType(), Teleporter.getComponentType(), BlockModule.BlockStateInfo.getComponentType()); + return this.query; } } diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/system/TurnOffTeleportersSystem.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/system/TurnOffTeleportersSystem.java new file mode 100644 index 00000000..48cf552a --- /dev/null +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/system/TurnOffTeleportersSystem.java @@ -0,0 +1,98 @@ +package com.hypixel.hytale.builtin.adventure.teleporter.system; + +import com.hypixel.hytale.builtin.adventure.teleporter.component.Teleporter; +import com.hypixel.hytale.builtin.teleport.TeleportPlugin; +import com.hypixel.hytale.builtin.teleport.Warp; +import com.hypixel.hytale.component.AddReason; +import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.ComponentAccessor; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.RemoveReason; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.component.query.AndQuery; +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.server.core.asset.type.blocktype.config.BlockType; +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.WorldChunk; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.compatqual.NullableDecl; + +public class TurnOffTeleportersSystem extends RefSystem { + public static final Query QUERY = Query.and(Teleporter.getComponentType(), BlockModule.BlockStateInfo.getComponentType()); + + @Override + public void onEntityAdded( + @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { + if (reason == AddReason.LOAD) { + updatePortalBlocksInWorld(store.getExternalData().getWorld()); + } + } + + @Override + public void onEntityRemove( + @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { + if (reason == RemoveReason.REMOVE) { + updatePortalBlocksInWorld(store.getExternalData().getWorld()); + } + } + + public static void updatePortalBlocksInWorld(World world) { + Store store = world.getChunkStore().getStore(); + AndQuery entityQuery = Query.and(Teleporter.getComponentType(), BlockModule.BlockStateInfo.getComponentType()); + store.forEachChunk(entityQuery, (archetypeChunk, commandBuffer) -> { + for (int i = 0; i < archetypeChunk.size(); i++) { + Ref ref = archetypeChunk.getReferenceTo(i); + updatePortalBlockInWorld(ref, commandBuffer); + } + }); + } + + private static void updatePortalBlockInWorld(Ref ref, ComponentAccessor store) { + if (ref.isValid()) { + Teleporter teleporter = store.getComponent(ref, Teleporter.getComponentType()); + BlockModule.BlockStateInfo blockState = store.getComponent(ref, BlockModule.BlockStateInfo.getComponentType()); + updatePortalBlockInWorld(store, teleporter, blockState); + } + } + + public static void updatePortalBlockInWorld(ComponentAccessor store, Teleporter teleporter, BlockModule.BlockStateInfo blockStateInfo) { + Ref chunkRef = blockStateInfo.getChunkRef(); + if (chunkRef.isValid()) { + 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); + BlockType blockType = worldChunkComponent.getBlockType(x, y, z); + if (blockType != null) { + String warpId = teleporter.getWarp(); + Warp destinationWarp = warpId == null ? null : TeleportPlugin.get().getWarps().get(warpId); + String currentState = blockType.getStateForBlock(blockType); + String desiredState = destinationWarp == null ? "default" : "Active"; + if (!desiredState.equals(currentState)) { + worldChunkComponent.setBlockInteractionState(x, y, z, blockType, desiredState, false); + blockStateInfo.markNeedsSaving(store); + } + + if (destinationWarp == null) { + teleporter.setWarp(null); + blockStateInfo.markNeedsSaving(store); + } + } + } + } + } + + @NullableDecl + @Override + public Query getQuery() { + return QUERY; + } +} diff --git a/src/com/hypixel/hytale/builtin/adventure/teleporter/util/CannedWarpNames.java b/src/com/hypixel/hytale/builtin/adventure/teleporter/util/CannedWarpNames.java index cf8257ae..fe86bccd 100644 --- a/src/com/hypixel/hytale/builtin/adventure/teleporter/util/CannedWarpNames.java +++ b/src/com/hypixel/hytale/builtin/adventure/teleporter/util/CannedWarpNames.java @@ -21,23 +21,23 @@ public final class CannedWarpNames { } @Nullable - public static String generateCannedWarpName(Ref blockRef, String language) { + public static String generateCannedWarpName(@Nonnull Ref blockRef, @Nonnull String language) { String translationKey = generateCannedWarpNameKey(blockRef, language); return translationKey == null ? null : I18nModule.get().getMessage(language, translationKey); } @Nullable - public static String generateCannedWarpNameKey(Ref blockRef, String language) { + public static String generateCannedWarpNameKey(@Nonnull Ref blockRef, @Nonnull String language) { Store store = blockRef.getStore(); World world = store.getExternalData().getWorld(); BlockModule.BlockStateInfo blockStateInfo = store.getComponent(blockRef, BlockModule.BlockStateInfo.getComponentType()); Random random = blockStateInfo == null ? new Random() : new Random(blockStateInfo.getIndex()); - Teleporter teleporter = store.getComponent(blockRef, Teleporter.getComponentType()); - String wordListKey = teleporter == null ? null : teleporter.getWarpNameWordListKey(); + Teleporter teleporterComponent = store.getComponent(blockRef, Teleporter.getComponentType()); + String wordListKey = teleporterComponent == null ? null : teleporterComponent.getWarpNameWordListKey(); Set existingNames = getWarpNamesInWorld(world); - if (teleporter != null) { - String ownName = teleporter.getOwnedWarp(); - if (ownName != null && !teleporter.isCustomName()) { + if (teleporterComponent != null) { + String ownName = teleporterComponent.getOwnedWarp(); + if (ownName != null && !teleporterComponent.isCustomName()) { existingNames.remove(ownName); } } @@ -46,7 +46,7 @@ public final class CannedWarpNames { } @Nonnull - private static Set getWarpNamesInWorld(World world) { + private static Set getWarpNamesInWorld(@Nonnull World world) { Set existingNames = new HashSet<>(); for (Warp warp : TeleportPlugin.get().getWarps().values()) { diff --git a/src/com/hypixel/hytale/builtin/adventure/worldlocationcondition/NeighbourBlockTagsLocationCondition.java b/src/com/hypixel/hytale/builtin/adventure/worldlocationcondition/NeighbourBlockTagsLocationCondition.java index c8f8dcdf..4384cee7 100644 --- a/src/com/hypixel/hytale/builtin/adventure/worldlocationcondition/NeighbourBlockTagsLocationCondition.java +++ b/src/com/hypixel/hytale/builtin/adventure/worldlocationcondition/NeighbourBlockTagsLocationCondition.java @@ -21,6 +21,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class NeighbourBlockTagsLocationCondition extends WorldLocationCondition { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( NeighbourBlockTagsLocationCondition.class, NeighbourBlockTagsLocationCondition::new, WorldLocationCondition.BASE_CODEC ) @@ -53,11 +54,12 @@ public class NeighbourBlockTagsLocationCondition extends WorldLocationCondition protected IntRange support = new IntRange(1, 4); @Override - public boolean test(World world, int worldX, int worldY, int worldZ) { + public boolean test(@Nonnull World world, int worldX, int worldY, int worldZ) { if (worldY <= 0) { return false; } else { - WorldChunk worldChunk = world.getNonTickingChunk(ChunkUtil.indexChunkFromBlock(worldX, worldZ)); + long chunkIndex = ChunkUtil.indexChunkFromBlock(worldX, worldZ); + WorldChunk worldChunk = world.getNonTickingChunk(chunkIndex); if (worldChunk == null) { return false; } else if (this.neighbourDirection == NeighbourBlockTagsLocationCondition.NeighbourDirection.SIDEWAYS) { @@ -95,15 +97,24 @@ public class NeighbourBlockTagsLocationCondition extends WorldLocationCondition } } - private boolean checkBlockHasTag(int x, int y, int z, @Nonnull BlockAccessor worldChunk) { - int blockIndex = worldChunk.getBlock(x, y, z); - TagPattern tagPattern = TagPattern.getAssetMap().getAsset(this.tagPatternId); - if (tagPattern != null) { - AssetExtraInfo.Data data = BlockType.getAssetMap().getAsset(blockIndex).getData(); - return data == null ? false : tagPattern.test(data.getTags()); - } else { - HytaleLogger.getLogger().at(Level.WARNING).log("No TagPattern asset found for id: " + this.tagPatternId); + private boolean checkBlockHasTag(int x, int y, int z, @Nullable BlockAccessor worldChunk) { + if (worldChunk == null) { return false; + } else { + int blockIndex = worldChunk.getBlock(x, y, z); + TagPattern tagPattern = TagPattern.getAssetMap().getAsset(this.tagPatternId); + if (tagPattern != null) { + BlockType blockType = BlockType.getAssetMap().getAsset(blockIndex); + if (blockType == null) { + return false; + } else { + AssetExtraInfo.Data data = blockType.getData(); + return data == null ? false : tagPattern.test(data.getTags()); + } + } else { + HytaleLogger.getLogger().at(Level.WARNING).log("No TagPattern asset found for id: " + this.tagPatternId); + return false; + } } } @@ -145,7 +156,7 @@ public class NeighbourBlockTagsLocationCondition extends WorldLocationCondition + super.toString(); } - private static enum NeighbourDirection { + protected static enum NeighbourDirection { ABOVE, BELOW, SIDEWAYS; diff --git a/src/com/hypixel/hytale/builtin/ambience/AmbiencePlugin.java b/src/com/hypixel/hytale/builtin/ambience/AmbiencePlugin.java index a238da24..d106696b 100644 --- a/src/com/hypixel/hytale/builtin/ambience/AmbiencePlugin.java +++ b/src/com/hypixel/hytale/builtin/ambience/AmbiencePlugin.java @@ -10,23 +10,33 @@ import com.hypixel.hytale.builtin.ambience.systems.ForcedMusicSystems; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.ResourceType; 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.entity.entities.Player; +import com.hypixel.hytale.server.core.modules.entity.component.AudioComponent; +import com.hypixel.hytale.server.core.modules.entity.component.Intangible; +import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; +import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; +import com.hypixel.hytale.server.core.prefab.PrefabCopyableComponent; +import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.core.util.Config; import java.util.logging.Level; import javax.annotation.Nonnull; public class AmbiencePlugin extends JavaPlugin { + @Nonnull private static final String DEFAULT_AMBIENT_EMITTER_MODEL = "NPC_Spawn_Marker"; private static AmbiencePlugin instance; private ComponentType ambienceTrackerComponentType; private ComponentType ambientEmitterComponentType; private ResourceType ambienceResourceType; + @Nonnull private final Config config = this.withConfig("AmbiencePlugin", AmbiencePlugin.AmbiencePluginConfig.CODEC); private Model ambientEmitterModel; @@ -41,15 +51,32 @@ public class AmbiencePlugin extends JavaPlugin { @Override protected void setup() { - this.ambienceTrackerComponentType = this.getEntityStoreRegistry().registerComponent(AmbienceTracker.class, AmbienceTracker::new); - this.ambientEmitterComponentType = this.getEntityStoreRegistry() - .registerComponent(AmbientEmitterComponent.class, "AmbientEmitter", AmbientEmitterComponent.CODEC); - this.ambienceResourceType = this.getEntityStoreRegistry().registerResource(AmbienceResource.class, AmbienceResource::new); - this.getEntityStoreRegistry().registerSystem(new AmbientEmitterSystems.EntityAdded()); - this.getEntityStoreRegistry().registerSystem(new AmbientEmitterSystems.EntityRefAdded()); - this.getEntityStoreRegistry().registerSystem(new AmbientEmitterSystems.Ticking()); - this.getEntityStoreRegistry().registerSystem(new ForcedMusicSystems.Tick()); - this.getEntityStoreRegistry().registerSystem(new ForcedMusicSystems.PlayerAdded()); + ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); + this.ambienceTrackerComponentType = entityStoreRegistry.registerComponent(AmbienceTracker.class, AmbienceTracker::new); + this.ambientEmitterComponentType = entityStoreRegistry.registerComponent(AmbientEmitterComponent.class, "AmbientEmitter", AmbientEmitterComponent.CODEC); + this.ambienceResourceType = entityStoreRegistry.registerResource(AmbienceResource.class, AmbienceResource::new); + ComponentType transformComponentType = TransformComponent.getComponentType(); + ComponentType networkIdComponentType = NetworkId.getComponentType(); + ComponentType intangibleComponentType = Intangible.getComponentType(); + ComponentType prefabCopyableComponentType = PrefabCopyableComponent.getComponentType(); + ComponentType audioComponentType = AudioComponent.getComponentType(); + ComponentType playerComponentType = Player.getComponentType(); + ComponentType playerRefComponentType = PlayerRef.getComponentType(); + entityStoreRegistry.registerSystem( + new AmbientEmitterSystems.EntityAdded( + this.ambientEmitterComponentType, transformComponentType, networkIdComponentType, intangibleComponentType, prefabCopyableComponentType + ) + ); + entityStoreRegistry.registerSystem( + new AmbientEmitterSystems.EntityRefAdded( + this.ambientEmitterComponentType, transformComponentType, audioComponentType, networkIdComponentType, intangibleComponentType + ) + ); + entityStoreRegistry.registerSystem(new AmbientEmitterSystems.Ticking(this.ambientEmitterComponentType, transformComponentType)); + entityStoreRegistry.registerSystem( + new ForcedMusicSystems.Tick(playerComponentType, playerRefComponentType, this.ambienceTrackerComponentType, this.ambienceResourceType) + ); + entityStoreRegistry.registerSystem(new ForcedMusicSystems.PlayerAdded(playerRefComponentType, this.ambienceTrackerComponentType)); this.getCommandRegistry().registerCommand(new AmbienceCommands()); } @@ -87,6 +114,7 @@ public class AmbiencePlugin extends JavaPlugin { } public static class AmbiencePluginConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( AmbiencePlugin.AmbiencePluginConfig.class, AmbiencePlugin.AmbiencePluginConfig::new ) diff --git a/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceClearCommand.java b/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceClearCommand.java index 0b14ab52..e7d4d45e 100644 --- a/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceClearCommand.java +++ b/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceClearCommand.java @@ -10,14 +10,17 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class AmbienceClearCommand extends AbstractWorldCommand { + @Nonnull + private static final Message MESSAGE_SERVER_COMMANDS_AMBIENCE_CLEAR_SUCCESS = Message.translation("server.commands.ambience.clear.success"); + public AmbienceClearCommand() { super("clear", "server.commands.ambience.clear.desc"); } @Override protected void execute(@Nonnull CommandContext context, @Nonnull World world, @Nonnull Store store) { - AmbienceResource resource = store.getResource(AmbienceResource.getResourceType()); - resource.setForcedMusicAmbience(null); - context.sendMessage(Message.translation("server.commands.ambience.clear.success")); + AmbienceResource ambienceResource = store.getResource(AmbienceResource.getResourceType()); + ambienceResource.setForcedMusicAmbience(null); + context.sendMessage(MESSAGE_SERVER_COMMANDS_AMBIENCE_CLEAR_SUCCESS); } } diff --git a/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceEmitterAddCommand.java b/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceEmitterAddCommand.java index cbc855a8..ab701891 100644 --- a/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceEmitterAddCommand.java +++ b/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceEmitterAddCommand.java @@ -32,6 +32,8 @@ public class AmbienceEmitterAddCommand extends AbstractPlayerCommand { "server.commands.ambience.emitter.add.arg.soundEvent.name", SoundEvent.class, "server.commands.ambience.emitter.add.arg.soundEvent.usage" ); @Nonnull + private static final Message MESSAGE_SERVER_COMMANDS_ERRORS_PLAYER_ONLY = Message.translation("server.commands.errors.playerOnly"); + @Nonnull private final RequiredArg soundEventArg = this.withRequiredArg( "soundEvent", "server.commands.ambience.emitter.add.arg.soundEvent.desc", SOUND_EVENT_ASSET_TYPE ); @@ -45,42 +47,41 @@ public class AmbienceEmitterAddCommand extends AbstractPlayerCommand { @Nonnull CommandContext context, @Nonnull Store store, @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world ) { if (!context.isPlayer()) { - throw new GeneralCommandException(Message.translation("server.commands.errors.playerOnly")); + throw new GeneralCommandException(MESSAGE_SERVER_COMMANDS_ERRORS_PLAYER_ONLY); } else { TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); + if (transformComponent != null) { + Holder holder = EntityStore.REGISTRY.newHolder(); + SoundEvent soundEvent = this.soundEventArg.get(context); + boolean looping = false; - assert transformComponent != null; - - Holder holder = EntityStore.REGISTRY.newHolder(); - SoundEvent soundEvent = this.soundEventArg.get(context); - boolean looping = false; - - for (SoundEventLayer layer : soundEvent.getLayers()) { - if (layer.isLooping()) { - looping = true; - break; + for (SoundEventLayer layer : soundEvent.getLayers()) { + if (layer.isLooping()) { + looping = true; + break; + } } - } - if (!looping) { - context.sendMessage(Message.translation("server.commands.ambience.emitter.add.notLooping").param("soundEventId", soundEvent.getId())); - } else { - AmbientEmitterComponent emitterComponent = new AmbientEmitterComponent(); - emitterComponent.setSoundEventId(soundEvent.getId()); - holder.addComponent(AmbientEmitterComponent.getComponentType(), emitterComponent); - TransformComponent emitterTransform = transformComponent.clone(); - holder.addComponent(TransformComponent.getComponentType(), emitterTransform); - holder.addComponent(Nameplate.getComponentType(), new Nameplate(soundEvent.getId())); - holder.ensureComponent(UUIDComponent.getComponentType()); - holder.ensureComponent(HiddenFromAdventurePlayers.getComponentType()); - Model model = AmbiencePlugin.get().getAmbientEmitterModel(); - holder.addComponent(ModelComponent.getComponentType(), new ModelComponent(model)); - holder.addComponent(PersistentModel.getComponentType(), new PersistentModel(model.toReference())); - Ref emitterRef = store.addEntity(holder, AddReason.SPAWN); - if (emitterRef != null && emitterRef.isValid()) { - context.sendMessage(Message.translation("server.commands.ambience.emitter.add.added").param("soundEventId", soundEvent.getId())); + if (!looping) { + context.sendMessage(Message.translation("server.commands.ambience.emitter.add.notLooping").param("soundEventId", soundEvent.getId())); } else { - context.sendMessage(Message.translation("server.commands.ambience.emitter.add.failed").param("soundEventId", soundEvent.getId())); + AmbientEmitterComponent emitterComponent = new AmbientEmitterComponent(); + emitterComponent.setSoundEventId(soundEvent.getId()); + holder.addComponent(AmbientEmitterComponent.getComponentType(), emitterComponent); + TransformComponent emitterTransform = transformComponent.clone(); + holder.addComponent(TransformComponent.getComponentType(), emitterTransform); + holder.addComponent(Nameplate.getComponentType(), new Nameplate(soundEvent.getId())); + holder.ensureComponent(UUIDComponent.getComponentType()); + holder.ensureComponent(HiddenFromAdventurePlayers.getComponentType()); + Model model = AmbiencePlugin.get().getAmbientEmitterModel(); + holder.addComponent(ModelComponent.getComponentType(), new ModelComponent(model)); + holder.addComponent(PersistentModel.getComponentType(), new PersistentModel(model.toReference())); + Ref emitterRef = store.addEntity(holder, AddReason.SPAWN); + if (emitterRef != null && emitterRef.isValid()) { + context.sendMessage(Message.translation("server.commands.ambience.emitter.add.added").param("soundEventId", soundEvent.getId())); + } else { + context.sendMessage(Message.translation("server.commands.ambience.emitter.add.failed").param("soundEventId", soundEvent.getId())); + } } } } diff --git a/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceSetMusicCommand.java b/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceSetMusicCommand.java index fc80935f..b9662e2c 100644 --- a/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceSetMusicCommand.java +++ b/src/com/hypixel/hytale/builtin/ambience/commands/AmbienceSetMusicCommand.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class AmbienceSetMusicCommand extends AbstractWorldCommand { + @Nonnull private final RequiredArg ambienceFxIdArg = this.withRequiredArg( "ambienceFxId", "server.commands.ambience.setmusic.arg.ambiencefxid.desc", ArgTypes.AMBIENCE_FX_ASSET ); @@ -24,8 +25,8 @@ public class AmbienceSetMusicCommand extends AbstractWorldCommand { @Override protected void execute(@Nonnull CommandContext context, @Nonnull World world, @Nonnull Store store) { AmbienceFX ambienceFX = this.ambienceFxIdArg.get(context); - AmbienceResource resource = store.getResource(AmbienceResource.getResourceType()); - resource.setForcedMusicAmbience(ambienceFX.getId()); + AmbienceResource ambienceResource = store.getResource(AmbienceResource.getResourceType()); + ambienceResource.setForcedMusicAmbience(ambienceFX.getId()); context.sendMessage(Message.translation("server.commands.ambience.setmusic.success").param("ambience", ambienceFX.getId())); } } diff --git a/src/com/hypixel/hytale/builtin/ambience/components/AmbienceTracker.java b/src/com/hypixel/hytale/builtin/ambience/components/AmbienceTracker.java index 748319ac..3fc2461e 100644 --- a/src/com/hypixel/hytale/builtin/ambience/components/AmbienceTracker.java +++ b/src/com/hypixel/hytale/builtin/ambience/components/AmbienceTracker.java @@ -5,9 +5,11 @@ import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.protocol.packets.world.UpdateEnvironmentMusic; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class AmbienceTracker implements Component { + @Nonnull private final UpdateEnvironmentMusic musicPacket = new UpdateEnvironmentMusic(0); private int forcedMusicIndex; @@ -23,6 +25,7 @@ public class AmbienceTracker implements Component { return this.forcedMusicIndex; } + @Nonnull public UpdateEnvironmentMusic getMusicPacket() { return this.musicPacket; } diff --git a/src/com/hypixel/hytale/builtin/ambience/components/AmbientEmitterComponent.java b/src/com/hypixel/hytale/builtin/ambience/components/AmbientEmitterComponent.java index 0a0a3ae8..21700a1b 100644 --- a/src/com/hypixel/hytale/builtin/ambience/components/AmbientEmitterComponent.java +++ b/src/com/hypixel/hytale/builtin/ambience/components/AmbientEmitterComponent.java @@ -8,9 +8,11 @@ import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class AmbientEmitterComponent implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(AmbientEmitterComponent.class, AmbientEmitterComponent::new) .append(new KeyedCodec<>("SoundEventId", Codec.STRING), (emitter, s) -> emitter.soundEventId = s, emitter -> emitter.soundEventId) .add() diff --git a/src/com/hypixel/hytale/builtin/ambience/systems/AmbientEmitterSystems.java b/src/com/hypixel/hytale/builtin/ambience/systems/AmbientEmitterSystems.java index 55ab3e1d..1aff5cb3 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,26 +25,48 @@ 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 { - private final Query query = Query.and(AmbientEmitterComponent.getComponentType(), TransformComponent.getComponentType()); + @Nonnull + private final ComponentType networkIdComponentType; + @Nonnull + private final ComponentType intangibleComponentType; + @Nonnull + private final ComponentType prefabCopyableComponentType; + @Nonnull + private final Query query; + + public EntityAdded( + @Nonnull ComponentType ambientEmitterComponentType, + @Nonnull ComponentType transformComponentType, + @Nonnull ComponentType networkIdComponentType, + @Nonnull ComponentType intangibleComponentType, + @Nonnull ComponentType prefabCopyableComponentType + ) { + this.networkIdComponentType = networkIdComponentType; + this.intangibleComponentType = intangibleComponentType; + this.prefabCopyableComponentType = prefabCopyableComponentType; + this.query = Query.and(ambientEmitterComponentType, transformComponentType); + } @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(); + if (!archetype.contains(this.networkIdComponentType)) { + int nextNetworkId = store.getExternalData().takeNextNetworkId(); + holder.addComponent(this.networkIdComponentType, new NetworkId(nextNetworkId)); } - holder.ensureComponent(Intangible.getComponentType()); - holder.ensureComponent(PrefabCopyableComponent.getComponentType()); + holder.ensureComponent(this.intangibleComponentType); + holder.ensureComponent(this.prefabCopyableComponentType); } @Override public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { } + @Nonnull @Override public Query getQuery() { return this.query; @@ -50,29 +74,57 @@ public class AmbientEmitterSystems { } public static class EntityRefAdded extends RefSystem { - private final Query query = Query.and(AmbientEmitterComponent.getComponentType(), TransformComponent.getComponentType()); + @Nonnull + private final ComponentType ambientEmitterComponentType; + @Nonnull + private final ComponentType transformComponentType; + @Nonnull + private final ComponentType audioComponentType; + @Nonnull + private final ComponentType networkIdComponentType; + @Nonnull + private final ComponentType intangibleComponentType; + @Nonnull + private final Query query; + + public EntityRefAdded( + @Nonnull ComponentType ambientEmitterComponentType, + @Nonnull ComponentType transformComponentType, + @Nonnull ComponentType audioComponentType, + @Nonnull ComponentType networkIdComponentType, + @Nonnull ComponentType intangibleComponentType + ) { + this.ambientEmitterComponentType = ambientEmitterComponentType; + this.transformComponentType = transformComponentType; + this.audioComponentType = audioComponentType; + this.networkIdComponentType = networkIdComponentType; + this.intangibleComponentType = intangibleComponentType; + this.query = Query.and(ambientEmitterComponentType, transformComponentType); + } @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - AmbientEmitterComponent emitterComponent = store.getComponent(ref, AmbientEmitterComponent.getComponentType()); + AmbientEmitterComponent emitterComponent = store.getComponent(ref, this.ambientEmitterComponentType); assert emitterComponent != null; - TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); + TransformComponent transformComponent = store.getComponent(ref, this.transformComponentType); assert transformComponent != null; Holder emitterHolder = EntityStore.REGISTRY.newHolder(); - emitterHolder.addComponent(TransformComponent.getComponentType(), transformComponent.clone()); + emitterHolder.addComponent(this.transformComponentType, transformComponent.clone()); AudioComponent audioComponent = new AudioComponent(); audioComponent.addSound(SoundEvent.getAssetMap().getIndex(emitterComponent.getSoundEventId())); - emitterHolder.addComponent(AudioComponent.getComponentType(), audioComponent); - emitterHolder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId())); - emitterHolder.ensureComponent(Intangible.getComponentType()); + emitterHolder.addComponent(this.audioComponentType, audioComponent); + int nextNetworkId = store.getExternalData().takeNextNetworkId(); + emitterHolder.addComponent(this.networkIdComponentType, new NetworkId(nextNetworkId)); + emitterHolder.ensureComponent(this.intangibleComponentType); emitterHolder.addComponent(EntityStore.REGISTRY.getNonSerializedComponentType(), NonSerialized.get()); - emitterComponent.setSpawnedEmitter(commandBuffer.addEntity(emitterHolder, AddReason.SPAWN)); + Ref emitterRef = commandBuffer.addEntity(emitterHolder, AddReason.SPAWN); + emitterComponent.setSpawnedEmitter(emitterRef); } @Override @@ -80,7 +132,7 @@ public class AmbientEmitterSystems { @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { if (reason == RemoveReason.REMOVE) { - AmbientEmitterComponent emitterComponent = store.getComponent(ref, AmbientEmitterComponent.getComponentType()); + AmbientEmitterComponent emitterComponent = store.getComponent(ref, this.ambientEmitterComponentType); assert emitterComponent != null; @@ -91,7 +143,7 @@ public class AmbientEmitterSystems { } } - @Nullable + @Nonnull @Override public Query getQuery() { return this.query; @@ -99,7 +151,21 @@ public class AmbientEmitterSystems { } public static class Ticking extends EntityTickingSystem { - private final Query query = Query.and(AmbientEmitterComponent.getComponentType(), TransformComponent.getComponentType()); + @Nonnull + private final ComponentType ambientEmitterComponentType; + @Nonnull + private final ComponentType transformComponentType; + @Nonnull + private final Query query; + + public Ticking( + @Nonnull ComponentType ambientEmitterComponentType, + @Nonnull ComponentType transformComponentType + ) { + this.ambientEmitterComponentType = ambientEmitterComponentType; + this.transformComponentType = transformComponentType; + this.query = Query.and(ambientEmitterComponentType, transformComponentType); + } @Override public void tick( @@ -109,29 +175,33 @@ public class AmbientEmitterSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - AmbientEmitterComponent emitter = archetypeChunk.getComponent(index, AmbientEmitterComponent.getComponentType()); + AmbientEmitterComponent emitterComponent = archetypeChunk.getComponent(index, this.ambientEmitterComponentType); - assert emitter != null; + assert emitterComponent != null; - TransformComponent transform = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + TransformComponent transformComponent = archetypeChunk.getComponent(index, this.transformComponentType); - 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, this.transformComponentType); + 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/ambience/systems/ForcedMusicSystems.java b/src/com/hypixel/hytale/builtin/ambience/systems/ForcedMusicSystems.java index 3e9d3f16..f0a9ad42 100644 --- a/src/com/hypixel/hytale/builtin/ambience/systems/ForcedMusicSystems.java +++ b/src/com/hypixel/hytale/builtin/ambience/systems/ForcedMusicSystems.java @@ -6,8 +6,10 @@ 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.RemoveReason; +import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.HolderSystem; @@ -17,26 +19,37 @@ 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.storage.EntityStore; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class ForcedMusicSystems { - private static final Query TICK_QUERY = Archetype.of( - Player.getComponentType(), PlayerRef.getComponentType(), AmbienceTracker.getComponentType() - ); - public static class PlayerAdded extends HolderSystem { + @Nonnull + private final ComponentType playerRefComponentType; + @Nonnull + private final ComponentType ambienceTrackerComponentType; + @Nonnull + private final Query query; + + public PlayerAdded( + @Nonnull ComponentType playerRefComponentType, + @Nonnull ComponentType ambienceTrackerComponentType + ) { + this.playerRefComponentType = playerRefComponentType; + this.ambienceTrackerComponentType = ambienceTrackerComponentType; + this.query = Query.and(playerRefComponentType, ambienceTrackerComponentType); + } + @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - holder.ensureComponent(AmbienceTracker.getComponentType()); + holder.ensureComponent(this.ambienceTrackerComponentType); } @Override public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { - AmbienceTracker ambienceTrackerComponent = holder.getComponent(AmbienceTracker.getComponentType()); + AmbienceTracker ambienceTrackerComponent = holder.getComponent(this.ambienceTrackerComponentType); assert ambienceTrackerComponent != null; - PlayerRef playerRefComponent = holder.getComponent(PlayerRef.getComponentType()); + PlayerRef playerRefComponent = holder.getComponent(this.playerRefComponentType); assert playerRefComponent != null; @@ -45,14 +58,35 @@ public class ForcedMusicSystems { playerRefComponent.getPacketHandler().write(pooledPacket); } - @Nullable + @Nonnull @Override public Query getQuery() { - return Query.and(PlayerRef.getComponentType(), AmbienceTracker.getComponentType()); + return this.query; } } public static class Tick extends EntityTickingSystem { + @Nonnull + private final ComponentType playerRefComponentType; + @Nonnull + private final ComponentType ambienceTrackerComponentType; + @Nonnull + private final ResourceType ambienceResourceType; + @Nonnull + private final Query query; + + public Tick( + @Nonnull ComponentType playerComponentType, + @Nonnull ComponentType playerRefComponentType, + @Nonnull ComponentType ambienceTrackerComponentType, + @Nonnull ResourceType ambienceResourceType + ) { + this.playerRefComponentType = playerRefComponentType; + this.ambienceTrackerComponentType = ambienceTrackerComponentType; + this.ambienceResourceType = ambienceResourceType; + this.query = Archetype.of(playerComponentType, playerRefComponentType, ambienceTrackerComponentType); + } + @Override public void tick( float dt, @@ -61,23 +95,29 @@ public class ForcedMusicSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - AmbienceResource ambienceResource = store.getResource(AmbienceResource.getResourceType()); - AmbienceTracker tracker = archetypeChunk.getComponent(index, AmbienceTracker.getComponentType()); - PlayerRef playerRef = archetypeChunk.getComponent(index, PlayerRef.getComponentType()); - int have = tracker.getForcedMusicIndex(); + AmbienceResource ambienceResource = store.getResource(this.ambienceResourceType); + AmbienceTracker ambienceTrackerComponent = archetypeChunk.getComponent(index, this.ambienceTrackerComponentType); + + assert ambienceTrackerComponent != null; + + PlayerRef playerRefComponent = archetypeChunk.getComponent(index, this.playerRefComponentType); + + assert playerRefComponent != null; + + int have = ambienceTrackerComponent.getForcedMusicIndex(); int desired = ambienceResource.getForcedMusicIndex(); if (have != desired) { - tracker.setForcedMusicIndex(desired); - UpdateEnvironmentMusic pooledPacket = tracker.getMusicPacket(); + ambienceTrackerComponent.setForcedMusicIndex(desired); + UpdateEnvironmentMusic pooledPacket = ambienceTrackerComponent.getMusicPacket(); pooledPacket.environmentIndex = desired; - playerRef.getPacketHandler().write(pooledPacket); + playerRefComponent.getPacketHandler().write(pooledPacket); } } - @Nullable + @Nonnull @Override public Query getQuery() { - return ForcedMusicSystems.TICK_QUERY; + 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..a8536fa0 100644 --- a/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorGamePacketHandler.java +++ b/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorGamePacketHandler.java @@ -95,7 +95,7 @@ public class AssetEditorGamePacketHandler implements SubPacketHandler { private boolean lacksPermission(@Nonnull Player player, boolean shouldShowDenialMessage) { if (!player.hasPermission("hytale.editor.asset")) { if (shouldShowDenialMessage) { - player.sendMessage(Messages.USAGE_DENIED_MESSAGE); + player.sendMessage(Messages.USAGE_DENIED); } return true; diff --git a/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorPacketHandler.java b/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorPacketHandler.java index d692ed34..8b00e1ae 100644 --- a/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorPacketHandler.java +++ b/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorPacketHandler.java @@ -101,7 +101,7 @@ public class AssetEditorPacketHandler extends GenericPacketHandler { @Nonnull @Override public String getIdentifier() { - return "{Editor(" + NettyUtil.formatRemoteAddress(this.channel) + "), " + this.editorClient.getUuid() + ", " + this.editorClient.getUsername() + "}"; + return "{Editor(" + NettyUtil.formatRemoteAddress(this.getChannel()) + "), " + this.editorClient.getUuid() + ", " + this.editorClient.getUsername() + "}"; } @Override @@ -137,6 +137,7 @@ public class AssetEditorPacketHandler extends GenericPacketHandler { this.registerHandler(316, p -> this.handle((AssetEditorCreateAssetPack)p)); this.registerHandler(315, p -> this.handle((AssetEditorUpdateAssetPack)p)); this.registerHandler(317, p -> this.handle((AssetEditorDeleteAssetPack)p)); + this.registerHandler(232, p -> this.handle((UpdateLanguage)p)); } public void handle(@Nonnull AssetEditorSubscribeModifiedAssetsChanges packet) { @@ -400,16 +401,16 @@ public class AssetEditorPacketHandler extends GenericPacketHandler { "%s - %s at %s left with reason: %s - %s", this.editorClient.getUuid(), this.editorClient.getUsername(), - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(this.getChannel()), packet.type.name(), packet.reason ); - this.channel.close(); + this.getChannel().close(); } private boolean lacksPermission(int token) { if (!this.editorClient.hasPermission("hytale.editor.asset")) { - this.editorClient.sendFailureReply(token, Messages.USAGE_DENIED_MESSAGE); + this.editorClient.sendFailureReply(token, Messages.USAGE_DENIED); return true; } else { return false; @@ -422,7 +423,7 @@ public class AssetEditorPacketHandler extends GenericPacketHandler { private boolean lacksPermission(String permissionId) { if (!this.editorClient.hasPermission(permissionId)) { - this.editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.USAGE_DENIED_MESSAGE); + this.editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.USAGE_DENIED); return true; } else { return false; @@ -431,7 +432,7 @@ public class AssetEditorPacketHandler extends GenericPacketHandler { private boolean lacksPermission(int token, String permissionId) { if (!this.editorClient.hasPermission(permissionId)) { - this.editorClient.sendFailureReply(token, Messages.USAGE_DENIED_MESSAGE); + this.editorClient.sendFailureReply(token, Messages.USAGE_DENIED); return true; } else { return false; diff --git a/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorPlugin.java b/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorPlugin.java index 0dfadceb..5f8e3721 100644 --- a/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorPlugin.java +++ b/src/com/hypixel/hytale/builtin/asseteditor/AssetEditorPlugin.java @@ -36,8 +36,9 @@ import com.hypixel.hytale.common.util.FormatUtil; import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.event.EventRegistry; import com.hypixel.hytale.event.IEventDispatcher; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorAsset; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorAssetListUpdate; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorAssetPackSetup; @@ -69,6 +70,7 @@ import com.hypixel.hytale.protocol.packets.asseteditor.SchemaFile; import com.hypixel.hytale.protocol.packets.asseteditor.TimestampedAssetReference; import com.hypixel.hytale.protocol.packets.assets.UpdateTranslations; import com.hypixel.hytale.server.core.HytaleServer; +import com.hypixel.hytale.server.core.HytaleServerConfig; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.Options; import com.hypixel.hytale.server.core.asset.AssetModule; @@ -76,6 +78,7 @@ import com.hypixel.hytale.server.core.asset.AssetPackRegisterEvent; import com.hypixel.hytale.server.core.asset.AssetPackUnregisterEvent; import com.hypixel.hytale.server.core.asset.AssetRegistryLoader; import com.hypixel.hytale.server.core.asset.common.events.CommonAssetMonitorEvent; +import com.hypixel.hytale.server.core.config.ModConfig; import com.hypixel.hytale.server.core.io.PacketHandler; import com.hypixel.hytale.server.core.io.ServerManager; import com.hypixel.hytale.server.core.io.handlers.InitialPacketHandler; @@ -96,7 +99,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -118,22 +120,32 @@ import org.bson.BsonValue; public class AssetEditorPlugin extends JavaPlugin { private static AssetEditorPlugin instance; + @Nonnull private final StampedLock globalEditLock = new StampedLock(); + @Nonnull private final Map> uuidToEditorClients = new ConcurrentHashMap<>(); + @Nonnull private final Map clientOpenAssetPathMapping = new ConcurrentHashMap<>(); + @Nonnull private final Set clientsSubscribedToModifiedAssetsChanges = ConcurrentHashMap.newKeySet(); @Nonnull private Map schemas = new Object2ObjectOpenHashMap<>(); private AssetEditorSetupSchemas setupSchemasPacket; + @Nonnull private final StampedLock initLock = new StampedLock(); + @Nonnull private final Set initQueue = new HashSet<>(); @Nonnull private AssetEditorPlugin.InitState initState = AssetEditorPlugin.InitState.NOT_INITIALIZED; @Nullable private ScheduledFuture scheduledReinitFuture; + @Nonnull private final Map assetPackDataSources = new ConcurrentHashMap<>(); + @Nonnull private final AssetTypeRegistry assetTypeRegistry = new AssetTypeRegistry(); + @Nonnull private final UndoRedoManager undoRedoManager = new UndoRedoManager(); + @Nullable private ScheduledFuture pingClientsTask; public static AssetEditorPlugin get() { @@ -145,7 +157,7 @@ public class AssetEditorPlugin extends JavaPlugin { } @Nullable - DataSource registerDataSourceForPack(AssetPack assetPack) { + DataSource registerDataSourceForPack(@Nonnull AssetPack assetPack) { PluginManifest manifest = assetPack.getManifest(); if (manifest == null) { this.getLogger().at(Level.SEVERE).log("Could not load asset pack manifest for " + assetPack.getName()); @@ -160,6 +172,7 @@ public class AssetEditorPlugin extends JavaPlugin { @Override protected void setup() { instance = this; + EventRegistry eventRegistry = this.getEventRegistry(); for (AssetPack assetPack : AssetModule.get().getAssetPacks()) { this.registerDataSourceForPack(assetPack); @@ -180,13 +193,13 @@ public class AssetEditorPlugin extends JavaPlugin { this.assetTypeRegistry.registerAssetType(new CommonAssetTypeHandler("Sound", null, ".ogg", AssetEditorEditorType.None)); this.assetTypeRegistry.registerAssetType(new CommonAssetTypeHandler("UI", null, ".ui", AssetEditorEditorType.Text)); this.assetTypeRegistry.registerAssetType(new CommonAssetTypeHandler("Language", null, ".lang", AssetEditorEditorType.Text)); - this.getEventRegistry().register(RegisterAssetStoreEvent.class, this::onRegisterAssetStore); - this.getEventRegistry().register(RemoveAssetStoreEvent.class, this::onUnregisterAssetStore); - this.getEventRegistry().register(AssetPackRegisterEvent.class, this::onRegisterAssetPack); - this.getEventRegistry().register(AssetPackUnregisterEvent.class, this::onUnregisterAssetPack); - this.getEventRegistry().register(AssetStoreMonitorEvent.class, this::onAssetMonitor); - this.getEventRegistry().register(CommonAssetMonitorEvent.class, this::onAssetMonitor); - this.getEventRegistry().register(MessagesUpdated.class, this::onI18nMessagesUpdated); + eventRegistry.register(RegisterAssetStoreEvent.class, this::onRegisterAssetStore); + eventRegistry.register(RemoveAssetStoreEvent.class, this::onUnregisterAssetStore); + eventRegistry.register(AssetPackRegisterEvent.class, this::onRegisterAssetPack); + eventRegistry.register(AssetPackUnregisterEvent.class, this::onUnregisterAssetPack); + eventRegistry.register(AssetStoreMonitorEvent.class, this::onAssetMonitor); + eventRegistry.register(CommonAssetMonitorEvent.class, this::onAssetMonitor); + eventRegistry.register(MessagesUpdated.class, this::onI18nMessagesUpdated); AssetSpecificFunctionality.setup(); } @@ -210,38 +223,49 @@ public class AssetEditorPlugin extends JavaPlugin { } } - this.pingClientsTask.cancel(false); + if (this.pingClientsTask != null) { + this.pingClientsTask.cancel(false); + } else { + this.getLogger().at(Level.WARNING).log("Failed to cancel ping clients task as it was null"); + } for (DataSource dataSource : this.assetPackDataSources.values()) { dataSource.shutdown(); } } - public DataSource getDataSourceForPath(AssetPath path) { + @Nullable + public DataSource getDataSourceForPath(@Nonnull AssetPath path) { return this.getDataSourceForPack(path.packId()); } - public DataSource getDataSourceForPack(String assetPack) { + @Nullable + public DataSource getDataSourceForPack(@Nonnull String assetPack) { return this.assetPackDataSources.get(assetPack); } + @Nonnull public Collection getDataSources() { return this.assetPackDataSources.values(); } + @Nonnull public AssetTypeRegistry getAssetTypeRegistry() { return this.assetTypeRegistry; } - public Schema getSchema(String id) { + @Nullable + public Schema getSchema(@Nonnull String id) { return this.schemas.get(id); } + @Nonnull public Map getClientOpenAssetPathMapping() { return this.clientOpenAssetPathMapping; } - public Set getEditorClients(UUID uuid) { + @Nullable + public Set getEditorClients(@Nonnull UUID uuid) { return this.uuidToEditorClients.get(uuid); } @@ -259,7 +283,7 @@ public class AssetEditorPlugin extends JavaPlugin { } @Nonnull - private List getClientsWithOpenAssetPath(AssetPath path) { + private List getClientsWithOpenAssetPath(@Nonnull AssetPath path) { if (this.clientOpenAssetPathMapping.isEmpty()) { return Collections.emptyList(); } else { @@ -275,11 +299,12 @@ public class AssetEditorPlugin extends JavaPlugin { } } - public AssetPath getOpenAssetPath(EditorClient editorClient) { + @Nullable + public AssetPath getOpenAssetPath(@Nonnull EditorClient editorClient) { return this.clientOpenAssetPathMapping.get(editorClient); } - private void onRegisterAssetPack(AssetPackRegisterEvent event) { + private void onRegisterAssetPack(@Nonnull AssetPackRegisterEvent event) { if (!this.assetPackDataSources.containsKey(event.getAssetPack().getName())) { DataSource dataSource = this.registerDataSourceForPack(event.getAssetPack()); if (dataSource != null) { @@ -307,7 +332,7 @@ public class AssetEditorPlugin extends JavaPlugin { } } - private void onUnregisterAssetPack(AssetPackUnregisterEvent event) { + private void onUnregisterAssetPack(@Nonnull AssetPackUnregisterEvent event) { if (this.assetPackDataSources.containsKey(event.getAssetPack().getName())) { DataSource dataSource = this.assetPackDataSources.remove(event.getAssetPack().getName()); dataSource.shutdown(); @@ -633,7 +658,7 @@ public class AssetEditorPlugin extends JavaPlugin { this.getLogger().at(Level.INFO).log("Done Initializing %s", editorClient.getUsername()); } - public void handleEditorClientDisconnected(@Nonnull EditorClient editorClient, PacketHandler.DisconnectReason disconnectReason) { + public void handleEditorClientDisconnected(@Nonnull EditorClient editorClient, @Nonnull PacketHandler.DisconnectReason disconnectReason) { IEventDispatcher dispatch = HytaleServer.get() .getEventBus() .dispatchFor(AssetEditorClientDisconnectEvent.class); @@ -655,11 +680,11 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleDeleteAssetPack(@Nonnull EditorClient editorClient, @Nonnull String packId) { if (packId.equalsIgnoreCase("Hytale:Hytale")) { - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSET_PACK); } else { DataSource dataSource = this.getDataSourceForPack(packId); if (dataSource == null) { - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSET_PACK); } else { AssetModule.get().unregisterPack(packId); @@ -692,9 +717,7 @@ public class AssetEditorPlugin extends JavaPlugin { } if (!isInModsDirectory) { - editorClient.sendPopupNotification( - AssetEditorPopupNotificationType.Error, Message.translation("server.assetEditor.messages.packOutsideDirectory") - ); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.PACK_OUTSIDE_DIRECTORY); } else { try { FileUtil.deleteDirectory(targetPath); @@ -708,17 +731,17 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleUpdateAssetPack(@Nonnull EditorClient editorClient, @Nonnull String packId, @Nonnull AssetPackManifest packetManifest) { if (packId.equals("Hytale:Hytale")) { - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSET_PACK); } else { DataSource dataSource = this.getDataSourceForPack(packId); if (dataSource == null) { - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSET_PACK); } else if (dataSource.isImmutable()) { - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.ASSETS_READ_ONLY); } else { PluginManifest manifest = dataSource.getManifest(); if (manifest == null) { - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Message.translation("server.assetEditor.messages.manifestNotFound")); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.MANIFEST_NOT_FOUND); } else { boolean didIdentifierChange = false; if (packetManifest.name != null && !packetManifest.name.isEmpty() && !manifest.getName().equals(packetManifest.name)) { @@ -742,11 +765,9 @@ public class AssetEditorPlugin extends JavaPlugin { if (packetManifest.version != null && !packetManifest.version.isEmpty()) { try { manifest.setVersion(Semver.fromString(packetManifest.version)); - } catch (IllegalArgumentException var14) { - this.getLogger().at(Level.WARNING).withCause(var14).log("Invalid version format: %s", packetManifest.version); - editorClient.sendPopupNotification( - AssetEditorPopupNotificationType.Error, Message.translation("server.assetEditor.messages.invalidVersionFormat") - ); + } catch (IllegalArgumentException var15) { + this.getLogger().at(Level.WARNING).withCause(var15).log("Invalid version format: %s", packetManifest.version); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.INVALID_VERSION_FORMAT); return; } } @@ -765,26 +786,38 @@ public class AssetEditorPlugin extends JavaPlugin { manifest.setAuthors(authors); } + if (packetManifest.serverVersion != null) { + manifest.setServerVersion(packetManifest.serverVersion); + } + Path manifestPath = dataSource.getRootPath().resolve("manifest.json"); try { BsonUtil.writeSync(manifestPath, PluginManifest.CODEC, manifest, this.getLogger()); this.getLogger().at(Level.INFO).log("Saved manifest for pack %s", packId); - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Success, Message.translation("server.assetEditor.messages.manifestSaved")); - } catch (IOException var13) { - this.getLogger().at(Level.SEVERE).withCause(var13).log("Failed to save manifest for pack %s", packId); - editorClient.sendPopupNotification( - AssetEditorPopupNotificationType.Error, Message.translation("server.assetEditor.messages.manifestSaveFailed") - ); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Success, Messages.MANIFEST_SAVED); + } catch (IOException var14) { + this.getLogger().at(Level.SEVERE).withCause(var14).log("Failed to save manifest for pack %s", packId); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.MANIFEST_SAVE_FAILED); } this.broadcastPackAddedOrUpdated(packId, manifest); if (didIdentifierChange) { - String newPackId = new PluginIdentifier(manifest).toString(); + PluginIdentifier newPackIdentifier = new PluginIdentifier(manifest); + String newPackId = newPackIdentifier.toString(); Path packPath = dataSource.getRootPath(); + HytaleServerConfig serverConfig = HytaleServer.get().getConfig(); + HytaleServerConfig.setBoot(serverConfig, newPackIdentifier, true); + Map modConfig = serverConfig.getModConfig(); + modConfig.remove(PluginIdentifier.fromString(packId)); + serverConfig.markChanged(); + if (serverConfig.consumeHasChanged()) { + HytaleServerConfig.save(serverConfig).join(); + } + AssetModule assetModule = AssetModule.get(); assetModule.unregisterPack(packId); - assetModule.registerPack(newPackId, packPath, manifest); + assetModule.registerPack(newPackId, packPath, manifest, false); } } } @@ -793,7 +826,7 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleCreateAssetPack(@Nonnull EditorClient editorClient, @Nonnull AssetPackManifest packetManifest, int requestToken) { if (packetManifest.name == null || packetManifest.name.isEmpty()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.packNameRequired")); + editorClient.sendFailureReply(requestToken, Messages.PACK_NAME_REQUIRED); } else if (packetManifest.group != null && !packetManifest.group.isEmpty()) { PluginManifest manifest = new PluginManifest(); manifest.setName(packetManifest.name); @@ -809,9 +842,9 @@ public class AssetEditorPlugin extends JavaPlugin { if (packetManifest.version != null && !packetManifest.version.isEmpty()) { try { manifest.setVersion(Semver.fromString(packetManifest.version)); - } catch (IllegalArgumentException var12) { - this.getLogger().at(Level.WARNING).withCause(var12).log("Invalid version format: %s", packetManifest.version); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.invalidVersionFormat")); + } catch (IllegalArgumentException var13) { + this.getLogger().at(Level.WARNING).withCause(var13).log("Invalid version format: %s", packetManifest.version); + editorClient.sendFailureReply(requestToken, Messages.INVALID_VERSION_FORMAT); return; } } @@ -830,9 +863,10 @@ public class AssetEditorPlugin extends JavaPlugin { manifest.setAuthors(authors); } + manifest.setServerVersion(packetManifest.serverVersion); String packId = new PluginIdentifier(manifest).toString(); if (this.assetPackDataSources.containsKey(packId)) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.packAlreadyExists")); + editorClient.sendFailureReply(requestToken, Messages.PACK_ALREADY_EXISTS); } else { Path modsPath = PluginManager.MODS_PATH; String dirName = AssetPathUtil.removeInvalidFileNameChars( @@ -840,33 +874,41 @@ public class AssetEditorPlugin extends JavaPlugin { ); Path normalized = Path.of(dirName).normalize(); if (AssetPathUtil.isInvalidFileName(normalized)) { - editorClient.sendFailureReply(requestToken, Messages.INVALID_FILENAME_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.INVALID_FILE_NAME); } else { Path packPath = modsPath.resolve(normalized).normalize(); if (!packPath.startsWith(modsPath)) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.packOutsideDirectory")); + editorClient.sendFailureReply(requestToken, Messages.PACK_OUTSIDE_DIRECTORY); } else if (Files.exists(packPath)) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.packAlreadyExistsAtPath")); + editorClient.sendFailureReply(requestToken, Messages.PACK_ALREADY_EXISTS_AT_PATH); } else { try { Files.createDirectories(packPath); Path manifestPath = packPath.resolve("manifest.json"); BsonUtil.writeSync(manifestPath, PluginManifest.CODEC, manifest, this.getLogger()); - AssetModule.get().registerPack(packId, packPath, manifest); - editorClient.sendSuccessReply(requestToken, Message.translation("server.assetEditor.messages.packCreated")); + HytaleServerConfig serverConfig = HytaleServer.get().getConfig(); + HytaleServerConfig.setBoot(serverConfig, new PluginIdentifier(manifest), true); + serverConfig.markChanged(); + if (serverConfig.consumeHasChanged()) { + HytaleServerConfig.save(serverConfig).join(); + } + + AssetModule.get().registerPack(packId, packPath, manifest, false); + editorClient.sendSuccessReply(requestToken, Messages.PACK_CREATED); this.getLogger().at(Level.INFO).log("Created new pack: %s at %s", packId, packPath); - } catch (IOException var11) { - this.getLogger().at(Level.SEVERE).withCause(var11).log("Failed to create pack %s", packId); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.packCreationFailed")); + } catch (IOException var12) { + this.getLogger().at(Level.SEVERE).withCause(var12).log("Failed to create pack %s", packId); + editorClient.sendFailureReply(requestToken, Messages.PACK_CREATION_FAILED); } } } } } else { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.packGroupRequired")); + editorClient.sendFailureReply(requestToken, Messages.PACK_GROUP_REQUIRED); } } + @Nonnull private static AssetPackManifest toManifestPacket(@Nonnull PluginManifest manifest) { AssetPackManifest packet = new AssetPackManifest(); packet.name = manifest.getName(); @@ -874,6 +916,7 @@ public class AssetEditorPlugin extends JavaPlugin { packet.group = manifest.getGroup(); packet.version = manifest.getVersion() != null ? manifest.getVersion().toString() : ""; packet.website = manifest.getWebsite() != null ? manifest.getWebsite() : ""; + packet.serverVersion = manifest.getServerVersion() != null ? manifest.getServerVersion() : ""; List authors = new ObjectArrayList<>(); for (AuthorInfo a : manifest.getAuthors()) { @@ -887,7 +930,7 @@ public class AssetEditorPlugin extends JavaPlugin { return packet; } - private void broadcastPackAddedOrUpdated(String packId, PluginManifest manifest) { + private void broadcastPackAddedOrUpdated(@Nonnull String packId, @Nonnull PluginManifest manifest) { AssetPackManifest manifestPacket = toManifestPacket(manifest); for (Set clients : this.uuidToEditorClients.values()) { @@ -923,7 +966,7 @@ public class AssetEditorPlugin extends JavaPlugin { editorClient.getPacketHandler().write(new AssetEditorExportAssetInitialize(new AssetEditorAsset(null, assetPath.toPacket()), null, 0, false)); } else { byte[][] parts = ArrayUtil.split(bytes, 2621440); - Packet[] packets = new Packet[2 + parts.length]; + ToClientPacket[] packets = new ToClientPacket[2 + parts.length]; packets[0] = new AssetEditorExportAssetInitialize(new AssetEditorAsset(null, assetPath.toPacket()), null, bytes.length, false); for (int partIndex = 0; partIndex < parts.length; partIndex++) { @@ -993,11 +1036,11 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleAssetUpdate(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath, @Nonnull byte[] data, int requestToken) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); } else if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else { AssetTypeHandler assetTypeHandler = this.assetTypeRegistry.tryGetAssetTypeHandler(assetPath.path(), editorClient, requestToken); if (assetTypeHandler != null) { @@ -1007,13 +1050,13 @@ public class AssetEditorPlugin extends JavaPlugin { try { if (!dataSource.doesAssetExist(assetPath.path())) { this.getLogger().at(Level.WARNING).log("%s does not exist", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.update.doesntExist")); + editorClient.sendFailureReply(requestToken, Messages.UPDATE_DOESNT_EXIST); return; } if (!assetTypeHandler.isValidData(data)) { this.getLogger().at(Level.WARNING).log("Failed to validate data for %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.createAsset.failed")); + editorClient.sendFailureReply(requestToken, Messages.CREATE_ASSET_FAILED); return; } @@ -1026,7 +1069,7 @@ public class AssetEditorPlugin extends JavaPlugin { } this.getLogger().at(Level.WARNING).log("Failed to update asset %s in data source!", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.update.failed")); + editorClient.sendFailureReply(requestToken, Messages.UPDATE_FAILED); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1048,26 +1091,26 @@ public class AssetEditorPlugin extends JavaPlugin { int requestToken ) { AssetTypeHandler assetTypeHandler = this.assetTypeRegistry.getAssetTypeHandler(assetType); - if (!(assetTypeHandler instanceof JsonTypeHandler)) { + if (!(assetTypeHandler instanceof JsonTypeHandler jsonTypeHandler)) { this.getLogger().at(Level.WARNING).log("Invalid asset type %s", assetType); editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.unknownAssetType").param("assetType", assetType)); } else { DataSource dataSource; - if (assetIndex > -1 && assetTypeHandler instanceof AssetStoreTypeHandler) { - AssetStore assetStore = ((AssetStoreTypeHandler)assetTypeHandler).getAssetStore(); + if (assetIndex > -1 && assetTypeHandler instanceof AssetStoreTypeHandler assetStoreTypeHandler) { + AssetStore assetStore = assetStoreTypeHandler.getAssetStore(); AssetMap assetMap = assetStore.getAssetMap(); String keyString = AssetStoreUtil.getIdFromIndex(assetStore, assetIndex); Object key = assetStore.decodeStringKey(keyString); Path storedPath = assetMap.getPath(key); String storedAssetPack = assetMap.getAssetPack(key); if (storedPath == null || storedAssetPack == null) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.unknownAssetIndex")); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_INDEX); return; } dataSource = this.getDataSourceForPack(storedAssetPack); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); return; } @@ -1075,18 +1118,18 @@ public class AssetEditorPlugin extends JavaPlugin { } else { dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); return; } } if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else if (!assetPath.path().startsWith(assetTypeHandler.getRootPath())) { this.getLogger().at(Level.WARNING).log("%s is not within valid asset directory", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.directoryOutsideRoot")); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ROOT); } else { String fileExtension = PathUtil.getFileExtension(assetPath.path()); if (!fileExtension.equalsIgnoreCase(assetTypeHandler.getConfig().fileExtension)) { @@ -1107,7 +1150,7 @@ public class AssetEditorPlugin extends JavaPlugin { byte[] bytes = dataSource.getAssetBytes(assetPath.path()); if (bytes == null) { this.getLogger().at(Level.WARNING).log("%s does not exist", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.update.doesntExist")); + editorClient.sendFailureReply(requestToken, Messages.UPDATE_DOESNT_EXIST); return; } @@ -1118,9 +1161,9 @@ public class AssetEditorPlugin extends JavaPlugin { asset = this.applyCommandsToAsset(bytes, assetPath, commands, rebuildCacheBuilder); String json = BsonUtil.toJson(asset) + "\n"; bytes = json.getBytes(StandardCharsets.UTF_8); - } catch (Exception var23) { - this.getLogger().at(Level.WARNING).withCause(var23).log("Failed to apply commands to %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.update.failed")); + } catch (Exception var24) { + this.getLogger().at(Level.WARNING).withCause(var24).log("Failed to apply commands to %s", assetPath); + editorClient.sendFailureReply(requestToken, Messages.UPDATE_FAILED); return; } @@ -1135,18 +1178,17 @@ public class AssetEditorPlugin extends JavaPlugin { this.updateJsonAssetForConnectedClients(assetPath, commands, editorClient); editorClient.sendSuccessReply(requestToken); this.sendModifiedAssetsUpdateToConnectedUsers(); - ((JsonTypeHandler)assetTypeHandler) - .loadAssetFromDocument( - assetPath, - dataSource.getFullPathToAssetData(assetPath.path()), - asset.clone(), - new AssetUpdateQuery(rebuildCacheBuilder.build()), - editorClient - ); + jsonTypeHandler.loadAssetFromDocument( + assetPath, + dataSource.getFullPathToAssetData(assetPath.path()), + asset.clone(), + new AssetUpdateQuery(rebuildCacheBuilder.build()), + editorClient + ); return; } - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.update.failed")); + editorClient.sendFailureReply(requestToken, Messages.UPDATE_FAILED); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1158,17 +1200,17 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleUndo(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath, int requestToken) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); } else if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else { AssetTypeHandler assetTypeHandler = this.assetTypeRegistry.tryGetAssetTypeHandler(assetPath.path(), editorClient, requestToken); if (assetTypeHandler != null) { if (!(assetTypeHandler instanceof JsonTypeHandler)) { this.getLogger().at(Level.WARNING).log("Undo can only be applied to an instance of JsonTypeHandler"); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.invalidAssetType")); + editorClient.sendFailureReply(requestToken, Messages.INVALID_ASSET_TYPE); } else { long stamp = this.globalEditLock.writeLock(); @@ -1176,7 +1218,7 @@ public class AssetEditorPlugin extends JavaPlugin { AssetUndoRedoInfo undoRedo = this.undoRedoManager.getUndoRedoStack(assetPath); if (undoRedo == null || undoRedo.undoStack.isEmpty()) { this.getLogger().at(Level.INFO).log("Nothing to undo"); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.undo.empty")); + editorClient.sendFailureReply(requestToken, Messages.UNDO_EMPTY); return; } @@ -1195,7 +1237,7 @@ public class AssetEditorPlugin extends JavaPlugin { byte[] bytes = dataSource.getAssetBytes(assetPath.path()); if (bytes == null) { this.getLogger().at(Level.WARNING).log("%s does not exist", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.update.doesntExist")); + editorClient.sendFailureReply(requestToken, Messages.UPDATE_DOESNT_EXIST); return; } @@ -1208,7 +1250,7 @@ public class AssetEditorPlugin extends JavaPlugin { bytes = json.getBytes(StandardCharsets.UTF_8); } catch (Exception var18) { this.getLogger().at(Level.WARNING).withCause(var18).log("Failed to undo for %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.undo.failed")); + editorClient.sendFailureReply(requestToken, Messages.UNDO_FAILED); return; } @@ -1229,7 +1271,7 @@ public class AssetEditorPlugin extends JavaPlugin { return; } - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.undo.failed")); + editorClient.sendFailureReply(requestToken, Messages.UNDO_FAILED); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1241,17 +1283,17 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleRedo(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath, int requestToken) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); } else if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else { AssetTypeHandler assetTypeHandler = this.assetTypeRegistry.tryGetAssetTypeHandler(assetPath.path(), editorClient, requestToken); if (assetTypeHandler != null) { if (!(assetTypeHandler instanceof JsonTypeHandler)) { this.getLogger().at(Level.WARNING).log("Redo can only be applied to an instance of JsonTypeHandler"); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.invalidAssetType")); + editorClient.sendFailureReply(requestToken, Messages.INVALID_ASSET_TYPE); } else { long stamp = this.globalEditLock.writeLock(); @@ -1259,14 +1301,14 @@ public class AssetEditorPlugin extends JavaPlugin { AssetUndoRedoInfo undoRedo = this.undoRedoManager.getUndoRedoStack(assetPath); if (undoRedo == null || undoRedo.redoStack.isEmpty()) { this.getLogger().at(Level.WARNING).log("Nothing to redo"); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.redo.empty")); + editorClient.sendFailureReply(requestToken, Messages.REDO_EMPTY); return; } byte[] bytes = dataSource.getAssetBytes(assetPath.path()); if (bytes == null) { this.getLogger().at(Level.WARNING).log("%s does not exist", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.update.doesntExist")); + editorClient.sendFailureReply(requestToken, Messages.UPDATE_DOESNT_EXIST); return; } @@ -1280,7 +1322,7 @@ public class AssetEditorPlugin extends JavaPlugin { bytes = json.getBytes(StandardCharsets.UTF_8); } catch (Exception var17) { this.getLogger().at(Level.WARNING).withCause(var17).log("Failed to redo for %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.redo.failed")); + editorClient.sendFailureReply(requestToken, Messages.REDO_FAILED); return; } @@ -1301,7 +1343,7 @@ public class AssetEditorPlugin extends JavaPlugin { return; } - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.redo.failed")); + editorClient.sendFailureReply(requestToken, Messages.REDO_FAILED); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1313,16 +1355,16 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleFetchAsset(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath, int requestToken) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else if (this.assetTypeRegistry.tryGetAssetTypeHandler(assetPath.path(), editorClient, requestToken) != null) { long stamp = this.globalEditLock.readLock(); try { if (!dataSource.doesAssetExist(assetPath.path())) { this.getLogger().at(Level.WARNING).log("%s is not a regular file", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.fetchAsset.doesntExist")); + editorClient.sendFailureReply(requestToken, Messages.FETCH_ASSET_DOESNT_EXIST); return; } @@ -1334,7 +1376,7 @@ public class AssetEditorPlugin extends JavaPlugin { } this.getLogger().at(Level.INFO).log("Failed to get '%s'", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.fetchAsset.failed")); + editorClient.sendFailureReply(requestToken, Messages.FETCH_ASSET_FAILED); } finally { this.globalEditLock.unlockRead(stamp); } @@ -1344,9 +1386,9 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleFetchJsonAssetWithParents(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath, boolean isFromOpenedTab, int requestToken) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else if (this.assetTypeRegistry.tryGetAssetTypeHandler(assetPath.path(), editorClient, requestToken) != null) { long stamp = this.globalEditLock.readLock(); @@ -1362,7 +1404,7 @@ public class AssetEditorPlugin extends JavaPlugin { } this.getLogger().at(Level.INFO).log("Failed to get '%s'", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.fetchAsset.failed")); + editorClient.sendFailureReply(requestToken, Messages.FETCH_ASSET_FAILED); } finally { this.globalEditLock.unlockRead(stamp); } @@ -1372,43 +1414,39 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleRequestChildIds(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.UNKNOWN_ASSET_PACK); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); + } else if (!(this.assetTypeRegistry.getAssetTypeHandlerForPath(assetPath.path()) instanceof AssetStoreTypeHandler assetStoreTypeHandler)) { + this.getLogger().at(Level.WARNING).log("Invalid asset type for %s", assetPath); + editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.REQUEST_CHILD_IDS_ASSET_TYPE_MISSING); } else { - AssetTypeHandler assetTypeHandler = this.assetTypeRegistry.getAssetTypeHandlerForPath(assetPath.path()); - if (!(assetTypeHandler instanceof AssetStoreTypeHandler)) { - this.getLogger().at(Level.WARNING).log("Invalid asset type for %s", assetPath); - editorClient.sendPopupNotification( - AssetEditorPopupNotificationType.Error, Message.translation("server.assetEditor.messages.requestChildIds.assetTypeMissing") - ); - } else { - AssetStore assetStore = ((AssetStoreTypeHandler)assetTypeHandler).getAssetStore(); - Object key = assetStore.decodeFilePathKey(assetPath.path()); - Set children = assetStore.getAssetMap().getChildren(key); - HashSet childrenIds = new HashSet<>(); - if (children != null) { - for (Object child : children) { - if (assetStore.getAssetMap().getPath(child) != null) { - childrenIds.add(child.toString()); - } + AssetStore assetStore = assetStoreTypeHandler.getAssetStore(); + AssetMap assetMap = assetStore.getAssetMap(); + Object key = assetStore.decodeFilePathKey(assetPath.path()); + Set children = assetMap.getChildren(key); + HashSet childrenIds = new HashSet(); + if (children != null) { + for (Object child : children) { + if (assetMap.getPath(child) != null) { + childrenIds.add(child.toString()); } } - - this.getLogger().at(Level.INFO).log("Children ids for '%s': %s", key.toString(), childrenIds); - editorClient.getPacketHandler().write(new AssetEditorRequestChildrenListReply(assetPath.toPacket(), childrenIds.toArray(String[]::new))); } + + this.getLogger().at(Level.INFO).log("Children ids for '%s': %s", key.toString(), childrenIds); + editorClient.getPacketHandler().write(new AssetEditorRequestChildrenListReply(assetPath.toPacket(), childrenIds.toArray(String[]::new))); } } public void handleDeleteAsset(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath, int requestToken) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); } else if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else { AssetTypeHandler assetTypeHandler = this.assetTypeRegistry.tryGetAssetTypeHandler(assetPath.path(), editorClient, requestToken); if (assetTypeHandler != null) { @@ -1418,7 +1456,7 @@ public class AssetEditorPlugin extends JavaPlugin { try { if (!dataSource.doesAssetExist(assetPath.path())) { this.getLogger().at(Level.WARNING).log("%s does not exist", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.deleteAsset.alreadyDeleted")); + editorClient.sendFailureReply(requestToken, Messages.DELETE_ASSET_ALREADY_DELETED); return; } @@ -1434,7 +1472,7 @@ public class AssetEditorPlugin extends JavaPlugin { } this.getLogger().at(Level.WARNING).log("Failed to delete %s from data source", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.failedToDeleteAsset")); + editorClient.sendFailureReply(requestToken, Messages.FAILED_TO_DELETE_ASSET); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1447,24 +1485,24 @@ public class AssetEditorPlugin extends JavaPlugin { } } - public void handleSubscribeToModifiedAssetsChanges(EditorClient editorClient) { + public void handleSubscribeToModifiedAssetsChanges(@Nonnull EditorClient editorClient) { this.clientsSubscribedToModifiedAssetsChanges.add(editorClient); } - public void handleUnsubscribeFromModifiedAssetsChanges(EditorClient editorClient) { + public void handleUnsubscribeFromModifiedAssetsChanges(@Nonnull EditorClient editorClient) { this.clientsSubscribedToModifiedAssetsChanges.remove(editorClient); } public void handleRenameAsset(@Nonnull EditorClient editorClient, @Nonnull AssetPath oldAssetPath, @Nonnull AssetPath newAssetPath, int requestToken) { DataSource dataSource = this.getDataSourceForPath(oldAssetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); } else if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, oldAssetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else if (!this.isValidPath(dataSource, newAssetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else { AssetTypeHandler assetTypeHandler = this.assetTypeRegistry.tryGetAssetTypeHandler(oldAssetPath.path(), editorClient, requestToken); if (assetTypeHandler != null) { @@ -1479,21 +1517,21 @@ public class AssetEditorPlugin extends JavaPlugin { ); } else if (!newAssetPath.path().startsWith(assetTypeHandler.getRootPath())) { this.getLogger().at(Level.WARNING).log("%s is not within valid asset directory", newAssetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.directoryOutsideRoot")); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ROOT); } else { long stamp = this.globalEditLock.writeLock(); try { if (dataSource.doesAssetExist(newAssetPath.path())) { this.getLogger().at(Level.WARNING).log("%s already exists", newAssetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.renameAsset.alreadyExists")); + editorClient.sendFailureReply(requestToken, Messages.RENAME_ASSET_ALREADY_EXISTS); return; } byte[] oldAsset = dataSource.getAssetBytes(oldAssetPath.path()); if (oldAsset == null) { this.getLogger().at(Level.WARNING).log("%s is not a regular file", oldAssetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.renameAsset.doesntExist")); + editorClient.sendFailureReply(requestToken, Messages.RENAME_ASSET_DOESNT_EXIST); return; } @@ -1517,7 +1555,7 @@ public class AssetEditorPlugin extends JavaPlugin { } this.getLogger().at(Level.WARNING).log("Failed to move file %s to %s", oldAssetPath, newAssetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.renameAsset.failed")); + editorClient.sendFailureReply(requestToken, Messages.RENAME_ASSET_FAILED); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1529,24 +1567,24 @@ public class AssetEditorPlugin extends JavaPlugin { public void handleDeleteDirectory(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath, int requestToken) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.directoryOutsideRoot")); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ROOT); } else if (!this.getAssetTypeRegistry().isPathInAssetTypeFolder(assetPath.path())) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else { long stamp = this.globalEditLock.writeLock(); try { if (!dataSource.doesDirectoryExist(assetPath.path())) { this.getLogger().at(Level.WARNING).log("Directory doesn't exist %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.createDirectory.alreadyExists")); + editorClient.sendFailureReply(requestToken, Messages.CREATE_DIRECTORY_ALREADY_EXISTS); return; } if (!dataSource.getAssetTree().isDirectoryEmpty(assetPath.path())) { this.getLogger().at(Level.WARNING).log("%s must be empty", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.deleteDirectory.notEmpty")); + editorClient.sendFailureReply(requestToken, Messages.DELETE_DIRECTORY_NOT_EMPTY); return; } @@ -1560,7 +1598,7 @@ public class AssetEditorPlugin extends JavaPlugin { } this.getLogger().at(Level.WARNING).log("Directory %s could not be deleted!", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.deleteDirectory.failed")); + editorClient.sendFailureReply(requestToken, Messages.DELETE_DIRECTORY_FAILED); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1568,31 +1606,31 @@ public class AssetEditorPlugin extends JavaPlugin { } public void handleRenameDirectory(@Nonnull EditorClient editorClient, AssetPath path, AssetPath newPath, int requestToken) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.renameDirectory.unsupported")); + editorClient.sendFailureReply(requestToken, Messages.RENAME_DIRECTORY_UNSUPPORTED); } public void handleCreateDirectory(@Nonnull EditorClient editorClient, @Nonnull AssetPath assetPath, int requestToken) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.createDirectory.noDataSource")); + editorClient.sendFailureReply(requestToken, Messages.CREATE_DIRECTORY_NO_DATA_SOURCE); } else if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.createDirectory.noPath")); + editorClient.sendFailureReply(requestToken, Messages.CREATE_DIRECTORY_NO_PATH); } else { long stamp = this.globalEditLock.writeLock(); try { if (dataSource.doesDirectoryExist(assetPath.path())) { this.getLogger().at(Level.WARNING).log("Directory already exists at %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.createDirectory.alreadyExists")); + editorClient.sendFailureReply(requestToken, Messages.CREATE_DIRECTORY_ALREADY_EXISTS); return; } Path parentDirectoryPath = assetPath.path().getParent(); if (!dataSource.doesDirectoryExist(parentDirectoryPath)) { this.getLogger().at(Level.WARNING).log("Parent directory is missing for %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.parentDirectoryMissing")); + editorClient.sendFailureReply(requestToken, Messages.PARENT_DIRECTORY_MISSING); return; } @@ -1609,7 +1647,7 @@ public class AssetEditorPlugin extends JavaPlugin { } this.getLogger().at(Level.WARNING).log("Failed to create directory %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.failedToCreateDirectory")); + editorClient.sendFailureReply(requestToken, Messages.FAILED_TO_CREATE_DIRECTORY); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1626,11 +1664,11 @@ public class AssetEditorPlugin extends JavaPlugin { ) { DataSource dataSource = this.getDataSourceForPath(assetPath); if (dataSource == null) { - editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSETPACK_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.UNKNOWN_ASSET_PACK); } else if (dataSource.isImmutable()) { - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.assetsReadOnly")); + editorClient.sendFailureReply(requestToken, Messages.ASSETS_READ_ONLY); } else if (!this.isValidPath(dataSource, assetPath)) { - editorClient.sendFailureReply(requestToken, Messages.OUTSIDE_ASSET_ROOT_MESSAGE); + editorClient.sendFailureReply(requestToken, Messages.DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT); } else { AssetTypeHandler assetTypeHandler = this.assetTypeRegistry.tryGetAssetTypeHandler(assetPath.path(), editorClient, requestToken); if (assetTypeHandler != null) { @@ -1639,13 +1677,13 @@ public class AssetEditorPlugin extends JavaPlugin { try { if (dataSource.doesAssetExist(assetPath.path())) { this.getLogger().at(Level.WARNING).log("%s already exists", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.createAsset.idAlreadyExists")); + editorClient.sendFailureReply(requestToken, Messages.CREATE_ASSET_ID_ALREADY_EXISTS); return; } if (!assetTypeHandler.isValidData(data)) { this.getLogger().at(Level.WARNING).log("Failed to validate data for %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.createAsset.failed")); + editorClient.sendFailureReply(requestToken, Messages.CREATE_ASSET_FAILED); return; } @@ -1681,7 +1719,7 @@ public class AssetEditorPlugin extends JavaPlugin { } this.getLogger().at(Level.WARNING).log("Failed to create asset %s", assetPath); - editorClient.sendFailureReply(requestToken, Message.translation("server.assetEditor.messages.createAsset.failed")); + editorClient.sendFailureReply(requestToken, Messages.CREATE_ASSET_FAILED); } finally { this.globalEditLock.unlockWrite(stamp); } @@ -1760,13 +1798,13 @@ public class AssetEditorPlugin extends JavaPlugin { } } - private void sendPacketToAllEditorUsers(@Nonnull Packet packet) { + private void sendPacketToAllEditorUsers(@Nonnull ToClientPacket packet) { for (EditorClient editorClient : this.clientOpenAssetPathMapping.keySet()) { editorClient.getPacketHandler().write(packet); } } - private void sendPacketToAllEditorUsersExcept(@Nonnull Packet packet, EditorClient ignoreEditorClient) { + private void sendPacketToAllEditorUsersExcept(@Nonnull ToClientPacket packet, EditorClient ignoreEditorClient) { for (EditorClient editorClient : this.clientOpenAssetPathMapping.keySet()) { if (!editorClient.equals(ignoreEditorClient)) { editorClient.getPacketHandler().write(packet); @@ -1778,13 +1816,13 @@ public class AssetEditorPlugin extends JavaPlugin { this.updateAssetForConnectedClients(assetPath, null); } - private void updateAssetForConnectedClients(@Nonnull AssetPath assetPath, EditorClient ignoreEditorClient) { + private void updateAssetForConnectedClients(@Nonnull AssetPath assetPath, @Nullable EditorClient ignoreEditorClient) { DataSource dataSource = this.getDataSourceForPath(assetPath); byte[] bytes = dataSource.getAssetBytes(assetPath.path()); this.updateAssetForConnectedClients(assetPath, bytes, ignoreEditorClient); } - private void updateAssetForConnectedClients(@Nonnull AssetPath assetPath, byte[] bytes, EditorClient ignoreEditorClient) { + private void updateAssetForConnectedClients(@Nonnull AssetPath assetPath, byte[] bytes, @Nullable EditorClient ignoreEditorClient) { AssetEditorAssetUpdated updatePacket = new AssetEditorAssetUpdated(assetPath.toPacket(), bytes); for (Entry entry : this.clientOpenAssetPathMapping.entrySet()) { @@ -1794,11 +1832,13 @@ public class AssetEditorPlugin extends JavaPlugin { } } - private void updateJsonAssetForConnectedClients(@Nonnull AssetPath assetPath, JsonUpdateCommand[] commands) { + private void updateJsonAssetForConnectedClients(@Nonnull AssetPath assetPath, @Nonnull JsonUpdateCommand[] commands) { this.updateJsonAssetForConnectedClients(assetPath, commands, null); } - private void updateJsonAssetForConnectedClients(@Nonnull AssetPath assetPath, JsonUpdateCommand[] commands, EditorClient ignoreEditorClient) { + private void updateJsonAssetForConnectedClients( + @Nonnull AssetPath assetPath, @Nonnull JsonUpdateCommand[] commands, @Nullable EditorClient ignoreEditorClient + ) { AssetEditorJsonAssetUpdated updatePacket = new AssetEditorJsonAssetUpdated(assetPath.toPacket(), commands); for (Entry connectedPlayer : this.clientOpenAssetPathMapping.entrySet()) { @@ -1810,7 +1850,7 @@ public class AssetEditorPlugin extends JavaPlugin { @Nonnull private AssetEditorLastModifiedAssets buildAssetEditorLastModifiedAssetsPacket() { - ArrayList allAssets = new ArrayList<>(); + List allAssets = new ObjectArrayList<>(); for (Entry dataSource : this.assetPackDataSources.entrySet()) { if (dataSource.getValue() instanceof StandardDataSource standardDataSource) { diff --git a/src/com/hypixel/hytale/builtin/asseteditor/Messages.java b/src/com/hypixel/hytale/builtin/asseteditor/Messages.java index 110e717e..c152158d 100644 --- a/src/com/hypixel/hytale/builtin/asseteditor/Messages.java +++ b/src/com/hypixel/hytale/builtin/asseteditor/Messages.java @@ -1,10 +1,93 @@ package com.hypixel.hytale.builtin.asseteditor; import com.hypixel.hytale.server.core.Message; +import javax.annotation.Nonnull; public class Messages { - public static final Message USAGE_DENIED_MESSAGE = Message.translation("server.assetEditor.messages.usageDenied"); - public static final Message INVALID_FILENAME_MESSAGE = Message.translation("server.assetEditor.messages.invalidFileName"); - public static final Message OUTSIDE_ASSET_ROOT_MESSAGE = Message.translation("server.assetEditor.messages.directoryOutsideAssetTypeRoot"); - public static final Message UNKNOWN_ASSETPACK_MESSAGE = Message.translation("server.assetEditor.messages.unknownAssetPack"); + @Nonnull + public static final Message USAGE_DENIED = Message.translation("server.assetEditor.messages.usageDenied"); + @Nonnull + public static final Message INVALID_FILE_NAME = Message.translation("server.assetEditor.messages.invalidFileName"); + @Nonnull + public static final Message DIRECTORY_OUTSIDE_ASSET_TYPE_ROOT = Message.translation("server.assetEditor.messages.directoryOutsideAssetTypeRoot"); + @Nonnull + public static final Message UNKNOWN_ASSET_PACK = Message.translation("server.assetEditor.messages.unknownAssetPack"); + @Nonnull + public static final Message ASSETS_READ_ONLY = Message.translation("server.assetEditor.messages.assetsReadOnly"); + @Nonnull + public static final Message UPDATE_DOESNT_EXIST = Message.translation("server.assetEditor.messages.update.doesntExist"); + @Nonnull + public static final Message CREATE_ASSET_FAILED = Message.translation("server.assetEditor.messages.createAsset.failed"); + @Nonnull + public static final Message UPDATE_FAILED = Message.translation("server.assetEditor.messages.update.failed"); + @Nonnull + public static final Message PACK_OUTSIDE_DIRECTORY = Message.translation("server.assetEditor.messages.packOutsideDirectory"); + @Nonnull + public static final Message PACK_ALREADY_EXISTS_AT_PATH = Message.translation("server.assetEditor.messages.packAlreadyExistsAtPath"); + @Nonnull + public static final Message PACK_CREATED = Message.translation("server.assetEditor.messages.packCreated"); + @Nonnull + public static final Message PACK_CREATION_FAILED = Message.translation("server.assetEditor.messages.packCreationFailed"); + @Nonnull + public static final Message UNKNOWN_ASSET_INDEX = Message.translation("server.assetEditor.messages.unknownAssetIndex"); + @Nonnull + public static final Message DIRECTORY_OUTSIDE_ROOT = Message.translation("server.assetEditor.messages.directoryOutsideRoot"); + @Nonnull + public static final Message INVALID_ASSET_TYPE = Message.translation("server.assetEditor.messages.invalidAssetType"); + @Nonnull + public static final Message UNDO_EMPTY = Message.translation("server.assetEditor.messages.undo.empty"); + @Nonnull + public static final Message UNDO_FAILED = Message.translation("server.assetEditor.messages.undo.failed"); + @Nonnull + public static final Message REDO_EMPTY = Message.translation("server.assetEditor.messages.redo.empty"); + @Nonnull + public static final Message REDO_FAILED = Message.translation("server.assetEditor.messages.redo.failed"); + @Nonnull + public static final Message FETCH_ASSET_DOESNT_EXIST = Message.translation("server.assetEditor.messages.fetchAsset.doesntExist"); + @Nonnull + public static final Message FETCH_ASSET_FAILED = Message.translation("server.assetEditor.messages.fetchAsset.failed"); + @Nonnull + public static final Message REQUEST_CHILD_IDS_ASSET_TYPE_MISSING = Message.translation("server.assetEditor.messages.requestChildIds.assetTypeMissing"); + @Nonnull + public static final Message DELETE_ASSET_ALREADY_DELETED = Message.translation("server.assetEditor.messages.deleteAsset.alreadyDeleted"); + @Nonnull + public static final Message FAILED_TO_DELETE_ASSET = Message.translation("server.assetEditor.messages.failedToDeleteAsset"); + @Nonnull + public static final Message RENAME_ASSET_ALREADY_EXISTS = Message.translation("server.assetEditor.messages.renameAsset.alreadyExists"); + @Nonnull + public static final Message RENAME_ASSET_DOESNT_EXIST = Message.translation("server.assetEditor.messages.renameAsset.doesntExist"); + @Nonnull + public static final Message RENAME_ASSET_FAILED = Message.translation("server.assetEditor.messages.renameAsset.failed"); + @Nonnull + public static final Message CREATE_DIRECTORY_ALREADY_EXISTS = Message.translation("server.assetEditor.messages.createDirectory.alreadyExists"); + @Nonnull + public static final Message DELETE_DIRECTORY_NOT_EMPTY = Message.translation("server.assetEditor.messages.deleteDirectory.notEmpty"); + @Nonnull + public static final Message DELETE_DIRECTORY_FAILED = Message.translation("server.assetEditor.messages.deleteDirectory.failed"); + @Nonnull + public static final Message RENAME_DIRECTORY_UNSUPPORTED = Message.translation("server.assetEditor.messages.renameDirectory.unsupported"); + @Nonnull + public static final Message CREATE_DIRECTORY_NO_DATA_SOURCE = Message.translation("server.assetEditor.messages.createDirectory.noDataSource"); + @Nonnull + public static final Message CREATE_DIRECTORY_NO_PATH = Message.translation("server.assetEditor.messages.createDirectory.noPath"); + @Nonnull + public static final Message PARENT_DIRECTORY_MISSING = Message.translation("server.assetEditor.messages.parentDirectoryMissing"); + @Nonnull + public static final Message FAILED_TO_CREATE_DIRECTORY = Message.translation("server.assetEditor.messages.failedToCreateDirectory"); + @Nonnull + public static final Message CREATE_ASSET_ID_ALREADY_EXISTS = Message.translation("server.assetEditor.messages.createAsset.idAlreadyExists"); + @Nonnull + public static final Message MANIFEST_NOT_FOUND = Message.translation("server.assetEditor.messages.manifestNotFound"); + @Nonnull + public static final Message INVALID_VERSION_FORMAT = Message.translation("server.assetEditor.messages.invalidVersionFormat"); + @Nonnull + public static final Message MANIFEST_SAVED = Message.translation("server.assetEditor.messages.manifestSaved"); + @Nonnull + public static final Message MANIFEST_SAVE_FAILED = Message.translation("server.assetEditor.messages.manifestSaveFailed"); + @Nonnull + public static final Message PACK_NAME_REQUIRED = Message.translation("server.assetEditor.messages.packNameRequired"); + @Nonnull + public static final Message PACK_GROUP_REQUIRED = Message.translation("server.assetEditor.messages.packGroupRequired"); + @Nonnull + public static final Message PACK_ALREADY_EXISTS = Message.translation("server.assetEditor.messages.packAlreadyExists"); } diff --git a/src/com/hypixel/hytale/builtin/asseteditor/assettypehandler/CommonAssetTypeHandler.java b/src/com/hypixel/hytale/builtin/asseteditor/assettypehandler/CommonAssetTypeHandler.java index 1c5ec892..95cc6edc 100644 --- a/src/com/hypixel/hytale/builtin/asseteditor/assettypehandler/CommonAssetTypeHandler.java +++ b/src/com/hypixel/hytale/builtin/asseteditor/assettypehandler/CommonAssetTypeHandler.java @@ -21,11 +21,12 @@ import java.nio.file.Path; import java.util.Collections; import java.util.logging.Level; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class CommonAssetTypeHandler extends AssetTypeHandler { private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); - public CommonAssetTypeHandler(String id, String icon, String fileExtension, AssetEditorEditorType editorType) { + public CommonAssetTypeHandler(String id, @Nullable String icon, String fileExtension, AssetEditorEditorType editorType) { super(new AssetEditorAssetType(id, icon, true, "Common", fileExtension, editorType)); } diff --git a/src/com/hypixel/hytale/builtin/asseteditor/datasource/StandardDataSource.java b/src/com/hypixel/hytale/builtin/asseteditor/datasource/StandardDataSource.java index b0306dbe..2b44a679 100644 --- a/src/com/hypixel/hytale/builtin/asseteditor/datasource/StandardDataSource.java +++ b/src/com/hypixel/hytale/builtin/asseteditor/datasource/StandardDataSource.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.builtin.asseteditor.data.AssetState; import com.hypixel.hytale.builtin.asseteditor.data.ModifiedAsset; import com.hypixel.hytale.codec.ExtraInfo; import com.hypixel.hytale.common.plugin.PluginManifest; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.Options; @@ -85,7 +86,10 @@ public class StandardDataSource implements DataSource { @Override public void shutdown() { - this.saveSchedule.cancel(false); + if (this.saveSchedule != null) { + this.saveSchedule.cancel(false); + } + this.saveRecentModifications(); } @@ -134,7 +138,12 @@ public class StandardDataSource implements DataSource { } public Path resolveAbsolutePath(Path path) { - return this.rootPath.resolve(path.toString()).toAbsolutePath(); + Path resolved = this.rootPath.resolve(path.toString()).toAbsolutePath(); + if (!PathUtil.isChildOf(this.rootPath, resolved)) { + throw new IllegalArgumentException("Invalid path: " + path); + } else { + return resolved; + } } @Override diff --git a/src/com/hypixel/hytale/builtin/beds/BedsPlugin.java b/src/com/hypixel/hytale/builtin/beds/BedsPlugin.java index f4cbb5c4..314caad2 100644 --- a/src/com/hypixel/hytale/builtin/beds/BedsPlugin.java +++ b/src/com/hypixel/hytale/builtin/beds/BedsPlugin.java @@ -6,16 +6,22 @@ import com.hypixel.hytale.builtin.beds.sleep.components.SleepTracker; import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSomnolence; import com.hypixel.hytale.builtin.beds.sleep.systems.player.EnterBedSystem; import com.hypixel.hytale.builtin.beds.sleep.systems.player.RegisterTrackerSystem; +import com.hypixel.hytale.builtin.beds.sleep.systems.player.SleepNotificationSystem; import com.hypixel.hytale.builtin.beds.sleep.systems.player.UpdateSleepPacketSystem; import com.hypixel.hytale.builtin.beds.sleep.systems.player.WakeUpOnDismountSystem; import com.hypixel.hytale.builtin.beds.sleep.systems.world.StartSlumberSystem; import com.hypixel.hytale.builtin.beds.sleep.systems.world.UpdateWorldSlumberSystem; +import com.hypixel.hytale.builtin.mounts.MountedComponent; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction; +import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; 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.storage.EntityStore; +import javax.annotation.Nonnull; public class BedsPlugin extends JavaPlugin { private static BedsPlugin instance; @@ -27,22 +33,33 @@ public class BedsPlugin extends JavaPlugin { return instance; } - public BedsPlugin(JavaPluginInit init) { + public BedsPlugin(@Nonnull JavaPluginInit init) { super(init); } @Override protected void setup() { instance = this; - this.playerSomnolenceComponentType = this.getEntityStoreRegistry().registerComponent(PlayerSomnolence.class, PlayerSomnolence::new); - this.sleepTrackerComponentType = this.getEntityStoreRegistry().registerComponent(SleepTracker.class, SleepTracker::new); - this.worldSomnolenceResourceType = this.getEntityStoreRegistry().registerResource(WorldSomnolence.class, WorldSomnolence::new); - this.getEntityStoreRegistry().registerSystem(new StartSlumberSystem()); - this.getEntityStoreRegistry().registerSystem(new UpdateSleepPacketSystem()); - this.getEntityStoreRegistry().registerSystem(new WakeUpOnDismountSystem()); - this.getEntityStoreRegistry().registerSystem(new RegisterTrackerSystem()); - this.getEntityStoreRegistry().registerSystem(new UpdateWorldSlumberSystem()); - this.getEntityStoreRegistry().registerSystem(new EnterBedSystem()); + ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); + this.playerSomnolenceComponentType = entityStoreRegistry.registerComponent(PlayerSomnolence.class, PlayerSomnolence::new); + this.sleepTrackerComponentType = entityStoreRegistry.registerComponent(SleepTracker.class, SleepTracker::new); + this.worldSomnolenceResourceType = entityStoreRegistry.registerResource(WorldSomnolence.class, WorldSomnolence::new); + ComponentType playerRefComponentType = PlayerRef.getComponentType(); + ComponentType mountedComponentType = MountedComponent.getComponentType(); + ResourceType worldTimeResourceType = WorldTimeResource.getResourceType(); + entityStoreRegistry.registerSystem(new RegisterTrackerSystem(playerRefComponentType, this.sleepTrackerComponentType)); + entityStoreRegistry.registerSystem(new WakeUpOnDismountSystem(mountedComponentType, this.playerSomnolenceComponentType)); + entityStoreRegistry.registerSystem(new EnterBedSystem(mountedComponentType, playerRefComponentType)); + entityStoreRegistry.registerSystem( + new UpdateSleepPacketSystem( + playerRefComponentType, this.playerSomnolenceComponentType, this.sleepTrackerComponentType, this.worldSomnolenceResourceType, worldTimeResourceType + ) + ); + entityStoreRegistry.registerSystem(new StartSlumberSystem(this.playerSomnolenceComponentType, this.worldSomnolenceResourceType, worldTimeResourceType)); + entityStoreRegistry.registerSystem( + new UpdateWorldSlumberSystem(this.playerSomnolenceComponentType, this.worldSomnolenceResourceType, worldTimeResourceType) + ); + entityStoreRegistry.registerSystem(new SleepNotificationSystem()); Interaction.CODEC.register("Bed", BedInteraction.class, BedInteraction.CODEC); } diff --git a/src/com/hypixel/hytale/builtin/beds/interactions/BedInteraction.java b/src/com/hypixel/hytale/builtin/beds/interactions/BedInteraction.java index 813a81e8..f46d563c 100644 --- a/src/com/hypixel/hytale/builtin/beds/interactions/BedInteraction.java +++ b/src/com/hypixel/hytale/builtin/beds/interactions/BedInteraction.java @@ -5,6 +5,7 @@ import com.hypixel.hytale.builtin.beds.respawn.SelectOverrideRespawnPointPage; import com.hypixel.hytale.builtin.beds.respawn.SetNameRespawnPointPage; import com.hypixel.hytale.builtin.beds.sleep.components.PlayerSleep; import com.hypixel.hytale.builtin.beds.sleep.components.PlayerSomnolence; +import com.hypixel.hytale.builtin.beds.sleep.systems.player.SleepNotificationSystem; import com.hypixel.hytale.builtin.mounts.BlockMountAPI; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.component.AddReason; @@ -58,69 +59,72 @@ public class BedInteraction extends SimpleBlockInteraction { @Nonnull CooldownHandler cooldownHandler ) { Ref ref = context.getEntity(); - Player player = commandBuffer.getComponent(ref, Player.getComponentType()); - if (player != null) { + Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { Store store = commandBuffer.getStore(); PlayerRef playerRefComponent = commandBuffer.getComponent(ref, PlayerRef.getComponentType()); + if (playerRefComponent != null) { + UUIDComponent playerUuidComponent = commandBuffer.getComponent(ref, UUIDComponent.getComponentType()); + if (playerUuidComponent != null) { + UUID playerUuid = playerUuidComponent.getUuid(); + long chunkIndex = ChunkUtil.indexChunkFromBlock(pos.x, pos.z); + Ref chunkRef = world.getChunkStore().getChunkReference(chunkIndex); + if (chunkRef != null && chunkRef.isValid()) { + Store chunkStore = chunkRef.getStore(); + BlockComponentChunk blockComponentChunk = chunkStore.getComponent(chunkRef, BlockComponentChunk.getComponentType()); + if (blockComponentChunk != null) { + int blockIndex = ChunkUtil.indexBlockInColumn(pos.x, pos.y, pos.z); + Ref blockRef = blockComponentChunk.getEntityReference(blockIndex); + if (blockRef == null || !blockRef.isValid()) { + Holder holder = ChunkStore.REGISTRY.newHolder(); + holder.putComponent(BlockModule.BlockStateInfo.getComponentType(), new BlockModule.BlockStateInfo(blockIndex, chunkRef)); + holder.ensureComponent(RespawnBlock.getComponentType()); + blockRef = chunkStore.addEntity(holder, AddReason.SPAWN); + } - assert playerRefComponent != null; - - UUIDComponent playerUuidComponent = commandBuffer.getComponent(ref, UUIDComponent.getComponentType()); - - assert playerUuidComponent != null; - - UUID playerUuid = playerUuidComponent.getUuid(); - Ref chunkReference = world.getChunkStore().getChunkReference(ChunkUtil.indexChunkFromBlock(pos.x, pos.z)); - if (chunkReference != null) { - Store chunkStore = chunkReference.getStore(); - BlockComponentChunk blockComponentChunk = chunkStore.getComponent(chunkReference, BlockComponentChunk.getComponentType()); - - assert blockComponentChunk != null; - - int blockIndex = ChunkUtil.indexBlockInColumn(pos.x, pos.y, pos.z); - Ref blockRef = blockComponentChunk.getEntityReference(blockIndex); - if (blockRef == null) { - 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) - ); - } else { - pageManager.openCustomPage(ref, store, new SetNameRespawnPointPage(playerRefComponent, type, pos, respawnBlockComponent)); + if (blockRef != null && blockRef.isValid()) { + RespawnBlock respawnBlockComponent = chunkStore.getComponent(blockRef, RespawnBlock.getComponentType()); + if (respawnBlockComponent != null) { + UUID ownerUUID = respawnBlockComponent.getOwnerUUID(); + PageManager pageManager = playerComponent.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) { + playerComponent.sendMessage(Message.translation("server.interactions.didNotMount").param("state", result.toString())); + } else if (result instanceof BlockMountAPI.Mounted) { + commandBuffer.putComponent(ref, PlayerSomnolence.getComponentType(), PlayerSleep.NoddingOff.createComponent()); + commandBuffer.run(s -> SleepNotificationSystem.maybeDoNotification(s, false)); + } + } else if (ownerUUID != null) { + playerComponent.sendMessage(MESSAGE_SERVER_CUSTOM_UI_RESPAWN_POINT_CLAIMED); + } else { + PlayerRespawnPointData[] respawnPoints = playerComponent.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 +139,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..c0f995b6 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); @@ -45,37 +50,38 @@ public class OverrideNearbyRespawnPointPage extends RespawnPointPage { ) { commandBuilder.append("Pages/OverrideNearbyRespawnPointPage.ui"); HeadRotation headRotationComponent = store.getComponent(ref, HeadRotation.getComponentType()); + if (headRotationComponent != null) { + PlayerRef playerRefComponent = store.getComponent(ref, PlayerRef.getComponentType()); + if (playerRefComponent != null) { + double direction = Math.toDegrees(headRotationComponent.getRotation().getYaw()); + commandBuilder.set( + "#DescriptionLabel.Text", + Message.translation("server.customUI.overrideNearbyRespawnPoint.label") + .param("respawnPointCount", this.nearbyRespawnPoints.length) + .param("minDistance", this.radiusLimitRespawnPoint) + ); - assert headRotationComponent != null; + for (int i = 0; i < this.nearbyRespawnPoints.length; i++) { + String selector = "#RespawnPointList[" + i + "]"; + PlayerRespawnPointData nearbyRespawnPoint = this.nearbyRespawnPoints[i]; + commandBuilder.append("#RespawnPointList", "Pages/OverrideRespawnPointButton.ui"); + commandBuilder.set(selector + ".Disabled", true); + commandBuilder.set(selector + " #Name.Text", nearbyRespawnPoint.getName()); + Vector3i nearbyRespawnPointPosition = nearbyRespawnPoint.getBlockPosition(); + int distance = (int)this.respawnPointPosition + .distanceTo(nearbyRespawnPointPosition.x, this.respawnPointPosition.y, nearbyRespawnPointPosition.z); + commandBuilder.set(selector + " #Distance.Text", Message.translation("server.customUI.respawnPointDistance").param("distance", distance)); + double angle = Math.atan2(nearbyRespawnPointPosition.z - this.respawnPointPosition.z, nearbyRespawnPointPosition.x - this.respawnPointPosition.x); + commandBuilder.set(selector + " #Icon.Angle", Math.toDegrees(angle) + direction + 90.0); + } - PlayerRef playerRefComponent = store.getComponent(ref, PlayerRef.getComponentType()); - - assert playerRefComponent != null; - - double direction = Math.toDegrees(headRotationComponent.getRotation().getYaw()); - commandBuilder.set( - "#DescriptionLabel.Text", - Message.translation("server.customUI.overrideNearbyRespawnPoint.label") - .param("respawnPointCount", this.nearbyRespawnPoints.length) - .param("minDistance", this.radiusLimitRespawnPoint) - ); - - for (int i = 0; i < this.nearbyRespawnPoints.length; i++) { - String selector = "#RespawnPointList[" + i + "]"; - PlayerRespawnPointData nearbyRespawnPoint = this.nearbyRespawnPoints[i]; - commandBuilder.append("#RespawnPointList", "Pages/OverrideRespawnPointButton.ui"); - commandBuilder.set(selector + ".Disabled", true); - commandBuilder.set(selector + " #Name.Text", nearbyRespawnPoint.getName()); - Vector3i nearbyRespawnPointPosition = nearbyRespawnPoint.getBlockPosition(); - int distance = (int)this.respawnPointPosition.distanceTo(nearbyRespawnPointPosition.x, this.respawnPointPosition.y, nearbyRespawnPointPosition.z); - commandBuilder.set(selector + " #Distance.Text", Message.translation("server.customUI.respawnPointDistance").param("distance", distance)); - double angle = Math.atan2(nearbyRespawnPointPosition.z - this.respawnPointPosition.z, nearbyRespawnPointPosition.x - this.respawnPointPosition.x); - commandBuilder.set(selector + " #Icon.Angle", Math.toDegrees(angle) + direction + 90.0); + commandBuilder.set( + "#NameInput.Value", Message.translation("server.customUI.defaultRespawnPointName").param("name", playerRefComponent.getUsername()) + ); + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#ConfirmButton", EventData.of("@RespawnPointName", "#NameInput.Value")); + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#CancelButton", EventData.of("Action", "Cancel")); + } } - - commandBuilder.set("#NameInput.Value", Message.translation("server.customUI.defaultRespawnPointName").param("name", playerRefComponent.getUsername())); - eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#ConfirmButton", EventData.of("@RespawnPointName", "#NameInput.Value")); - eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#CancelButton", EventData.of("Action", "Cancel")); } public void handleDataEvent(@Nonnull Ref ref, @Nonnull Store store, @Nonnull RespawnPointPage.RespawnPointEventData data) { @@ -84,7 +90,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..4042c536 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,58 +58,63 @@ public abstract class RespawnPointPage extends InteractiveCustomUIPage 32) { this.displayError(Message.translation("server.customUI.respawnNameTooLong").param("maxLength", 32)); } else { respawnBlock.setOwnerUUID(this.playerRef.getUuid()); World world = store.getExternalData().getWorld(); Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(blockPosition.x, blockPosition.z); + WorldChunk chunk = world.getChunkIfInMemory(chunkIndex); + if (chunk != null) { + chunk.markNeedsSaving(); + BlockType blockType = chunk.getBlockType(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); + if (blockType != null) { + int rotationIndex = chunk.getRotationIndex(blockPosition.x, blockPosition.y, blockPosition.z); + BlockBoundingBoxes blockBoundingBoxAsset = BlockBoundingBoxes.getAssetMap().getAsset(blockType.getHitboxTypeIndex()); + if (blockBoundingBoxAsset != null) { + Box hitbox = blockBoundingBoxAsset.get(rotationIndex).getBoundingBox(); + double blockCenterWidthOffset = hitbox.min.x + hitbox.width() / 2.0; + double blockCenterDepthOffset = hitbox.min.z + hitbox.depth() / 2.0; + Vector3d respawnPosition = new Vector3d( + blockPosition.getX() + blockCenterWidthOffset, blockPosition.getY() + hitbox.height(), blockPosition.getZ() + blockCenterDepthOffset + ); + PlayerRespawnPointData respawnPointData = new PlayerRespawnPointData(blockPosition, respawnPosition, respawnPointName); + PlayerWorldData perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(world.getName()); + PlayerRespawnPointData[] respawnPoints = handleRespawnPointsToRemove(world, perWorldData.getRespawnPoints(), respawnPointsToRemove); + if (respawnPoints != null) { + if (ArrayUtil.contains(respawnPoints, respawnPointData)) { + return; + } - assert playerComponent != null; - - WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(blockPosition.x, blockPosition.z)); - if (chunk != null) { - chunk.markNeedsSaving(); - BlockType blockType = chunk.getBlockType(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); - int rotationIndex = chunk.getRotationIndex(blockPosition.x, blockPosition.y, blockPosition.z); - Box hitbox = BlockBoundingBoxes.getAssetMap().getAsset(blockType.getHitboxTypeIndex()).get(rotationIndex).getBoundingBox(); - double blockCenterWidthOffset = hitbox.min.x + hitbox.width() / 2.0; - double blockCenterDepthOffset = hitbox.min.z + hitbox.depth() / 2.0; - Vector3d respawnPosition = new Vector3d( - blockPosition.getX() + blockCenterWidthOffset, blockPosition.getY() + hitbox.height(), blockPosition.getZ() + blockCenterDepthOffset - ); - PlayerRespawnPointData respawnPointData = new PlayerRespawnPointData(blockPosition, respawnPosition, respawnPointName); - PlayerWorldData perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(world.getName()); - PlayerRespawnPointData[] respawnPoints = this.handleRespawnPointsToRemove(perWorldData.getRespawnPoints(), respawnPointsToRemove, world); - if (respawnPoints != null) { - if (ArrayUtil.contains(respawnPoints, respawnPointData)) { - return; - } - - if (respawnPointsToRemove == null || respawnPointsToRemove.length == 0) { - for (int i = 0; i < respawnPoints.length; i++) { - PlayerRespawnPointData savedRespawnPointData = respawnPoints[i]; - if (savedRespawnPointData.getBlockPosition().equals(blockPosition)) { - savedRespawnPointData.setName(respawnPointName); - this.playerRef.sendMessage(Message.translation("server.customUI.updatedRespawnPointName").param("name", respawnPointName)); - playerComponent.getPageManager().setPage(ref, store, Page.None); - return; + if (respawnPointsToRemove == null || respawnPointsToRemove.length == 0) { + for (int i = 0; i < respawnPoints.length; i++) { + PlayerRespawnPointData savedRespawnPointData = respawnPoints[i]; + if (savedRespawnPointData.getBlockPosition().equals(blockPosition)) { + savedRespawnPointData.setName(respawnPointName); + this.playerRef.sendMessage(Message.translation("server.customUI.updatedRespawnPointName").param("name", respawnPointName)); + playerComponent.getPageManager().setPage(ref, store, Page.None); + return; + } + } + } } + + perWorldData.setRespawnPoints(ArrayUtil.append(respawnPoints, respawnPointData)); + this.playerRef.sendMessage(Message.translation("server.customUI.respawnPointSet").param("name", respawnPointName)); + playerComponent.getPageManager().setPage(ref, store, Page.None); } } } - - perWorldData.setRespawnPoints(ArrayUtil.append(respawnPoints, respawnPointData)); - this.playerRef.sendMessage(Message.translation("server.customUI.respawnPointSet").param("name", respawnPointName)); - playerComponent.getPageManager().setPage(ref, store, Page.None); } } } @Nonnull - private PlayerRespawnPointData[] handleRespawnPointsToRemove( - @Nonnull PlayerRespawnPointData[] respawnPoints, @Nullable PlayerRespawnPointData[] respawnPointsToRemove, @Nonnull World world + private static PlayerRespawnPointData[] handleRespawnPointsToRemove( + @Nonnull World world, @Nonnull PlayerRespawnPointData[] respawnPoints, @Nullable PlayerRespawnPointData[] respawnPointsToRemove ) { if (respawnPointsToRemove == null) { return respawnPoints; @@ -126,17 +133,21 @@ 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 +166,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..d3aa5fc8 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; @@ -47,32 +56,32 @@ public class SelectOverrideRespawnPointPage extends RespawnPointPage { commandBuilder.append("Pages/SelectOverrideRespawnPointPage.ui"); commandBuilder.clear("#RespawnPointList"); PlayerRef playerRefComponent = store.getComponent(ref, PlayerRef.getComponentType()); + if (playerRefComponent != null) { + HeadRotation rotationComponent = store.getComponent(ref, HeadRotation.getComponentType()); + if (rotationComponent != null) { + float lookYaw = rotationComponent.getRotation().getYaw(); + double direction = Math.toDegrees(lookYaw); - assert playerRefComponent != null; + for (int i = 0; i < this.respawnPoints.length; i++) { + String selector = "#RespawnPointList[" + i + "]"; + PlayerRespawnPointData respawnPoint = this.respawnPoints[i]; + commandBuilder.append("#RespawnPointList", "Pages/OverrideRespawnPointButton.ui"); + commandBuilder.set(selector + " #Name.Text", respawnPoint.getName()); + Vector3i respawnPointPosition = respawnPoint.getBlockPosition(); + int distance = (int)this.respawnPointToAddPosition.distanceTo(respawnPointPosition.x, this.respawnPointToAddPosition.y, respawnPointPosition.z); + commandBuilder.set(selector + " #Distance.Text", Message.translation("server.customUI.respawnPointDistance").param("distance", distance)); + double angle = Math.atan2(respawnPointPosition.z - this.respawnPointToAddPosition.z, respawnPointPosition.x - this.respawnPointToAddPosition.x); + commandBuilder.set(selector + " #Icon.Angle", Math.toDegrees(angle) + direction + 90.0); + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, selector, EventData.of("Index", Integer.toString(i)), false); + } - HeadRotation rotationComponent = store.getComponent(ref, HeadRotation.getComponentType()); - - assert rotationComponent != null; - - float lookYaw = rotationComponent.getRotation().getYaw(); - double direction = Math.toDegrees(lookYaw); - - for (int i = 0; i < this.respawnPoints.length; i++) { - String selector = "#RespawnPointList[" + i + "]"; - PlayerRespawnPointData respawnPoint = this.respawnPoints[i]; - commandBuilder.append("#RespawnPointList", "Pages/OverrideRespawnPointButton.ui"); - commandBuilder.set(selector + " #Name.Text", respawnPoint.getName()); - Vector3i respawnPointPosition = respawnPoint.getBlockPosition(); - int distance = (int)this.respawnPointToAddPosition.distanceTo(respawnPointPosition.x, this.respawnPointToAddPosition.y, respawnPointPosition.z); - commandBuilder.set(selector + " #Distance.Text", Message.translation("server.customUI.respawnPointDistance").param("distance", distance)); - double angle = Math.atan2(respawnPointPosition.z - this.respawnPointToAddPosition.z, respawnPointPosition.x - this.respawnPointToAddPosition.x); - commandBuilder.set(selector + " #Icon.Angle", Math.toDegrees(angle) + direction + 90.0); - eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, selector, EventData.of("Index", Integer.toString(i)), false); + commandBuilder.set( + "#NameInput.Value", Message.translation("server.customUI.defaultRespawnPointName").param("name", playerRefComponent.getUsername()) + ); + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#ConfirmButton", EventData.of("@RespawnPointName", "#NameInput.Value")); + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#CancelButton", EventData.of("Action", "Cancel")); + } } - - commandBuilder.set("#NameInput.Value", Message.translation("server.customUI.defaultRespawnPointName").param("name", playerRefComponent.getUsername())); - eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#ConfirmButton", EventData.of("@RespawnPointName", "#NameInput.Value")); - eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#CancelButton", EventData.of("Action", "Cancel")); } public void handleDataEvent(@Nonnull Ref ref, @Nonnull Store store, @Nonnull RespawnPointPage.RespawnPointEventData data) { @@ -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..91851d03 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; @@ -34,33 +38,33 @@ public class SetNameRespawnPointPage extends RespawnPointPage { ) { commandBuilder.append("Pages/NameRespawnPointPage.ui"); Player playerComponent = store.getComponent(ref, Player.getComponentType()); - - assert playerComponent != null; - - PlayerRef playerRefComponent = store.getComponent(ref, PlayerRef.getComponentType()); - - assert playerRefComponent != null; - - World world = store.getExternalData().getWorld(); - PlayerRespawnPointData[] respawnPoints = playerComponent.getPlayerConfigData().getPerWorldData(world.getName()).getRespawnPoints(); - String respawnPointName = null; - if (respawnPoints != null) { - for (PlayerRespawnPointData respawnPoint : respawnPoints) { - if (respawnPoint.getBlockPosition().equals(this.respawnBlockPosition)) { - respawnPointName = respawnPoint.getName(); - break; + if (playerComponent != null) { + PlayerRef playerRefComponent = store.getComponent(ref, PlayerRef.getComponentType()); + if (playerRefComponent != null) { + World world = store.getExternalData().getWorld(); + PlayerRespawnPointData[] respawnPoints = playerComponent.getPlayerConfigData().getPerWorldData(world.getName()).getRespawnPoints(); + String respawnPointName = null; + if (respawnPoints != null) { + for (PlayerRespawnPointData respawnPoint : respawnPoints) { + if (respawnPoint.getBlockPosition().equals(this.respawnBlockPosition)) { + respawnPointName = respawnPoint.getName(); + break; + } + } } + + if (respawnPointName == null) { + commandBuilder.set( + "#NameInput.Value", Message.translation("server.customUI.defaultRespawnPointName").param("name", playerRefComponent.getUsername()) + ); + } else { + commandBuilder.set("#NameInput.Value", respawnPointName); + } + + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#SetButton", EventData.of("@RespawnPointName", "#NameInput.Value")); + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#CancelButton", EventData.of("Action", "Cancel")); } } - - if (respawnPointName == null) { - commandBuilder.set("#NameInput.Value", Message.translation("server.customUI.defaultRespawnPointName").param("name", playerRefComponent.getUsername())); - } else { - commandBuilder.set("#NameInput.Value", respawnPointName); - } - - eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#SetButton", EventData.of("@RespawnPointName", "#NameInput.Value")); - eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#CancelButton", EventData.of("Action", "Cancel")); } public void handleDataEvent(@Nonnull Ref ref, @Nonnull Store store, @Nonnull RespawnPointPage.RespawnPointEventData data) { @@ -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..d2e1d61e 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSleep.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/components/PlayerSleep.java @@ -1,22 +1,37 @@ package com.hypixel.hytale.builtin.beds.sleep.components; import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; +import java.time.Duration; import java.time.Instant; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; public sealed interface PlayerSleep permits PlayerSleep.FullyAwake, PlayerSleep.MorningWakeUp, PlayerSleep.NoddingOff, PlayerSleep.Slumber { public static enum FullyAwake implements PlayerSleep { INSTANCE; } - public record MorningWakeUp(Instant gameTimeStart) implements PlayerSleep { - public static PlayerSomnolence createComponent(WorldTimeResource worldTimeResource) { - Instant now = worldTimeResource.getGameTime(); - PlayerSleep.MorningWakeUp state = new PlayerSleep.MorningWakeUp(now); + public record MorningWakeUp(@Nullable Instant gameTimeStart) implements PlayerSleep { + private static final Duration WAKE_UP_AUTOSLEEP_DELAY = Duration.ofHours(1L); + + @Nonnull + public static PlayerSomnolence createComponent(@Nullable Instant gameTimeStart) { + PlayerSleep.MorningWakeUp state = new PlayerSleep.MorningWakeUp(gameTimeStart); return new PlayerSomnolence(state); } + + public boolean isReadyToSleepAgain(Instant worldTime) { + if (this.gameTimeStart == null) { + return true; + } else { + Instant readyTime = worldTime.plus(WAKE_UP_AUTOSLEEP_DELAY); + return worldTime.isAfter(readyTime); + } + } } 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 +40,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..ed5af286 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,15 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class WorldSomnolence implements Resource { + @Nonnull private WorldSleep state = WorldSleep.Awake.INSTANCE; + private long lastSleepNotification; public static ResourceType getResourceType() { return BedsPlugin.getInstance().getWorldSomnolenceResourceType(); } + @Nonnull public WorldSleep getState() { return this.state; } @@ -22,6 +25,21 @@ public class WorldSomnolence implements Resource { this.state = state; } + public boolean useSleepNotificationCooldown(long now, long cooldownMs) { + long elapsedMs = now - this.lastSleepNotification; + boolean ready = elapsedMs >= cooldownMs; + if (ready) { + this.lastSleepNotification = now; + return true; + } else { + return false; + } + } + + public void resetNotificationCooldown() { + this.lastSleepNotification = 0L; + } + @Nullable @Override public Resource clone() { 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..a92d8dbc 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 @@ -9,9 +9,11 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.protocol.BlockMountType; +import com.hypixel.hytale.protocol.SoundCategory; import com.hypixel.hytale.server.core.Message; -import com.hypixel.hytale.server.core.asset.type.gameplay.SleepConfig; +import com.hypixel.hytale.server.core.asset.type.gameplay.sleep.SleepConfig; import com.hypixel.hytale.server.core.universe.PlayerRef; +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.storage.EntityStore; import java.time.Duration; @@ -21,22 +23,43 @@ 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 final ComponentType mountedComponentType; + @Nonnull + private final ComponentType playerRefComponentType; + @Nonnull + private final Query query; - @Override - public ComponentType componentType() { - return MountedComponent.getComponentType(); + public EnterBedSystem( + @Nonnull ComponentType mountedComponentType, @Nonnull ComponentType playerRefComponentType + ) { + this.mountedComponentType = mountedComponentType; + this.playerRefComponentType = playerRefComponentType; + this.query = Query.and(mountedComponentType, playerRefComponentType); } + @Nonnull + @Override + public ComponentType componentType() { + return this.mountedComponentType; + } + + @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } public void onComponentAdded( @Nonnull Ref ref, @Nonnull MountedComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - this.check(ref, component, store); + check(ref, component, store, this.playerRefComponentType); } public void onComponentSet( @@ -46,7 +69,7 @@ public class EnterBedSystem extends RefChangeSystem store, @Nonnull CommandBuffer commandBuffer ) { - this.check(ref, newComponent, store); + check(ref, newComponent, store, this.playerRefComponentType); } public void onComponentRemoved( @@ -54,38 +77,47 @@ public class EnterBedSystem extends RefChangeSystem ref, MountedComponent component, Store store) { + private static void check( + @Nonnull Ref ref, + @Nonnull MountedComponent component, + @Nonnull Store store, + @Nonnull ComponentType playerRefComponentType + ) { if (component.getBlockMountType() == BlockMountType.Bed) { - this.onEnterBed(ref, store); + onEnterBed(ref, store, playerRefComponentType); } } - public void onEnterBed(Ref ref, Store store) { + private static void onEnterBed( + @Nonnull Ref ref, @Nonnull Store store, @Nonnull ComponentType playerRefComponentType + ) { World world = store.getExternalData().getWorld(); CanSleepInWorld.Result canSleepResult = CanSleepInWorld.check(world); if (canSleepResult.isNegative()) { - PlayerRef playerRef = store.getComponent(ref, PlayerRef.getComponentType()); + PlayerRef playerRefComponent = store.getComponent(ref, playerRefComponentType); - assert playerRef != null; + assert playerRefComponent != null; if (canSleepResult instanceof CanSleepInWorld.NotDuringSleepHoursRange(LocalDateTime msg, SleepConfig var14)) { LocalTime startTime = var14.getSleepStartTime(); Duration untilSleep = var14.computeDurationUntilSleep(msg); Message msgx = Message.translation("server.interactions.sleep.sleepAtTheseHours") - .param("time", formatTime(startTime)) + .param("timeValue", startTime.toString()) .param("until", formatDuration(untilSleep)); - playerRef.sendMessage(msgx.color("#F2D729")); + playerRefComponent.sendMessage(msgx.color("#F2D729")); + SoundUtil.playSoundEvent2dToPlayer(playerRefComponent, var14.getSounds().getFailIndex(), SoundCategory.UI); } else { - Message msg = this.getMessage(canSleepResult); - playerRef.sendMessage(msg); + Message msg = getMessage(canSleepResult); + playerRefComponent.sendMessage(msg); } } } - private Message getMessage(CanSleepInWorld.Result param1) { + @Nonnull + private static Message getMessage(@Nonnull CanSleepInWorld.Result param0) { // $VF: Couldn't be decompiled // Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!) - // java.lang.IllegalStateException: Invalid switch case set: [[const(0)], [var1_1 instanceof ignored], [null]] for selector of type Lcom/hypixel/hytale/builtin/beds/sleep/systems/world/CanSleepInWorld$Result; + // java.lang.IllegalStateException: Invalid switch case set: [[const(0)], [var0_1 instanceof ignored], [null]] for selector of type Lcom/hypixel/hytale/builtin/beds/sleep/systems/world/CanSleepInWorld$Result; // at org.jetbrains.java.decompiler.modules.decompiler.exps.SwitchHeadExprent.checkExprTypeBounds(SwitchHeadExprent.java:66) // at org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor.checkTypeExpr(VarTypeProcessor.java:140) // at org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor.checkTypeExprent(VarTypeProcessor.java:126) @@ -98,44 +130,29 @@ 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/RegisterTrackerSystem.java b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/RegisterTrackerSystem.java index c025cf68..8d2caba5 100644 --- a/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/RegisterTrackerSystem.java +++ b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/RegisterTrackerSystem.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.builtin.beds.sleep.systems.player; import com.hypixel.hytale.builtin.beds.sleep.components.SleepTracker; import com.hypixel.hytale.component.AddReason; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.RemoveReason; import com.hypixel.hytale.component.Store; @@ -10,21 +11,32 @@ import com.hypixel.hytale.component.system.HolderSystem; 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 RegisterTrackerSystem extends HolderSystem { + @Nonnull + private final ComponentType sleepTrackerComponentType; + @Nonnull + private final Query query; + + public RegisterTrackerSystem( + @Nonnull ComponentType playerRefComponentType, @Nonnull ComponentType sleepTrackerComponentType + ) { + this.sleepTrackerComponentType = sleepTrackerComponentType; + this.query = playerRefComponentType; + } + @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - holder.ensureComponent(SleepTracker.getComponentType()); + holder.ensureComponent(this.sleepTrackerComponentType); } @Override public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { } - @Nullable + @Nonnull @Override public Query getQuery() { - return PlayerRef.getComponentType(); + return this.query; } } diff --git a/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/SleepNotificationSystem.java b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/SleepNotificationSystem.java new file mode 100644 index 00000000..97113818 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/beds/sleep/systems/player/SleepNotificationSystem.java @@ -0,0 +1,174 @@ +package com.hypixel.hytale.builtin.beds.sleep.systems.player; + +import com.hypixel.hytale.builtin.beds.sleep.components.PlayerSomnolence; +import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSleep; +import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSlumber; +import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSomnolence; +import com.hypixel.hytale.builtin.beds.sleep.systems.world.CanSleepInWorld; +import com.hypixel.hytale.builtin.beds.sleep.systems.world.StartSlumberSystem; +import com.hypixel.hytale.component.ComponentAccessor; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.component.system.DelayedSystem; +import com.hypixel.hytale.protocol.SoundCategory; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.asset.type.gameplay.sleep.SleepSoundsConfig; +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.world.SoundUtil; +import com.hypixel.hytale.server.core.universe.world.World; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; + +public class SleepNotificationSystem extends DelayedSystem { + public static final int SMALL_SERVER_PLAYER_COUNT = 4; + public static final double BIG_SERVER_SLEEPERS_RATIO = 0.5; + public static final String COLOR = "#5AB5B5"; + + public SleepNotificationSystem() { + super(1.0F); + } + + @Override + public void delayedTick(float dt, int systemIndex, @NonNullDecl Store store) { + World world = store.getExternalData().getWorld(); + SleepSoundsConfig sleepSounds = world.getGameplayConfig().getWorldConfig().getSleepConfig().getSounds(); + if (sleepSounds.isNotificationLoopEnabled()) { + maybeDoNotification(store, true); + } + } + + public static void maybeDoNotification(Store store, boolean fromAutoLoop) { + World world = store.getExternalData().getWorld(); + SleepSoundsConfig sleepSounds = world.getGameplayConfig().getWorldConfig().getSleepConfig().getSounds(); + SleepNotificationSystem.NotificationState state = getNotificationState(world); + if (state != SleepNotificationSystem.NotReady.INSTANCE) { + long now = System.currentTimeMillis(); + WorldSomnolence worldSomnolence = store.getResource(WorldSomnolence.getResourceType()); + if (worldSomnolence.useSleepNotificationCooldown(now, sleepSounds.getNotificationLoopCooldownMs())) { + int soundIndex = fromAutoLoop ? sleepSounds.getNotificationLoopIndex() : sleepSounds.getNotificationIndex(); + Collection playerRefs = world.getPlayerRefs(); + + for (PlayerRef playerRef : playerRefs) { + Ref ref = playerRef.getReference(); + if (ref != null && !StartSlumberSystem.canNotifyOthersAboutTryingToSleep(store, ref)) { + SoundUtil.playSoundEvent2dToPlayer(playerRef, soundIndex, SoundCategory.UI); + if (state instanceof SleepNotificationSystem.SmallServer) { + if (state.readyToSleep() == 1) { + Message sleeperName = playerRefs.stream() + .map(PlayerRef::getReference) + .filter(r -> StartSlumberSystem.canNotifyOthersAboutTryingToSleep(store, (Ref)r)) + .map(SleepNotificationSystem::getSleeperName) + .findFirst() + .orElseGet(() -> Message.raw("???")); + String msgKey = fromAutoLoop ? "server.interactions.sleep.notificationSingle" : "server.interactions.sleep.notificationSingleEnter"; + playerRef.sendMessage(Message.translation(msgKey).color("#5AB5B5").param("player", sleeperName)); + } else { + playerRef.sendMessage( + Message.translation("server.interactions.sleep.notificationSmall").color("#5AB5B5").param("sleepers", state.readyToSleep()) + ); + } + } else if (state instanceof SleepNotificationSystem.BigServer) { + playerRef.sendMessage( + Message.translation("server.interactions.sleep.notificationBig") + .color("#5AB5B5") + .param("sleepers", state.readyToSleep()) + .param("total", state.playerCount()) + ); + } + } + } + } + } + } + + private static SleepNotificationSystem.NotificationState getNotificationState(World world) { + if (CanSleepInWorld.check(world).isNegative()) { + return SleepNotificationSystem.NotReady.INSTANCE; + } else { + Store store = world.getEntityStore().getStore(); + WorldSleep worldSleep = store.getResource(WorldSomnolence.getResourceType()).getState(); + if (worldSleep instanceof WorldSlumber) { + return SleepNotificationSystem.NotReady.INSTANCE; + } else { + List> refs = world.getPlayerRefs().stream().map(PlayerRef::getReference).filter(Objects::nonNull).toList(); + int playerCount = refs.size(); + int readyToSleep = countReadyToSleep(refs, store); + if (playerCount <= 4) { + boolean ready = readyToSleep > 0; + return (SleepNotificationSystem.NotificationState)(ready + ? new SleepNotificationSystem.SmallServer(readyToSleep, playerCount) + : SleepNotificationSystem.NotReady.INSTANCE); + } else { + double sleepersRatio = (double)readyToSleep / playerCount; + boolean ready = sleepersRatio >= 0.5; + return (SleepNotificationSystem.NotificationState)(ready + ? new SleepNotificationSystem.BigServer(sleepersRatio, readyToSleep, playerCount) + : SleepNotificationSystem.NotReady.INSTANCE); + } + } + } + } + + private static int countReadyToSleep(Collection> playerRefs, ComponentAccessor store) { + int count = 0; + + for (Ref ref : playerRefs) { + PlayerSomnolence somnolence = store.getComponent(ref, PlayerSomnolence.getComponentType()); + if (somnolence != null) { + boolean readyToSleep = StartSlumberSystem.canNotifyOthersAboutTryingToSleep(store, ref); + if (readyToSleep) { + count++; + } + } + } + + return count; + } + + public static Message getSleeperName(@Nullable Ref ref) { + if (ref != null && ref.isValid()) { + Store store = ref.getStore(); + DisplayNameComponent displayNameComponent = store.getComponent(ref, DisplayNameComponent.getComponentType()); + Message lastSleeperDisplay = displayNameComponent == null ? null : displayNameComponent.getDisplayName(); + if (lastSleeperDisplay != null) { + return lastSleeperDisplay; + } else { + PlayerRef sleeperPlayerRef = store.getComponent(ref, PlayerRef.getComponentType()); + return Message.raw(sleeperPlayerRef == null ? "???" : sleeperPlayerRef.getUsername()); + } + } else { + return Message.raw("???"); + } + } + + private record BigServer(double ratio, int readyToSleep, int playerCount) implements SleepNotificationSystem.NotificationState { + } + + private static enum NotReady implements SleepNotificationSystem.NotificationState { + INSTANCE; + + @Override + public int readyToSleep() { + return 0; + } + + @Override + public int playerCount() { + return 0; + } + } + + private sealed interface NotificationState permits SleepNotificationSystem.NotReady, SleepNotificationSystem.SmallServer, SleepNotificationSystem.BigServer { + int readyToSleep(); + + int playerCount(); + } + + private record SmallServer(int readyToSleep, int playerCount) implements SleepNotificationSystem.NotificationState { + } +} 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..86d14be3 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 @@ -10,19 +10,22 @@ import com.hypixel.hytale.builtin.beds.sleep.systems.world.CanSleepInWorld; import com.hypixel.hytale.builtin.beds.sleep.systems.world.StartSlumberSystem; import com.hypixel.hytale.component.ArchetypeChunk; import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.tick.DelayedEntitySystem; import com.hypixel.hytale.protocol.packets.world.SleepClock; import com.hypixel.hytale.protocol.packets.world.SleepMultiplayer; import com.hypixel.hytale.protocol.packets.world.UpdateSleepState; +import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; 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,19 +33,47 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class UpdateSleepPacketSystem extends DelayedEntitySystem { - 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; + private static final int MAX_SAMPLE_COUNT = 5; + private static final float SYSTEM_INTERVAL_S = 0.25F; + @Nonnull + private static final Duration SPAN_BEFORE_BLACK_SCREEN = Duration.ofMillis(1200L); + @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); + @Nonnull + private final ComponentType playerRefComponentType; + @Nonnull + private final ComponentType playerSomnolenceComponentType; + @Nonnull + private final ComponentType sleepTrackerComponentType; + @Nonnull + private final ResourceType worldSomnolenceResourceType; + @Nonnull + private final ResourceType worldTimeResourceType; + @Nonnull + private final Query query; - @Override - public Query getQuery() { - return QUERY; + public UpdateSleepPacketSystem( + @Nonnull ComponentType playerRefComponentType, + @Nonnull ComponentType playerSomnolenceComponentType, + @Nonnull ComponentType sleepTrackerComponentType, + @Nonnull ResourceType worldSomnolenceResourceType, + @Nonnull ResourceType worldTimeResourceType + ) { + super(0.25F); + this.playerRefComponentType = playerRefComponentType; + this.playerSomnolenceComponentType = playerSomnolenceComponentType; + this.sleepTrackerComponentType = sleepTrackerComponentType; + this.worldSomnolenceResourceType = worldSomnolenceResourceType; + this.worldTimeResourceType = worldTimeResourceType; + this.query = Query.and(playerRefComponentType, playerSomnolenceComponentType, sleepTrackerComponentType); } - public UpdateSleepPacketSystem() { - super(0.25F); + @Nonnull + @Override + public Query getQuery() { + return this.query; } @Override @@ -54,13 +85,13 @@ public class UpdateSleepPacketSystem extends DelayedEntitySystem { @Nonnull CommandBuffer commandBuffer ) { UpdateSleepState packet = this.createSleepPacket(store, index, archetypeChunk); - SleepTracker sleepTrackerComponent = archetypeChunk.getComponent(index, SleepTracker.getComponentType()); + SleepTracker sleepTrackerComponent = archetypeChunk.getComponent(index, this.sleepTrackerComponentType); assert sleepTrackerComponent != null; packet = sleepTrackerComponent.generatePacketToSend(packet); if (packet != null) { - PlayerRef playerRefComponent = archetypeChunk.getComponent(index, PlayerRef.getComponentType()); + PlayerRef playerRefComponent = archetypeChunk.getComponent(index, this.playerRefComponentType); assert playerRefComponent != null; @@ -68,11 +99,12 @@ 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()); - WorldSleep worldSleepState = worldSomnolence.getState(); - PlayerSomnolence playerSomnolenceComponent = archetypeChunk.getComponent(index, PlayerSomnolence.getComponentType()); + WorldSomnolence worldSomnolenceResource = store.getResource(this.worldSomnolenceResourceType); + WorldSleep worldSleepState = worldSomnolenceResource.getState(); + PlayerSomnolence playerSomnolenceComponent = archetypeChunk.getComponent(index, this.playerSomnolenceComponentType); assert playerSomnolenceComponent != null; @@ -101,7 +133,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,16 +141,18 @@ 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(); - boolean readyToSleep = StartSlumberSystem.isReadyToSleep(store, ref); - if (readyToSleep) { - sleepersCount++; - } else { - awakeCount++; - awakeSampleList.add(playerRef.getUuid()); + if (ref != null && ref.isValid()) { + boolean readyToSleep = StartSlumberSystem.isReadyToSleep(store, ref); + if (readyToSleep) { + sleepersCount++; + } else { + awakeCount++; + awakeSampleList.add(playerRef.getUuid()); + } } } 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..b4433919 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,14 +14,29 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class WakeUpOnDismountSystem extends RefChangeSystem { - @Override - public ComponentType componentType() { - return MountedComponent.getComponentType(); + @Nonnull + private final ComponentType mountedComponentType; + @Nonnull + private final ComponentType playerSomnolenceComponentType; + + public WakeUpOnDismountSystem( + @Nonnull ComponentType mountedComponentType, + @Nonnull ComponentType playerSomnolenceComponentType + ) { + this.mountedComponentType = mountedComponentType; + this.playerSomnolenceComponentType = playerSomnolenceComponentType; } + @Nonnull + @Override + public ComponentType componentType() { + return this.mountedComponentType; + } + + @Nonnull @Override public Query getQuery() { - return MountedComponent.getComponentType(); + return this.mountedComponentType; } public void onComponentAdded( @@ -42,7 +57,7 @@ public class WakeUpOnDismountSystem extends RefChangeSystem ref, @Nonnull MountedComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { if (component.getBlockMountType() == BlockMountType.Bed) { - commandBuffer.putComponent(ref, PlayerSomnolence.getComponentType(), PlayerSomnolence.AWAKE); + commandBuffer.putComponent(ref, this.playerSomnolenceComponentType, PlayerSomnolence.AWAKE); } } } 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..5ff3f9ef 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 @@ -1,14 +1,16 @@ package com.hypixel.hytale.builtin.beds.sleep.systems.world; import com.hypixel.hytale.component.Store; -import com.hypixel.hytale.server.core.asset.type.gameplay.SleepConfig; +import com.hypixel.hytale.server.core.asset.type.gameplay.sleep.SleepConfig; 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..a51981c5 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 @@ -6,11 +6,16 @@ import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSleep; import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSlumber; import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSomnolence; import com.hypixel.hytale.component.ComponentAccessor; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.system.DelayedSystem; +import com.hypixel.hytale.protocol.SoundCategory; +import com.hypixel.hytale.server.core.asset.type.gameplay.sleep.SleepConfig; import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; import com.hypixel.hytale.server.core.universe.PlayerRef; +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.storage.EntityStore; import java.time.Duration; @@ -20,13 +25,30 @@ import java.time.ZoneOffset; import java.util.Collection; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; +import javax.annotation.Nullable; 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; + @Nonnull + private final ComponentType playerSomnolenceComponentType; + @Nonnull + private final ResourceType worldSomnolenceResourceType; + @Nonnull + private final ResourceType worldTimeResourceType; - public StartSlumberSystem() { + public StartSlumberSystem( + @Nonnull ComponentType playerSomnolenceComponentType, + @Nonnull ResourceType worldSomnolenceResourceType, + @Nonnull ResourceType worldTimeResourceType + ) { super(0.3F); + this.playerSomnolenceComponentType = playerSomnolenceComponentType; + this.worldSomnolenceResourceType = worldSomnolenceResourceType; + this.worldTimeResourceType = worldTimeResourceType; } @Override @@ -34,25 +56,31 @@ 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()) { if (!CanSleepInWorld.check(world).isNegative()) { - float wakeUpHour = world.getGameplayConfig().getWorldConfig().getSleepConfig().getWakeUpHour(); - WorldSomnolence worldSomnolenceResource = store.getResource(WorldSomnolence.getResourceType()); + SleepConfig sleepConfig = world.getGameplayConfig().getWorldConfig().getSleepConfig(); + float wakeUpHour = sleepConfig.getWakeUpHour(); + WorldSomnolence worldSomnolenceResource = store.getResource(this.worldSomnolenceResourceType); WorldSleep worldState = worldSomnolenceResource.getState(); if (worldState == WorldSleep.Awake.INSTANCE) { if (this.isEveryoneReadyToSleep(store)) { - WorldTimeResource timeResource = store.getResource(WorldTimeResource.getResourceType()); + WorldTimeResource timeResource = store.getResource(this.worldTimeResourceType); Instant now = timeResource.getGameTime(); Instant target = this.computeWakeupInstant(now, wakeUpHour); float irlSeconds = computeIrlSeconds(now, target); worldSomnolenceResource.setState(new WorldSlumber(now, target, irlSeconds)); - store.forEachEntityParallel(PlayerSomnolence.getComponentType(), (index, archetypeChunk, commandBuffer) -> { + store.forEachEntityParallel(this.playerSomnolenceComponentType, (index, archetypeChunk, commandBuffer) -> { Ref ref = archetypeChunk.getReferenceTo(index); - commandBuffer.putComponent(ref, PlayerSomnolence.getComponentType(), PlayerSleep.Slumber.createComponent(timeResource)); + commandBuffer.putComponent(ref, this.playerSomnolenceComponentType, PlayerSleep.Slumber.createComponent(timeResource)); + PlayerRef playerRef = archetypeChunk.getComponent(index, PlayerRef.getComponentType()); + if (playerRef != null) { + SoundUtil.playSoundEvent2dToPlayer(playerRef, sleepConfig.getSounds().getSuccessIndex(), SoundCategory.UI); + } }); + worldSomnolenceResource.resetNotificationCooldown(); } } } @@ -71,21 +99,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 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 +123,54 @@ 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; - } else { - PlayerSleep sleepState = somnolence.getSleepState(); + public static boolean isReadyToSleep(@Nonnull ComponentAccessor store, @Nullable Ref ref) { + if (ref != null && ref.isValid()) { + PlayerSomnolence somnolenceComponent = store.getComponent(ref, PlayerSomnolence.getComponentType()); + if (somnolenceComponent == null) { + return false; + } else { + PlayerSleep sleepState = somnolenceComponent.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 fullAwake -> false; + case PlayerSleep.MorningWakeUp morningWakeUp -> { + WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType()); + yield morningWakeUp.isReadyToSleepAgain(worldTimeResource.getGameTime()); + } + case PlayerSleep.NoddingOff noddingOff -> { + Instant sleepStart = noddingOff.realTimeStart().plus(NODDING_OFF_DURATION); + yield Instant.now().isAfter(sleepStart); + } + case PlayerSleep.Slumber ignored -> true; + default -> throw new MatchException(null, null); + }; + } + } else { + return true; + } + } + + public static boolean canNotifyOthersAboutTryingToSleep(@Nonnull ComponentAccessor store, @Nullable Ref ref) { + if (ref != null && ref.isValid()) { + PlayerSomnolence somnolenceComponent = store.getComponent(ref, PlayerSomnolence.getComponentType()); + if (somnolenceComponent == null) { + return false; + } else { + PlayerSleep sleepState = somnolenceComponent.getSleepState(); + + return switch (sleepState) { + case PlayerSleep.FullyAwake fullAwake -> false; + case PlayerSleep.MorningWakeUp morningWakeUp -> { + WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType()); + yield morningWakeUp.isReadyToSleepAgain(worldTimeResource.getGameTime()); + } + case PlayerSleep.NoddingOff noddingOff -> true; + case PlayerSleep.Slumber ignored -> true; + default -> throw new MatchException(null, null); + }; + } + } else { + return true; } } } 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..640ee1d6 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 @@ -6,7 +6,9 @@ import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSleep; import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSlumber; import com.hypixel.hytale.builtin.beds.sleep.resources.WorldSomnolence; import com.hypixel.hytale.component.ComponentAccessor; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.system.tick.TickingSystem; import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; @@ -16,36 +18,57 @@ 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 { + @Nonnull + private final ComponentType playerSomnolenceComponentType; + @Nonnull + private final ResourceType worldSomnolenceResourceType; + @Nonnull + private final ResourceType worldTimeResourceType; + + public UpdateWorldSlumberSystem( + @Nonnull ComponentType playerSomnolenceComponentType, + @Nonnull ResourceType worldSomnolenceResourceType, + @Nonnull ResourceType worldTimeResourceType + ) { + this.playerSomnolenceComponentType = playerSomnolenceComponentType; + this.worldSomnolenceResourceType = worldSomnolenceResourceType; + this.worldTimeResourceType = worldTimeResourceType; + } + @Override public void tick(float dt, int systemIndex, @Nonnull Store store) { World world = store.getExternalData().getWorld(); - WorldSomnolence worldSomnolence = store.getResource(WorldSomnolence.getResourceType()); - if (worldSomnolence.getState() instanceof WorldSlumber slumber) { - slumber.incProgressSeconds(dt); - boolean sleepingIsOver = slumber.getProgressSeconds() >= slumber.getIrlDurationSeconds() || isSomeoneAwake(store); + WorldSomnolence worldSomnolenceResource = store.getResource(this.worldSomnolenceResourceType); + if (worldSomnolenceResource.getState() instanceof WorldSlumber slumber) { + slumber.incrementProgressSeconds(dt); + boolean itsMorningTimeToWAKEUP = slumber.getProgressSeconds() >= slumber.getIrlDurationSeconds(); + boolean someoneIsAwake = isSomeoneAwake(store, this.playerSomnolenceComponentType); + boolean sleepingIsOver = itsMorningTimeToWAKEUP || someoneIsAwake; if (sleepingIsOver) { - worldSomnolence.setState(WorldSleep.Awake.INSTANCE); - WorldTimeResource timeResource = store.getResource(WorldTimeResource.getResourceType()); + worldSomnolenceResource.setState(WorldSleep.Awake.INSTANCE); + WorldTimeResource timeResource = store.getResource(this.worldTimeResourceType); + Instant now = timeResource.getGameTime(); Instant wakeUpTime = computeWakeupTime(slumber); timeResource.setGameTime(wakeUpTime, world, store); - store.forEachEntityParallel(PlayerSomnolence.getComponentType(), (index, archetypeChunk, commandBuffer) -> { - PlayerSomnolence somnolenceComponent = archetypeChunk.getComponent(index, PlayerSomnolence.getComponentType()); + store.forEachEntityParallel(this.playerSomnolenceComponentType, (index, archetypeChunk, commandBuffer) -> { + PlayerSomnolence somnolenceComponent = archetypeChunk.getComponent(index, this.playerSomnolenceComponentType); assert somnolenceComponent != null; if (somnolenceComponent.getSleepState() instanceof PlayerSleep.Slumber) { Ref ref = archetypeChunk.getReferenceTo(index); - commandBuffer.putComponent(ref, PlayerSomnolence.getComponentType(), PlayerSleep.MorningWakeUp.createComponent(timeResource)); + PlayerSomnolence sleepComponent = PlayerSleep.MorningWakeUp.createComponent(itsMorningTimeToWAKEUP ? now : null); + commandBuffer.putComponent(ref, this.playerSomnolenceComponentType, sleepComponent); } }); } } } + @Nonnull private static Instant computeWakeupTime(@Nonnull WorldSlumber slumber) { float progress = slumber.getProgressSeconds() / slumber.getIrlDurationSeconds(); long totalNanos = Duration.between(slumber.getStartInstant(), slumber.getTargetInstant()).toNanos(); @@ -53,25 +76,28 @@ public class UpdateWorldSlumberSystem extends TickingSystem { return slumber.getStartInstant().plusNanos(progressNanos); } - private static boolean isSomeoneAwake(@Nonnull ComponentAccessor store) { + private static boolean isSomeoneAwake( + @Nonnull ComponentAccessor store, @Nonnull ComponentType playerSomnolenceComponentType + ) { World world = store.getExternalData().getWorld(); Collection playerRefs = world.getPlayerRefs(); 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, playerSomnolenceComponentType); + 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/blockphysics/BlockPhysicsSystems.java b/src/com/hypixel/hytale/builtin/blockphysics/BlockPhysicsSystems.java index 755e9718..44dd8109 100644 --- a/src/com/hypixel/hytale/builtin/blockphysics/BlockPhysicsSystems.java +++ b/src/com/hypixel/hytale/builtin/blockphysics/BlockPhysicsSystems.java @@ -5,6 +5,7 @@ import com.hypixel.hytale.component.ArchetypeChunk; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.DisableProcessingAssert; +import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.dependency.Dependency; import com.hypixel.hytale.component.dependency.Order; @@ -30,10 +31,12 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockPhysicsSystems { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static final int MAX_SUPPORT_RADIUS = 14; public static class CachedAccessor extends AbstractCachedAccessor { + @Nonnull private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(BlockPhysicsSystems.CachedAccessor::new); private static final int PHYSICS_COMPONENT = 0; private static final int FLUID_COMPONENT = 1; @@ -125,9 +128,11 @@ public class BlockPhysicsSystems { } public static class Ticking extends EntityTickingSystem implements DisableProcessingAssert { + @Nonnull private static final Query QUERY = Query.and( ChunkSection.getComponentType(), BlockSection.getComponentType(), BlockPhysics.getComponentType(), FluidSection.getComponentType() ); + @Nonnull private static final Set> DEPENDENCIES = Set.of( new SystemDependency<>(Order.AFTER, ChunkBlockTickSystem.PreTick.class), new SystemDependency<>(Order.BEFORE, ChunkBlockTickSystem.Ticking.class) ); @@ -157,28 +162,40 @@ public class BlockPhysicsSystems { assert section != null; try { - BlockSection blockSection = archetypeChunk.getComponent(index, BlockSection.getComponentType()); - - assert blockSection != null; - - if (blockSection.getTickingBlocksCountCopy() <= 0) { + BlockSection blockSectionComponent = archetypeChunk.getComponent(index, BlockSection.getComponentType()); + if (blockSectionComponent == null) { return; } - BlockPhysics blockPhysics = archetypeChunk.getComponent(index, BlockPhysics.getComponentType()); + if (blockSectionComponent.getTickingBlocksCountCopy() <= 0) { + return; + } - assert blockPhysics != null; + BlockPhysics blockPhysicsComponent = archetypeChunk.getComponent(index, BlockPhysics.getComponentType()); + if (blockPhysicsComponent == null) { + return; + } - FluidSection fluidSection = archetypeChunk.getComponent(index, FluidSection.getComponentType()); + FluidSection fluidSectionComponent = archetypeChunk.getComponent(index, FluidSection.getComponentType()); + if (fluidSectionComponent == null) { + return; + } - assert fluidSection != null; + Ref columnRef = section.getChunkColumnReference(); + if (columnRef == null || !columnRef.isValid()) { + return; + } + + WorldChunk worldChunkComponent = commandBuffer.getComponent(columnRef, WorldChunk.getComponentType()); + if (worldChunkComponent == null) { + return; + } - WorldChunk worldChunk = commandBuffer.getComponent(section.getChunkColumnReference(), WorldChunk.getComponentType()); BlockPhysicsSystems.CachedAccessor accessor = BlockPhysicsSystems.CachedAccessor.of( - commandBuffer, blockSection, blockPhysics, fluidSection, section.getX(), section.getY(), section.getZ(), 14 + commandBuffer, blockSectionComponent, blockPhysicsComponent, fluidSectionComponent, section.getX(), section.getY(), section.getZ(), 14 ); - blockSection.forEachTicking( - worldChunk, + blockSectionComponent.forEachTicking( + worldChunkComponent, accessor, section.getY(), (wc, accessor1, localX, localY, localZ, blockId) -> { @@ -218,8 +235,8 @@ public class BlockPhysicsSystems { } } ); - } catch (Exception var12) { - BlockPhysicsSystems.LOGGER.at(Level.SEVERE).withCause(var12).log("Failed to tick chunk: %s", section); + } catch (Exception var13) { + BlockPhysicsSystems.LOGGER.at(Level.SEVERE).withCause(var13).log("Failed to tick chunk: %s", section); } } } diff --git a/src/com/hypixel/hytale/builtin/blockphysics/BlockPhysicsUtil.java b/src/com/hypixel/hytale/builtin/blockphysics/BlockPhysicsUtil.java index 97872125..ae2db82b 100644 --- a/src/com/hypixel/hytale/builtin/blockphysics/BlockPhysicsUtil.java +++ b/src/com/hypixel/hytale/builtin/blockphysics/BlockPhysicsUtil.java @@ -34,7 +34,7 @@ public class BlockPhysicsUtil { @Nonnull public static BlockPhysicsUtil.Result applyBlockPhysics( - @Nullable ComponentAccessor commandBuffer, + @Nonnull ComponentAccessor componentAccessor, @Nonnull Ref chunkReference, @Nonnull BlockPhysicsSystems.CachedAccessor chunkAccessor, BlockSection blockSection, @@ -55,9 +55,7 @@ public class BlockPhysicsUtil { supportDistance = testBlockPhysics(chunkAccessor, blockSection, blockPhysics, fluidSection, blockX, blockY, blockZ, blockType, rotation, filler); } else { BlockBoundingBoxes boundingBoxes = BlockBoundingBoxes.getAssetMap().getAsset(blockType.getHitboxTypeIndex()); - if (!boundingBoxes.protrudesUnitBox()) { - supportDistance = testBlockPhysics(chunkAccessor, blockSection, blockPhysics, fluidSection, blockX, blockY, blockZ, blockType, rotation, filler); - } else { + if (boundingBoxes != null && boundingBoxes.protrudesUnitBox()) { BlockBoundingBoxes.RotatedVariantBoxes rotatedBox = boundingBoxes.get(rotation); Box boundingBox = rotatedBox.getBoundingBox(); int minX = (int)boundingBox.min.x; @@ -94,7 +92,7 @@ public class BlockPhysicsUtil { int blockHeight = Math.max(maxY - minY, 1); int blockDepth = Math.max(maxZ - minZ, 1); - label138: + label136: for (int x = 0; x < blockWidth; x++) { for (int y = 0; y < blockHeight; y++) { for (int z = 0; z < blockDepth; z++) { @@ -140,7 +138,7 @@ public class BlockPhysicsUtil { case Any: if (fillerSupportDistance == -2) { supportDistance = -2; - break label138; + break label136; } if (fillerSupportDistance == 0) { @@ -152,7 +150,7 @@ public class BlockPhysicsUtil { case All: if (fillerSupportDistance == 0) { supportDistance = 0; - break label138; + break label136; } if (fillerSupportDistance == -2) { @@ -165,21 +163,23 @@ public class BlockPhysicsUtil { } } } + } else { + supportDistance = testBlockPhysics(chunkAccessor, blockSection, blockPhysics, fluidSection, blockX, blockY, blockZ, blockType, rotation, filler); } } if (supportDistance == 0) { - World world = commandBuffer.getExternalData().getWorld(); + World world = componentAccessor.getExternalData().getWorld(); Store chunkStore = world.getChunkStore().getStore(); switch (blockType.getSupportDropType()) { case BREAK: BlockHarvestUtils.naturallyRemoveBlockByPhysics( - new Vector3i(blockX, blockY, blockZ), blockType, filler, 256, chunkReference, commandBuffer, chunkStore + new Vector3i(blockX, blockY, blockZ), blockType, filler, 256, chunkReference, componentAccessor, chunkStore ); break; case DESTROY: BlockHarvestUtils.naturallyRemoveBlockByPhysics( - new Vector3i(blockX, blockY, blockZ), blockType, filler, 2304, chunkReference, commandBuffer, chunkStore + new Vector3i(blockX, blockY, blockZ), blockType, filler, 2304, chunkReference, componentAccessor, chunkStore ); } @@ -289,7 +289,6 @@ public class BlockPhysicsUtil { if (requiredBlockFaceSupport.isAppliedToFiller(blockFillerOffset)) { boolean doesSatisfyRequirements = doesSatisfyRequirements( blockType, - fluid, blockFillerOffset, neighbourFillerOffset, blockFace, @@ -361,7 +360,6 @@ public class BlockPhysicsUtil { public static boolean doesSatisfyRequirements( @Nonnull BlockType blockType, - Fluid fluid, Vector3i blockFillerOffset, Vector3i neighbourFillerOffset, BlockFace blockFace, diff --git a/src/com/hypixel/hytale/builtin/blockphysics/PrefabBufferValidator.java b/src/com/hypixel/hytale/builtin/blockphysics/PrefabBufferValidator.java index bf8be09c..1692a8ce 100644 --- a/src/com/hypixel/hytale/builtin/blockphysics/PrefabBufferValidator.java +++ b/src/com/hypixel/hytale/builtin/blockphysics/PrefabBufferValidator.java @@ -31,16 +31,17 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PrefabBufferValidator { + @Nonnull private static final FillerBlockUtil.FillerFetcher FILLER_FETCHER = new FillerBlockUtil.FillerFetcher() { - public int getBlock(IPrefabBuffer iPrefabBuffer, Void unused, int x, int y, int z) { + public int getBlock(@Nonnull IPrefabBuffer iPrefabBuffer, Void unused, int x, int y, int z) { return iPrefabBuffer.getBlockId(x, y, z); } - public int getFiller(IPrefabBuffer iPrefabBuffer, Void unused, int x, int y, int z) { + public int getFiller(@Nonnull IPrefabBuffer iPrefabBuffer, Void unused, int x, int y, int z) { return iPrefabBuffer.getFiller(x, y, z); } - public int getRotationIndex(IPrefabBuffer iPrefabBuffer, Void unused, int x, int y, int z) { + public int getRotationIndex(@Nonnull IPrefabBuffer iPrefabBuffer, Void unused, int x, int y, int z) { return iPrefabBuffer.getRotationIndex(x, y, z); } }; diff --git a/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerEntry.java b/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerEntry.java index c2cdd817..c108ab93 100644 --- a/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerEntry.java +++ b/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerEntry.java @@ -35,6 +35,7 @@ public class BlockSpawnerEntry implements IWeightedElement { ) .add() .build(); + @Nonnull public static final BlockSpawnerEntry[] EMPTY_ARRAY = new BlockSpawnerEntry[0]; private String blockName; private Holder blockComponents; @@ -63,6 +64,7 @@ public class BlockSpawnerEntry implements IWeightedElement { RANDOM, INHERIT; + @Nonnull public static final Codec CODEC = new EnumCodec<>(BlockSpawnerEntry.RotationMode.class); } } diff --git a/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerPlugin.java b/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerPlugin.java index 7216dab2..1896fccd 100644 --- a/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerPlugin.java +++ b/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerPlugin.java @@ -38,6 +38,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockSpawnerPlugin extends JavaPlugin { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); private ComponentType blockSpawnerComponentType; private static BlockSpawnerPlugin INSTANCE; @@ -70,14 +71,14 @@ public class BlockSpawnerPlugin extends JavaPlugin { this.getEventRegistry().registerGlobal(PrefabBufferValidator.ValidateBlockEvent.class, BlockSpawnerPlugin::validatePrefabBlock); } - private static void validatePrefabBlock(PrefabBufferValidator.ValidateBlockEvent validateBlockEvent) { + private static void validatePrefabBlock(@Nonnull PrefabBufferValidator.ValidateBlockEvent validateBlockEvent) { Holder holder = validateBlockEvent.holder(); if (holder != null) { - BlockSpawner spawner = holder.getComponent(BlockSpawner.getComponentType()); - if (spawner != null) { + BlockSpawner blockSpawnerComponent = holder.getComponent(BlockSpawner.getComponentType()); + if (blockSpawnerComponent != null) { BlockType blockType = BlockType.getAssetMap().getAsset(validateBlockEvent.blockId()); if (blockType != null) { - if (spawner.getBlockSpawnerId() == null) { + if (blockSpawnerComponent.getBlockSpawnerId() == null) { validateBlockEvent.reason() .append("\t Block ") .append(blockType.getId()) @@ -90,7 +91,7 @@ public class BlockSpawnerPlugin extends JavaPlugin { .append(" has no defined block spawner id") .append('\n'); } else { - BlockSpawnerTable blockSpawner = BlockSpawnerTable.getAssetMap().getAsset(spawner.getBlockSpawnerId()); + BlockSpawnerTable blockSpawner = BlockSpawnerTable.getAssetMap().getAsset(blockSpawnerComponent.getBlockSpawnerId()); if (blockSpawner == null) { validateBlockEvent.reason() .append("\t Block ") @@ -102,7 +103,7 @@ public class BlockSpawnerPlugin extends JavaPlugin { .append(", ") .append(validateBlockEvent.z()) .append(" has an invalid spawner id ") - .append(spawner.getBlockSpawnerId()) + .append(blockSpawnerComponent.getBlockSpawnerId()) .append('\n'); } } @@ -116,8 +117,11 @@ public class BlockSpawnerPlugin extends JavaPlugin { } private static class BlockSpawnerSystem extends RefSystem { + @Nonnull private static final ComponentType COMPONENT_TYPE = BlockSpawner.getComponentType(); + @Nonnull private static final ComponentType BLOCK_INFO_COMPONENT_TYPE = BlockModule.BlockStateInfo.getComponentType(); + @Nonnull private static final Query QUERY = Query.and(COMPONENT_TYPE, BLOCK_INFO_COMPONENT_TYPE); public BlockSpawnerSystem() { @@ -134,72 +138,74 @@ public class BlockSpawnerPlugin extends JavaPlugin { ) { WorldConfig worldConfig = store.getExternalData().getWorld().getWorldConfig(); if (worldConfig.getGameMode() != GameMode.Creative) { - BlockSpawner state = commandBuffer.getComponent(ref, COMPONENT_TYPE); + BlockSpawner blockSpawnerComponent = commandBuffer.getComponent(ref, COMPONENT_TYPE); - assert state != null; + assert blockSpawnerComponent != null; - BlockModule.BlockStateInfo info = commandBuffer.getComponent(ref, BLOCK_INFO_COMPONENT_TYPE); + BlockModule.BlockStateInfo blockStateInfoComponent = commandBuffer.getComponent(ref, BLOCK_INFO_COMPONENT_TYPE); - assert info != null; + assert blockStateInfoComponent != null; - String blockSpawnerId = state.getBlockSpawnerId(); + String blockSpawnerId = blockSpawnerComponent.getBlockSpawnerId(); if (blockSpawnerId != null) { BlockSpawnerTable table = BlockSpawnerTable.getAssetMap().getAsset(blockSpawnerId); if (table == null) { BlockSpawnerPlugin.LOGGER.at(Level.WARNING).log("Failed to find BlockSpawner Asset by name: %s", blockSpawnerId); } else { - Ref chunk = info.getChunkRef(); - if (chunk != null) { - WorldChunk wc = commandBuffer.getComponent(chunk, WorldChunk.getComponentType()); - int x = ChunkUtil.worldCoordFromLocalCoord(wc.getX(), ChunkUtil.xFromBlockInColumn(info.getIndex())); - int y = ChunkUtil.yFromBlockInColumn(info.getIndex()); - int z = ChunkUtil.worldCoordFromLocalCoord(wc.getZ(), ChunkUtil.zFromBlockInColumn(info.getIndex())); - long seed = worldConfig.getSeed(); - double randomRnd = HashUtil.random(x, y, z, seed + -1699164769L); - BlockSpawnerEntry entry = table.getEntries().get(randomRnd); - if (entry != null) { - String blockKey = entry.getBlockName(); + Ref chunkRef = blockStateInfoComponent.getChunkRef(); + if (chunkRef.isValid()) { + WorldChunk worldChunkComponent = commandBuffer.getComponent(chunkRef, WorldChunk.getComponentType()); + if (worldChunkComponent != null) { + int x = ChunkUtil.worldCoordFromLocalCoord(worldChunkComponent.getX(), ChunkUtil.xFromBlockInColumn(blockStateInfoComponent.getIndex())); + int y = ChunkUtil.yFromBlockInColumn(blockStateInfoComponent.getIndex()); + int z = ChunkUtil.worldCoordFromLocalCoord(worldChunkComponent.getZ(), ChunkUtil.zFromBlockInColumn(blockStateInfoComponent.getIndex())); + long seed = worldConfig.getSeed(); + double randomRnd = HashUtil.random(x, y, z, seed + -1699164769L); + BlockSpawnerEntry entry = table.getEntries().get(randomRnd); + if (entry != null) { + String blockKey = entry.getBlockName(); - RotationTuple rotation = switch (entry.getRotationMode()) { - case NONE -> RotationTuple.NONE; - case RANDOM -> { - String key = entry.getBlockName(); - VariantRotation variantRotation = BlockType.getAssetMap().getAsset(key).getVariantRotation(); - if (variantRotation == VariantRotation.None) { - yield RotationTuple.NONE; - } else { - int randomHash = (int)HashUtil.rehash(x, y, z, seed + -1699164769L); - Rotation rotationYaw = Rotation.NORMAL[(randomHash & 65535) % Rotation.NORMAL.length]; - yield BlockRotationUtil.getRotated(RotationTuple.NONE, Axis.Y, rotationYaw, variantRotation); + RotationTuple rotation = switch (entry.getRotationMode()) { + case NONE -> RotationTuple.NONE; + case RANDOM -> { + String key = entry.getBlockName(); + VariantRotation variantRotation = BlockType.getAssetMap().getAsset(key).getVariantRotation(); + if (variantRotation == VariantRotation.None) { + yield RotationTuple.NONE; + } else { + int randomHash = (int)HashUtil.rehash(x, y, z, seed + -1699164769L); + Rotation rotationYaw = Rotation.NORMAL[(randomHash & 65535) % Rotation.NORMAL.length]; + yield BlockRotationUtil.getRotated(RotationTuple.NONE, Axis.Y, rotationYaw, variantRotation); + } } - } - case INHERIT -> { - String key = entry.getBlockName(); - VariantRotation variantRotation = BlockType.getAssetMap().getAsset(key).getVariantRotation(); - if (variantRotation == VariantRotation.None) { - yield RotationTuple.NONE; - } else { - RotationTuple spawnerRotation = RotationTuple.get(wc.getRotationIndex(x, y, z)); - Rotation spawnerYaw = spawnerRotation.yaw(); - yield BlockRotationUtil.getRotated(RotationTuple.NONE, Axis.Y, spawnerYaw, variantRotation); + case INHERIT -> { + String key = entry.getBlockName(); + VariantRotation variantRotation = BlockType.getAssetMap().getAsset(key).getVariantRotation(); + if (variantRotation == VariantRotation.None) { + yield RotationTuple.NONE; + } else { + RotationTuple spawnerRotation = RotationTuple.get(worldChunkComponent.getRotationIndex(x, y, z)); + Rotation spawnerYaw = spawnerRotation.yaw(); + yield BlockRotationUtil.getRotated(RotationTuple.NONE, Axis.Y, spawnerYaw, variantRotation); + } + } + }; + Holder holder = entry.getBlockComponents(); + commandBuffer.removeEntity(ref, RemoveReason.REMOVE); + commandBuffer.run(_store -> { + int flags = 4; + if (holder != null) { + flags |= 2; } - } - }; - Holder holder = entry.getBlockComponents(); - commandBuffer.removeEntity(ref, RemoveReason.REMOVE); - commandBuffer.run(_store -> { - int flags = 4; - if (holder != null) { - flags |= 2; - } - int blockId = BlockType.getAssetMap().getIndex(blockKey); - BlockType blockType = BlockType.getAssetMap().getAsset(blockId); - wc.setBlock(x, y, z, blockId, blockType, rotation.index(), 0, flags); - if (holder != null) { - wc.setState(x, y, z, holder.clone()); - } - }); + int blockId = BlockType.getAssetMap().getIndex(blockKey); + BlockType blockType = BlockType.getAssetMap().getAsset(blockId); + worldChunkComponent.setBlock(x, y, z, blockId, blockType, rotation.index(), 0, flags); + if (holder != null) { + worldChunkComponent.setState(x, y, z, holder.clone()); + } + }); + } } } } diff --git a/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerTable.java b/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerTable.java index b745d5c6..3f127c7b 100644 --- a/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerTable.java +++ b/src/com/hypixel/hytale/builtin/blockspawner/BlockSpawnerTable.java @@ -16,6 +16,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockSpawnerTable implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( BlockSpawnerTable.class, BlockSpawnerTable::new, diff --git a/src/com/hypixel/hytale/builtin/blockspawner/command/BlockSpawnerGetCommand.java b/src/com/hypixel/hytale/builtin/blockspawner/command/BlockSpawnerGetCommand.java index c0508c0f..28387395 100644 --- a/src/com/hypixel/hytale/builtin/blockspawner/command/BlockSpawnerGetCommand.java +++ b/src/com/hypixel/hytale/builtin/blockspawner/command/BlockSpawnerGetCommand.java @@ -25,6 +25,8 @@ public class BlockSpawnerGetCommand extends AbstractWorldCommand { @Nonnull private static final Message MESSAGE_COMMANDS_ERRORS_PROVIDE_POSITION = Message.translation("server.commands.errors.providePosition"); @Nonnull + private static final Message MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_IN_WORLD = Message.translation("server.commands.errors.playerNotInWorld"); + @Nonnull private static final Message MESSAGE_COMMANDS_BLOCK_SPAWNER_NO_BLOCK_SPAWNER_SET = Message.translation("server.commands.blockspawner.noBlockSpawnerSet"); @Nonnull private final OptionalArg positionArg = this.withOptionalArg( @@ -47,6 +49,10 @@ public class BlockSpawnerGetCommand extends AbstractWorldCommand { } Ref ref = context.senderAsPlayerRef(); + if (ref == null || !ref.isValid()) { + throw new GeneralCommandException(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_IN_WORLD); + } + Vector3i targetBlock = TargetUtil.getTargetBlock(ref, 10.0, store); if (targetBlock == null) { throw new GeneralCommandException(MESSAGE_GENERAL_BLOCK_TARGET_NOT_IN_RANGE); @@ -64,9 +70,7 @@ public class BlockSpawnerGetCommand extends AbstractWorldCommand { assert worldChunkComponent != null; Ref blockRef = worldChunkComponent.getBlockComponentEntity(position.x, position.y, position.z); - if (blockRef == null) { - context.sendMessage(Message.translation("server.general.containerNotFound").param("block", position.toString())); - } else { + if (blockRef != null && blockRef.isValid()) { BlockSpawner spawnerState = chunkStore.getStore().getComponent(blockRef, BlockSpawner.getComponentType()); if (spawnerState == null) { context.sendMessage(Message.translation("server.general.containerNotFound").param("block", position.toString())); @@ -77,6 +81,8 @@ public class BlockSpawnerGetCommand extends AbstractWorldCommand { context.sendMessage(Message.translation("server.commands.blockspawner.currentBlockSpawner").param("id", spawnerState.getBlockSpawnerId())); } } + } else { + context.sendMessage(Message.translation("server.general.containerNotFound").param("block", position.toString())); } } else { context.sendMessage(Message.translation("server.general.containerNotFound").param("block", position.toString())); diff --git a/src/com/hypixel/hytale/builtin/blockspawner/command/BlockSpawnerSetCommand.java b/src/com/hypixel/hytale/builtin/blockspawner/command/BlockSpawnerSetCommand.java index de3885a3..a0ec6065 100644 --- a/src/com/hypixel/hytale/builtin/blockspawner/command/BlockSpawnerSetCommand.java +++ b/src/com/hypixel/hytale/builtin/blockspawner/command/BlockSpawnerSetCommand.java @@ -30,6 +30,8 @@ public class BlockSpawnerSetCommand extends AbstractWorldCommand { @Nonnull private static final Message MESSAGE_COMMANDS_ERRORS_PROVIDE_POSITION = Message.translation("server.commands.errors.providePosition"); @Nonnull + private static final Message MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_IN_WORLD = Message.translation("server.commands.errors.playerNotInWorld"); + @Nonnull private static final SingleArgumentType BLOCK_SPAWNER_ASSET_TYPE = new AssetArgumentType( "server.commands.parsing.argtype.asset.blockspawnertable.name", BlockSpawnerTable.class, "server.commands.parsing.argtype.asset.blockspawnertable.usage" ); @@ -60,6 +62,10 @@ public class BlockSpawnerSetCommand extends AbstractWorldCommand { } Ref ref = context.senderAsPlayerRef(); + if (ref == null || !ref.isValid()) { + throw new GeneralCommandException(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_IN_WORLD); + } + Vector3i targetBlock = TargetUtil.getTargetBlock(ref, 10.0, store); if (targetBlock == null) { throw new GeneralCommandException(MESSAGE_GENERAL_BLOCK_TARGET_NOT_IN_RANGE); @@ -68,32 +74,37 @@ public class BlockSpawnerSetCommand extends AbstractWorldCommand { position = targetBlock; } - WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(position.x, position.z)); - Ref blockRef = chunk.getBlockComponentEntity(position.x, position.y, position.z); - if (blockRef == null) { + WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(position.x, position.z)); + if (worldChunk == null) { context.sendMessage(Message.translation("server.general.containerNotFound").param("block", position.toString())); } else { - BlockSpawner spawnerState = world.getChunkStore().getStore().getComponent(blockRef, BlockSpawner.getComponentType()); - if (spawnerState == null) { - context.sendMessage(Message.translation("server.general.containerNotFound").param("block", position.toString())); - } else { - String spawnerId; - if (this.ignoreChecksFlag.get(context)) { - String[] input = context.getInput(this.blockSpawnerIdArg); - spawnerId = input != null && input.length > 0 ? input[0] : null; - if (spawnerId == null) { - context.sendMessage( - Message.translation("errors.validation_failure").param("message", "blockSpawnerId is required when --ignoreChecks is set") - ); - return; - } + Ref blockRef = worldChunk.getBlockComponentEntity(position.x, position.y, position.z); + if (blockRef != null && blockRef.isValid()) { + Store chunkStore = world.getChunkStore().getStore(); + BlockSpawner spawnerState = chunkStore.getComponent(blockRef, BlockSpawner.getComponentType()); + if (spawnerState == null) { + context.sendMessage(Message.translation("server.general.containerNotFound").param("block", position.toString())); } else { - spawnerId = this.blockSpawnerIdArg.get(context).getId(); - } + String spawnerId; + if (this.ignoreChecksFlag.get(context)) { + String[] input = context.getInput(this.blockSpawnerIdArg); + spawnerId = input != null && input.length > 0 ? input[0] : null; + if (spawnerId == null) { + context.sendMessage( + Message.translation("errors.validation_failure").param("message", "blockSpawnerId is required when --ignoreChecks is set") + ); + return; + } + } else { + spawnerId = this.blockSpawnerIdArg.get(context).getId(); + } - spawnerState.setBlockSpawnerId(spawnerId); - chunk.markNeedsSaving(); - context.sendMessage(Message.translation("server.commands.blockspawner.blockSpawnerSet").param("id", spawnerId)); + spawnerState.setBlockSpawnerId(spawnerId); + worldChunk.markNeedsSaving(); + context.sendMessage(Message.translation("server.commands.blockspawner.blockSpawnerSet").param("id", spawnerId)); + } + } else { + context.sendMessage(Message.translation("server.general.containerNotFound").param("block", position.toString())); } } } diff --git a/src/com/hypixel/hytale/builtin/blockspawner/state/BlockSpawner.java b/src/com/hypixel/hytale/builtin/blockspawner/state/BlockSpawner.java index 66b7958a..941ddaeb 100644 --- a/src/com/hypixel/hytale/builtin/blockspawner/state/BlockSpawner.java +++ b/src/com/hypixel/hytale/builtin/blockspawner/state/BlockSpawner.java @@ -11,6 +11,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockSpawner implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(BlockSpawner.class, BlockSpawner::new) .addField(new KeyedCodec<>("BlockSpawnerId", Codec.STRING), (state, s) -> state.blockSpawnerId = s, state -> state.blockSpawnerId) .build(); diff --git a/src/com/hypixel/hytale/builtin/blocktick/BlockTickPlugin.java b/src/com/hypixel/hytale/builtin/blocktick/BlockTickPlugin.java index 06445e1e..6c8ca34c 100644 --- a/src/com/hypixel/hytale/builtin/blocktick/BlockTickPlugin.java +++ b/src/com/hypixel/hytale/builtin/blocktick/BlockTickPlugin.java @@ -55,19 +55,17 @@ public class BlockTickPlugin extends JavaPlugin implements IBlockTickProvider { } } - public int discoverTickingBlocks(@Nonnull Holder holder, @Nonnull WorldChunk chunk) { + public int discoverTickingBlocks(@Nonnull Holder holder, @Nonnull WorldChunk worldChunk) { if (!this.isEnabled()) { return 0; } else { - BlockChunk bc = chunk.getBlockChunk(); - if (!bc.consumeNeedsPhysics()) { - return 0; - } else { - ChunkColumn column = holder.getComponent(ChunkColumn.getComponentType()); - if (column == null) { + BlockChunk blockChunkComponent = worldChunk.getBlockChunk(); + if (blockChunkComponent != null && blockChunkComponent.consumeNeedsPhysics()) { + ChunkColumn chunkColumnComponent = holder.getComponent(ChunkColumn.getComponentType()); + if (chunkColumnComponent == null) { return 0; } else { - Holder[] sections = column.getSectionHolders(); + Holder[] sections = chunkColumnComponent.getSectionHolders(); if (sections == null) { return 0; } else { @@ -76,14 +74,14 @@ public class BlockTickPlugin extends JavaPlugin implements IBlockTickProvider { for (int i = 0; i < sections.length; i++) { Holder sectionHolder = sections[i]; - BlockSection section = sectionHolder.ensureAndGetComponent(BlockSection.getComponentType()); - if (!section.isSolidAir()) { + BlockSection blockSectionComponent = sectionHolder.ensureAndGetComponent(BlockSection.getComponentType()); + if (!blockSectionComponent.isSolidAir()) { for (int blockIdx = 0; blockIdx < 32768; blockIdx++) { - int blockId = section.get(blockIdx); + int blockId = blockSectionComponent.get(blockIdx); BlockType blockType = assetMap.getAsset(blockId); if (blockType != null && blockType.getTickProcedure() != null) { - section.setTicking(blockIdx, true); - bc.markNeedsSaving(); + blockSectionComponent.setTicking(blockIdx, true); + blockChunkComponent.markNeedsSaving(); count++; } } @@ -93,6 +91,8 @@ public class BlockTickPlugin extends JavaPlugin implements IBlockTickProvider { return count; } } + } else { + return 0; } } } diff --git a/src/com/hypixel/hytale/builtin/blocktick/procedure/BasicChanceBlockGrowthProcedure.java b/src/com/hypixel/hytale/builtin/blocktick/procedure/BasicChanceBlockGrowthProcedure.java index 6c24dc54..f21ec9b6 100644 --- a/src/com/hypixel/hytale/builtin/blocktick/procedure/BasicChanceBlockGrowthProcedure.java +++ b/src/com/hypixel/hytale/builtin/blocktick/procedure/BasicChanceBlockGrowthProcedure.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import javax.annotation.Nonnull; public class BasicChanceBlockGrowthProcedure extends TickProcedure { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( BasicChanceBlockGrowthProcedure.class, BasicChanceBlockGrowthProcedure::new, TickProcedure.BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/blocktick/procedure/SplitChanceBlockGrowthProcedure.java b/src/com/hypixel/hytale/builtin/blocktick/procedure/SplitChanceBlockGrowthProcedure.java index c7065285..9f7a0a46 100644 --- a/src/com/hypixel/hytale/builtin/blocktick/procedure/SplitChanceBlockGrowthProcedure.java +++ b/src/com/hypixel/hytale/builtin/blocktick/procedure/SplitChanceBlockGrowthProcedure.java @@ -14,6 +14,7 @@ import org.bson.BsonDocument; import org.bson.BsonValue; public class SplitChanceBlockGrowthProcedure extends BasicChanceBlockGrowthProcedure { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SplitChanceBlockGrowthProcedure.class, SplitChanceBlockGrowthProcedure::new, TickProcedure.BASE_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/blocktick/system/ChunkBlockTickSystem.java b/src/com/hypixel/hytale/builtin/blocktick/system/ChunkBlockTickSystem.java index e02dfa99..3016e5cd 100644 --- a/src/com/hypixel/hytale/builtin/blocktick/system/ChunkBlockTickSystem.java +++ b/src/com/hypixel/hytale/builtin/blocktick/system/ChunkBlockTickSystem.java @@ -21,20 +21,23 @@ 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.storage.EntityStore; import java.time.Instant; import java.util.Set; import java.util.logging.Level; import javax.annotation.Nonnull; public class ChunkBlockTickSystem { + @Nonnull protected static final HytaleLogger LOGGER = BlockTickPlugin.get().getLogger(); public static class PreTick extends EntityTickingSystem { - private static final ComponentType COMPONENT_TYPE = BlockChunk.getComponentType(); + @Nonnull + private static final ComponentType COMPONENT_TYPE_WORLD_CHUNK = BlockChunk.getComponentType(); @Override public Query getQuery() { - return COMPONENT_TYPE; + return COMPONENT_TYPE_WORLD_CHUNK; } @Override @@ -50,26 +53,30 @@ public class ChunkBlockTickSystem { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - Instant time = commandBuffer.getExternalData().getWorld().getEntityStore().getStore().getResource(WorldTimeResource.getResourceType()).getGameTime(); - BlockChunk chunk = archetypeChunk.getComponent(index, COMPONENT_TYPE); + World world = commandBuffer.getExternalData().getWorld(); + Store entityStore = world.getEntityStore().getStore(); + Instant timeResource = entityStore.getResource(WorldTimeResource.getResourceType()).getGameTime(); + BlockChunk blockChunkComponent = archetypeChunk.getComponent(index, COMPONENT_TYPE_WORLD_CHUNK); - assert chunk != null; + assert blockChunkComponent != null; try { - chunk.preTick(time); - } catch (Throwable var9) { - ChunkBlockTickSystem.LOGGER.at(Level.SEVERE).withCause(var9).log("Failed to pre-tick chunk: %s", chunk); + blockChunkComponent.preTick(timeResource); + } catch (Throwable var11) { + ChunkBlockTickSystem.LOGGER.at(Level.SEVERE).withCause(var11).log("Failed to pre-tick chunk: %s", blockChunkComponent); } } } public static class Ticking extends EntityTickingSystem { - private static final ComponentType COMPONENT_TYPE = WorldChunk.getComponentType(); + @Nonnull + private static final ComponentType COMPONENT_TYPE_WORLD_CHUNK = WorldChunk.getComponentType(); + @Nonnull private static final Set> DEPENDENCIES = Set.of(new SystemDependency<>(Order.AFTER, ChunkBlockTickSystem.PreTick.class)); @Override public Query getQuery() { - return COMPONENT_TYPE; + return COMPONENT_TYPE_WORLD_CHUNK; } @Nonnull @@ -87,24 +94,33 @@ public class ChunkBlockTickSystem { @Nonnull CommandBuffer commandBuffer ) { Ref reference = archetypeChunk.getReferenceTo(index); - WorldChunk worldChunk = archetypeChunk.getComponent(index, COMPONENT_TYPE); + WorldChunk worldChunkComponent = archetypeChunk.getComponent(index, COMPONENT_TYPE_WORLD_CHUNK); + + assert worldChunkComponent != null; try { - tick(reference, worldChunk); + tick(reference, worldChunkComponent); } catch (Throwable var9) { - ChunkBlockTickSystem.LOGGER.at(Level.SEVERE).withCause(var9).log("Failed to tick chunk: %s", worldChunk); + ChunkBlockTickSystem.LOGGER.at(Level.SEVERE).withCause(var9).log("Failed to tick chunk: %s", worldChunkComponent); } } - protected static void tick(Ref ref, @Nonnull WorldChunk worldChunk) { - int ticked = worldChunk.getBlockChunk().forEachTicking(ref, worldChunk, (r, c, localX, localY, localZ, blockId) -> { - World world = c.getWorld(); - int blockX = c.getX() << 5 | localX; - int blockZ = c.getZ() << 5 | localZ; - return tickProcedure(world, c, blockX, localY, blockZ, blockId); - }); - if (ticked > 0) { - ChunkBlockTickSystem.LOGGER.at(Level.FINER).log("Ticked %d blocks in chunk (%d, %d)", ticked, worldChunk.getX(), worldChunk.getZ()); + protected static void tick(@Nonnull Ref ref, @Nonnull WorldChunk worldChunk) { + BlockChunk blockChunkComponent = worldChunk.getBlockChunk(); + if (blockChunkComponent == null) { + ChunkBlockTickSystem.LOGGER + .at(Level.WARNING) + .log("World chunk (%d, %d) has no BlockChunk component, skipping block ticking.", worldChunk.getX(), worldChunk.getZ()); + } else { + int ticked = blockChunkComponent.forEachTicking(ref, worldChunk, (r, c, localX, localY, localZ, blockId) -> { + World world = c.getWorld(); + int blockX = c.getX() << 5 | localX; + int blockZ = c.getZ() << 5 | localZ; + return tickProcedure(world, c, blockX, localY, blockZ, blockId); + }); + if (ticked > 0) { + ChunkBlockTickSystem.LOGGER.at(Level.FINER).log("Ticked %d blocks in chunk (%d, %d)", ticked, worldChunk.getX(), worldChunk.getZ()); + } } } diff --git a/src/com/hypixel/hytale/builtin/blocktick/system/MergeWaitingBlocksSystem.java b/src/com/hypixel/hytale/builtin/blocktick/system/MergeWaitingBlocksSystem.java index 362fb77d..1228da96 100644 --- a/src/com/hypixel/hytale/builtin/blocktick/system/MergeWaitingBlocksSystem.java +++ b/src/com/hypixel/hytale/builtin/blocktick/system/MergeWaitingBlocksSystem.java @@ -15,6 +15,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import javax.annotation.Nonnull; public class MergeWaitingBlocksSystem extends RefSystem { + @Nonnull private static final ComponentType COMPONENT_TYPE = WorldChunk.getComponentType(); @Override @@ -27,9 +28,12 @@ public class MergeWaitingBlocksSystem extends RefSystem { @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { ChunkStore chunkStore = store.getExternalData(); - WorldChunk chunk = store.getComponent(ref, COMPONENT_TYPE); - int x = chunk.getX(); - int z = chunk.getZ(); + WorldChunk worldChunkComponent = store.getComponent(ref, COMPONENT_TYPE); + + assert worldChunkComponent != null; + + int x = worldChunkComponent.getX(); + int z = worldChunkComponent.getZ(); mergeTickingBlocks(chunkStore, x - 1, z); mergeTickingBlocks(chunkStore, x + 1, z); mergeTickingBlocks(chunkStore, x, z - 1); @@ -43,9 +47,10 @@ public class MergeWaitingBlocksSystem extends RefSystem { } public static void mergeTickingBlocks(@Nonnull ChunkStore store, int x, int z) { - BlockChunk blockChunk = store.getChunkComponent(ChunkUtil.indexChunk(x, z), BlockChunk.getComponentType()); - if (blockChunk != null) { - blockChunk.mergeTickingBlocks(); + long chunkIndex = ChunkUtil.indexChunk(x, z); + BlockChunk blockChunkComponent = store.getChunkComponent(chunkIndex, BlockChunk.getComponentType()); + if (blockChunkComponent != null) { + blockChunkComponent.mergeTickingBlocks(); } } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPacketHandler.java b/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPacketHandler.java index e26ff51d..1c12ef5e 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPacketHandler.java +++ b/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPacketHandler.java @@ -8,7 +8,6 @@ import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.Axis; -import com.hypixel.hytale.math.matrix.Matrix4d; import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3f; @@ -32,6 +31,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; @@ -55,544 +55,549 @@ import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.io.handlers.IPacketHandler; +import com.hypixel.hytale.server.core.io.handlers.IWorldPacketHandler; import com.hypixel.hytale.server.core.io.handlers.SubPacketHandler; 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.permissions.PermissionsModule; import com.hypixel.hytale.server.core.prefab.selection.mask.BlockPattern; 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.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.logging.Level; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.joml.Quaterniond; public class BuilderToolsPacketHandler implements SubPacketHandler { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull + private static final String BUILDER_TOOL_ID_EXTRUDE = "Extrude"; + @Nonnull + private static final String BUILDER_TOOL_ID_SELECTION = "Selection"; + @Nonnull + private static final String BUILDER_TOOL_ID_LINE = "Line"; + @Nonnull + private static final Message MESSAGE_BUILDER_TOOLS_USAGE_DENIED = Message.translation("server.builderTools.usageDenied"); + @Nonnull private final IPacketHandler packetHandler; - public BuilderToolsPacketHandler(IPacketHandler packetHandler) { + public BuilderToolsPacketHandler(@Nonnull IPacketHandler packetHandler) { this.packetHandler = packetHandler; } + private static boolean hasPermission(@Nonnull PlayerRef playerRef) { + return hasPermission(playerRef, null); + } + + private static boolean hasPermission(@Nonnull PlayerRef playerRef, @Nullable String additionalPermission) { + UUID playerUuid = playerRef.getUuid(); + PermissionsModule permissionsModule = PermissionsModule.get(); + boolean hasBuilderToolsEditor = permissionsModule.hasPermission(playerUuid, "hytale.editor.builderTools"); + boolean hasAdditionalPerm = additionalPermission != null && permissionsModule.hasPermission(playerUuid, additionalPermission); + if (!hasBuilderToolsEditor && !hasAdditionalPerm) { + playerRef.sendMessage(MESSAGE_BUILDER_TOOLS_USAGE_DENIED); + return false; + } else { + return true; + } + } + @Override public void registerHandlers() { if (BuilderToolsPlugin.get().isDisabled()) { this.packetHandler.registerNoOpHandlers(400, 401, 412, 409, 403, 406, 407, 413, 414, 417); } else { - this.packetHandler.registerHandler(106, p -> this.handle((LoadHotbar)p)); - this.packetHandler.registerHandler(107, p -> this.handle((SaveHotbar)p)); - this.packetHandler.registerHandler(400, p -> this.handle((BuilderToolArgUpdate)p)); - this.packetHandler.registerHandler(401, p -> this.handle((BuilderToolEntityAction)p)); - this.packetHandler.registerHandler(412, p -> this.handle((BuilderToolGeneralAction)p)); - this.packetHandler.registerHandler(409, p -> this.handle((BuilderToolSelectionUpdate)p)); - this.packetHandler.registerHandler(403, p -> this.handle((BuilderToolExtrudeAction)p)); - this.packetHandler.registerHandler(406, p -> this.handle((BuilderToolRotateClipboard)p)); - this.packetHandler.registerHandler(407, p -> this.handle((BuilderToolPasteClipboard)p)); - this.packetHandler.registerHandler(413, p -> this.handle((BuilderToolOnUseInteraction)p)); - this.packetHandler.registerHandler(410, p -> this.handle((BuilderToolSelectionToolAskForClipboard)p)); - this.packetHandler.registerHandler(414, p -> this.handle((BuilderToolLineAction)p)); - this.packetHandler.registerHandler(402, p -> this.handle((BuilderToolSetEntityTransform)p)); - this.packetHandler.registerHandler(420, p -> this.handle((BuilderToolSetEntityScale)p)); - this.packetHandler.registerHandler(405, p -> this.handle((BuilderToolSelectionTransform)p)); - this.packetHandler.registerHandler(404, p -> this.handle((BuilderToolStackArea)p)); - this.packetHandler.registerHandler(408, p -> this.handle((BuilderToolSetTransformationModeState)p)); - this.packetHandler.registerHandler(417, p -> this.handle((PrefabUnselectPrefab)p)); - 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)); + IWorldPacketHandler.registerHandler(this.packetHandler, 106, this::handleLoadHotbar, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 107, this::handleSaveHotbar, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 401, this::handleBuilderToolEntityAction, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 402, this::handleBuilderToolSetEntityTransform, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 420, this::handleBuilderToolSetEntityScale, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler( + this.packetHandler, 408, this::handleBuilderToolSetTransformationModeState, BuilderToolsPacketHandler::hasPermission + ); + IWorldPacketHandler.registerHandler(this.packetHandler, 417, this::handlePrefabUnselectPrefab, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 421, this::handleBuilderToolSetEntityPickupEnabled, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 422, this::handleBuilderToolSetEntityLight, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 423, this::handleBuilderToolSetNPCDebug, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 425, this::handleBuilderToolSetEntityCollision, BuilderToolsPacketHandler::hasPermission); + IWorldPacketHandler.registerHandler(this.packetHandler, 400, this::handleBuilderToolArgUpdate, p -> hasPermission(p, "hytale.editor.brush.config")); + IWorldPacketHandler.registerHandler( + this.packetHandler, 409, this::handleBuilderToolSelectionUpdate, p -> hasPermission(p, "hytale.editor.selection.use") + ); + IWorldPacketHandler.registerHandler( + this.packetHandler, 403, this::handleBuilderToolExtrudeAction, p -> hasPermission(p, "hytale.editor.selection.modify") + ); + IWorldPacketHandler.registerHandler( + this.packetHandler, 406, this::handleBuilderToolRotateClipboard, p -> hasPermission(p, "hytale.editor.selection.clipboard") + ); + IWorldPacketHandler.registerHandler( + this.packetHandler, 407, this::handleBuilderToolPasteClipboard, p -> hasPermission(p, "hytale.editor.selection.clipboard") + ); + IWorldPacketHandler.registerHandler(this.packetHandler, 413, this::handleBuilderToolOnUseInteraction, p -> hasPermission(p, "hytale.editor.brush.use")); + IWorldPacketHandler.registerHandler( + this.packetHandler, 410, this::handleBuilderToolSelectionToolAskForClipboard, p -> hasPermission(p, "hytale.editor.selection.clipboard") + ); + IWorldPacketHandler.registerHandler(this.packetHandler, 414, this::handleBuilderToolLineAction, p -> hasPermission(p, "hytale.editor.brush.use")); + IWorldPacketHandler.registerHandler( + this.packetHandler, 405, this::handleBuilderToolSelectionTransform, p -> hasPermission(p, "hytale.editor.selection.clipboard") + ); + IWorldPacketHandler.registerHandler( + this.packetHandler, 404, this::handleBuilderToolStackArea, p -> hasPermission(p, "hytale.editor.selection.clipboard") + ); + IWorldPacketHandler.registerHandler(this.packetHandler, 412, this::handleBuilderToolGeneralAction); } } - static boolean hasPermission(@Nonnull Player player) { - if (!player.hasPermission("hytale.editor.builderTools")) { - player.sendMessage(Message.translation("server.builderTools.usageDenied")); - return false; - } else { - return true; + public void handleBuilderToolSetTransformationModeState( + @Nonnull BuilderToolSetTransformationModeState packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + ToolOperation.getOrCreatePrototypeSettings(playerRef.getUuid()).setInSelectionTransformationMode(packet.enabled); + } + + public void handleBuilderToolArgUpdate( + @Nonnull BuilderToolArgUpdate packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + BuilderToolsPlugin.get().onToolArgUpdate(playerRef, playerComponent, packet); } } - static boolean hasPermission(@Nonnull Player player, @Nonnull String permission) { - if (!player.hasPermission(permission) && !player.hasPermission("hytale.editor.builderTools")) { - player.sendMessage(Message.translation("server.builderTools.usageDenied")); - return false; - } else { - return true; + public void handleLoadHotbar( + @Nonnull LoadHotbar packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + playerComponent.getHotbarManager().loadHotbar(ref, packet.inventoryRow, store); } } - public void handle(@Nonnull BuilderToolSetTransformationModeState 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)) { + public void handleSaveHotbar( + @Nonnull SaveHotbar packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + playerComponent.getHotbarManager().saveHotbar(ref, packet.inventoryRow, store); + } + } + + public void handleBuilderToolEntityAction( + @Nonnull BuilderToolEntityAction packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + int targetId = packet.entityId; + Ref targetRef = world.getEntityStore().getRefFromNetworkId(targetId); + if (targetRef != null && targetRef.isValid()) { + Player targetPlayerComponent = store.getComponent(targetRef, Player.getComponentType()); + if (targetPlayerComponent != null) { + playerComponent.sendMessage(Message.translation("server.builderTools.entityTool.cannotTargetPlayer")); + } else { LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - ToolOperation.getOrCreatePrototypeSettings(playerRef.getUuid()).setInSelectionTransformationMode(packet.enabled); - } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolSetTransformationModeState packet. Player ref is invalid!"); - } - } - - public void handle(@Nonnull BuilderToolArgUpdate 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, "hytale.editor.brush.config")) { - BuilderToolsPlugin.get().onToolArgUpdate(playerRef, playerComponent, packet); - } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolArgUpdate packet. Player ref is invalid!"); - } - } - - public void handle(@Nonnull LoadHotbar 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()); - - assert playerComponent != null; - - playerComponent.getHotbarManager().loadHotbar(ref, packet.inventoryRow, store); - }); - } else { - throw new RuntimeException("Unable to process LoadHotbar packet. Player ref is invalid!"); - } - } - - public void handle(@Nonnull SaveHotbar 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()); - - assert playerComponent != null; - - playerComponent.getHotbarManager().saveHotbar(ref, packet.inventoryRow, store); - }); - } else { - throw new RuntimeException("Unable to process SaveHotbar packet. Player ref is invalid!"); - } - } - - public void handle(@Nonnull BuilderToolEntityAction 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)) { - int entityId = packet.entityId; - Ref entityReference = world.getEntityStore().getRefFromNetworkId(entityId); - if (entityReference == null) { - playerComponent.sendMessage(Message.translation("server.general.entityNotFound").param("id", entityId)); - } else { - Player targetPlayerComponent = store.getComponent(entityReference, Player.getComponentType()); - if (targetPlayerComponent != null) { - playerComponent.sendMessage(Message.translation("server.builderTools.entityTool.cannotTargetPlayer")); - } else { - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - switch (packet.action) { - case Freeze: - UUIDComponent uuidComponent = store.getComponent(entityReference, UUIDComponent.getComponentType()); - if (uuidComponent != null) { - CommandManager.get().handleCommand(playerComponent, "npc freeze --toggle --entity " + uuidComponent.getUuid()); - } - break; - case Clone: - world.execute(() -> EntityCloneCommand.cloneEntity(playerComponent, entityReference, store)); - break; - case Remove: - world.execute(() -> EntityRemoveCommand.removeEntity(ref, entityReference, store)); + switch (packet.action) { + case Freeze: + UUIDComponent uuidComponent = store.getComponent(targetRef, UUIDComponent.getComponentType()); + if (uuidComponent != null) { + CommandManager.get().handleCommand(playerComponent, "npc freeze --toggle --entity " + uuidComponent.getUuid()); } - } + break; + case Clone: + world.execute(() -> EntityCloneCommand.cloneEntity(playerComponent, targetRef, store)); + break; + case Remove: + world.execute(() -> EntityRemoveCommand.removeEntity(ref, targetRef, store)); } } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolEntityAction packet. Player ref is invalid!"); + } else { + playerComponent.sendMessage(Message.translation("server.general.entityNotFound").param("id", targetId)); + } } } - public void handle(@Nonnull BuilderToolGeneralAction 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()); - - assert playerComponent != null; - - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - switch (packet.action) { - case HistoryUndo: - if (!hasPermission(playerComponent, "hytale.editor.history")) { - return; - } - - BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.undo(r, 1, componentAccessor)); - break; - case HistoryRedo: - if (!hasPermission(playerComponent, "hytale.editor.history")) { - return; - } - - BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.redo(r, 1, componentAccessor)); - break; - case SelectionCopy: - if (!hasPermission(playerComponent, "hytale.editor.selection.clipboard")) { - return; - } - - CopyCommand.copySelection(ref, store); - break; - case SelectionPosition1: - case SelectionPosition2: - if (!hasPermission(playerComponent, "hytale.editor.selection.use")) { - return; - } - - TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); - BuilderToolsPlugin.BuilderState builderState = BuilderToolsPlugin.getState(playerComponent, playerRef); - Vector3d position = transformComponent.getPosition(); - Vector3i intTriple = new Vector3i(MathUtil.floor(position.getX()), MathUtil.floor(position.getY()), MathUtil.floor(position.getZ())); - BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> { - if (packet.action == BuilderToolAction.SelectionPosition1) { - builderState.pos1(intTriple, componentAccessor); - } else { - builderState.pos2(intTriple, componentAccessor); - } - }); - break; - case ActivateToolMode: - if (!hasPermission(playerComponent)) { - return; - } - - playerComponent.getInventory().setUsingToolsItem(true); - break; - case DeactivateToolMode: - if (!hasPermission(playerComponent)) { - return; - } - - playerComponent.getInventory().setUsingToolsItem(false); - } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolGeneralAction packet. Player ref is invalid!"); - } - } - - public void handle(@Nonnull BuilderToolSelectionUpdate 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, "hytale.editor.selection.use")) { - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - BuilderToolsPlugin.addToQueue( - playerComponent, - playerRef, - (r, s, componentAccessor) -> s.update(packet.xMin, packet.yMin, packet.zMin, packet.xMax, packet.yMax, packet.zMax) - ); + public void handleBuilderToolGeneralAction( + @Nonnull BuilderToolGeneralAction packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + switch (packet.action) { + case HistoryUndo: + if (!hasPermission(playerRef, "hytale.editor.history")) { + return; } - } - ); - } else { - throw new RuntimeException("Unable to process BuilderToolSelectionUpdate packet. Player ref is invalid!"); - } - } - public void handle(BuilderToolSelectionToolAskForClipboard 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, "hytale.editor.selection.clipboard")) { - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - PrototypePlayerBuilderToolSettings prototypeSettings = ToolOperation.getOrCreatePrototypeSettings(playerRef.getUuid()); - BuilderToolsPlugin.addToQueue( - playerComponent, - playerRef, - (r, s, componentAccessor) -> { - BlockSelection selection = s.getSelection(); - if (selection != null) { - EditorBlocksChange editorPacket = selection.toPacket(); - BlockChange[] blocksChange = editorPacket.blocksChange; - prototypeSettings.setBlockChangesForPlaySelectionToolPasteMode(blocksChange); - ArrayList fluidChanges = new ArrayList<>(); - int anchorX = selection.getAnchorX(); - int anchorY = selection.getAnchorY(); - int anchorZ = selection.getAnchorZ(); - selection.forEachFluid( - (x, y, z, fluidId, fluidLevel) -> fluidChanges.add( - new PrototypePlayerBuilderToolSettings.FluidChange(x - anchorX, y - anchorY, z - anchorZ, fluidId, fluidLevel) - ) - ); - PrototypePlayerBuilderToolSettings.FluidChange[] fluidChangesArray = fluidChanges.toArray( - PrototypePlayerBuilderToolSettings.FluidChange[]::new - ); - prototypeSettings.setFluidChangesForPlaySelectionToolPasteMode(fluidChangesArray); - FluidChange[] packetFluids = new FluidChange[fluidChangesArray.length]; - - for (int i = 0; i < fluidChangesArray.length; i++) { - PrototypePlayerBuilderToolSettings.FluidChange fc = fluidChangesArray[i]; - packetFluids[i] = new FluidChange(fc.x(), fc.y(), fc.z(), fc.fluidId(), fc.fluidLevel()); - } - - playerRef.getPacketHandler().write(new BuilderToolSelectionToolReplyWithClipboard(blocksChange, packetFluids)); - } - } - ); + BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.undo(r, 1, componentAccessor)); + break; + case HistoryRedo: + if (!hasPermission(playerRef, "hytale.editor.history")) { + return; } - } - ); - } else { - throw new RuntimeException("Unable to process BuilderToolSelectionToolAskForClipboard packet. Player ref is invalid!"); - } - } - public int toInt(float value) { - return (int)Math.floor(value + 0.1); - } - - private void handle(@Nonnull BuilderToolSelectionTransform 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, "hytale.editor.selection.clipboard")) { - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - boolean keepEmptyBlocks = true; - BuilderTool builderTool = BuilderTool.getActiveBuilderTool(playerComponent); - if (builderTool != null && builderTool.getId().equals("Selection")) { - BuilderTool.ArgData args = builderTool.getItemArgData(playerComponent.getInventory().getItemInHand()); - if (args != null && args.tool() != null) { - keepEmptyBlocks = (Boolean)args.tool().getOrDefault("KeepEmptyBlocks", true); - } - } - - boolean finalKeepEmptyBlocks = keepEmptyBlocks; - float[] tmx = new float[16]; - - for (int i = 0; i < packet.transformationMatrix.length; i++) { - tmx[i] = this.toInt(packet.transformationMatrix[i]); - } - - Matrix4d transformationMatrix = new Matrix4d() - .assign( - tmx[0], tmx[4], tmx[8], tmx[12], tmx[1], tmx[5], tmx[9], tmx[13], tmx[2], tmx[6], tmx[10], tmx[14], tmx[3], tmx[7], tmx[11], tmx[15] - ); - Vector3i initialSelectionMin = new Vector3i(packet.initialSelectionMin.x, packet.initialSelectionMin.y, packet.initialSelectionMin.z); - Vector3i initialSelectionMax = new Vector3i(packet.initialSelectionMax.x, packet.initialSelectionMax.y, packet.initialSelectionMax.z); - Vector3f rotationOrigin = new Vector3f(packet.initialRotationOrigin.x, packet.initialRotationOrigin.y, packet.initialRotationOrigin.z); - PrototypePlayerBuilderToolSettings prototypeSettings = ToolOperation.getOrCreatePrototypeSettings(playerRef.getUuid()); - BuilderToolsPlugin.addToQueue( - playerComponent, - playerRef, - (r, s, componentAccessor) -> { - int blockCount = s.getSelection().getSelectionVolume(); - boolean large = blockCount > 20000; - if (large) { - playerComponent.sendMessage(Message.translation("server.builderTools.selection.large.warning")); - } - - if (prototypeSettings.getBlockChangesForPlaySelectionToolPasteMode() == null) { - s.select(initialSelectionMin, initialSelectionMax, "SelectionTranslatePacket", componentAccessor); - if (packet.cutOriginal) { - s.copyOrCut( - r, - initialSelectionMin.x, - initialSelectionMin.y, - initialSelectionMin.z, - initialSelectionMax.x, - initialSelectionMax.y, - initialSelectionMax.z, - 138, - store - ); - } else { - s.copyOrCut( - r, - initialSelectionMin.x, - initialSelectionMin.y, - initialSelectionMin.z, - initialSelectionMax.x, - initialSelectionMax.y, - initialSelectionMax.z, - 136, - store - ); - } - - BlockSelection selection = s.getSelection(); - BlockChange[] blocksChange = selection.toPacket().blocksChange; - prototypeSettings.setBlockChangesForPlaySelectionToolPasteMode(blocksChange); - ArrayList fluidChanges = new ArrayList<>(); - int anchorX = selection.getAnchorX(); - int anchorY = selection.getAnchorY(); - int anchorZ = selection.getAnchorZ(); - selection.forEachFluid( - (x, y, z, fluidId, fluidLevel) -> fluidChanges.add( - new PrototypePlayerBuilderToolSettings.FluidChange(x - anchorX, y - anchorY, z - anchorZ, fluidId, fluidLevel) - ) - ); - prototypeSettings.setFluidChangesForPlaySelectionToolPasteMode( - fluidChanges.toArray(PrototypePlayerBuilderToolSettings.FluidChange[]::new) - ); - prototypeSettings.setBlockChangeOffsetOrigin(new Vector3i(selection.getX(), selection.getY(), selection.getZ())); - } - - Vector3i blockChangeOffsetOrigin = prototypeSettings.getBlockChangeOffsetOrigin(); - if (packet.initialPastePointForClipboardPaste != null) { - blockChangeOffsetOrigin = new Vector3i( - packet.initialPastePointForClipboardPaste.x, - packet.initialPastePointForClipboardPaste.y, - packet.initialPastePointForClipboardPaste.z - ); - } - - if (blockChangeOffsetOrigin == null) { - playerComponent.sendMessage(Message.translation("server.builderTools.selection.noBlockChangeOffsetOrigin")); - } else { - s.transformThenPasteClipboard( - prototypeSettings.getBlockChangesForPlaySelectionToolPasteMode(), - prototypeSettings.getFluidChangesForPlaySelectionToolPasteMode(), - transformationMatrix, - rotationOrigin, - blockChangeOffsetOrigin, - finalKeepEmptyBlocks, - componentAccessor - ); - s.select(initialSelectionMin, initialSelectionMax, "SelectionTranslatePacket", componentAccessor); - s.transformSelectionPoints(transformationMatrix, rotationOrigin); - if (large) { - playerComponent.sendMessage(Message.translation("server.builderTools.selection.large.complete")); - } - - if (packet.isExitingTransformMode) { - prototypeSettings.setInSelectionTransformationMode(false); - } - } - } - ); + BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.redo(r, 1, componentAccessor)); + break; + case SelectionCopy: + if (!hasPermission(playerRef, "hytale.editor.selection.clipboard")) { + return; } - } - ); - } else { - throw new RuntimeException("Unable to process BuilderToolSelectionTransform packet. Player ref is invalid!"); - } - } - public void handle(@Nonnull BuilderToolExtrudeAction 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, "hytale.editor.selection.modify")) { - BuilderTool builderTool = BuilderTool.getActiveBuilderTool(playerComponent); - if (builderTool != null && builderTool.getId().equals("Extrude")) { - ItemStack activeItemStack = playerComponent.getInventory().getItemInHand(); - BuilderTool.ArgData args = builderTool.getItemArgData(activeItemStack); - int extrudeDepth = (Integer)args.tool().get("ExtrudeDepth"); - int extrudeRadius = (Integer)args.tool().get("ExtrudeRadius"); - int blockId = ((BlockPattern)args.tool().get("ExtrudeMaterial")).firstBlock(); - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - BuilderToolsPlugin.addToQueue( - playerComponent, - playerRef, - (r, s, componentAccessor) -> s.extendFace( - packet.x, - packet.y, - packet.z, - packet.xNormal, - packet.yNormal, - packet.zNormal, - extrudeDepth, - extrudeRadius, - blockId, - null, - null, - componentAccessor - ) - ); - } + CopyCommand.copySelection(ref, store); + break; + case SelectionPosition1: + case SelectionPosition2: + if (!hasPermission(playerRef, "hytale.editor.selection.use")) { + return; } - } - ); - } else { - throw new RuntimeException("Unable to process BuilderToolExtrudeAction packet. Player ref is invalid!"); - } - } - public void handle(@Nonnull BuilderToolStackArea 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()); + TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); + if (transformComponent == null) { + return; + } - assert playerComponent != null; - - if (hasPermission(playerComponent, "hytale.editor.selection.clipboard")) { - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + BuilderToolsPlugin.BuilderState builderState = BuilderToolsPlugin.getState(playerComponent, playerRef); + Vector3d position = transformComponent.getPosition(); + Vector3i intTriple = new Vector3i(MathUtil.floor(position.getX()), MathUtil.floor(position.getY()), MathUtil.floor(position.getZ())); 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 (packet.action == BuilderToolAction.SelectionPosition1) { + builderState.pos1(intTriple, componentAccessor); + } else { + builderState.pos2(intTriple, componentAccessor); + } }); + break; + case ActivateToolMode: + if (!hasPermission(playerRef, "hytale.editor.builderTools")) { + return; + } + + playerComponent.getInventory().setUsingToolsItem(true); + break; + case DeactivateToolMode: + if (!hasPermission(playerRef, "hytale.editor.builderTools")) { + return; + } + + playerComponent.getInventory().setUsingToolsItem(false); + } + } + } + + public void handleBuilderToolSelectionUpdate( + @Nonnull BuilderToolSelectionUpdate packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + BuilderToolsPlugin.addToQueue( + playerComponent, playerRef, (r, s, componentAccessor) -> s.update(packet.xMin, packet.yMin, packet.zMin, packet.xMax, packet.yMax, packet.zMax) + ); + } + } + + public void handleBuilderToolSelectionToolAskForClipboard( + @Nonnull BuilderToolSelectionToolAskForClipboard packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + PrototypePlayerBuilderToolSettings prototypeSettings = ToolOperation.getOrCreatePrototypeSettings(playerRef.getUuid()); + BuilderToolsPlugin.addToQueue( + playerComponent, + playerRef, + (r, s, componentAccessor) -> { + BlockSelection selection = s.getSelection(); + if (selection != null) { + EditorBlocksChange editorPacket = selection.toPacket(); + BlockChange[] blocksChange = editorPacket.blocksChange; + prototypeSettings.setBlockChangesForPlaySelectionToolPasteMode(blocksChange); + ArrayList fluidChanges = new ArrayList<>(); + int anchorX = selection.getAnchorX(); + int anchorY = selection.getAnchorY(); + int anchorZ = selection.getAnchorZ(); + selection.forEachFluid( + (x, y, z, fluidId, fluidLevel) -> fluidChanges.add( + new PrototypePlayerBuilderToolSettings.FluidChange(x - anchorX, y - anchorY, z - anchorZ, fluidId, fluidLevel) + ) + ); + PrototypePlayerBuilderToolSettings.FluidChange[] fluidChangesArray = fluidChanges.toArray( + PrototypePlayerBuilderToolSettings.FluidChange[]::new + ); + prototypeSettings.setFluidChangesForPlaySelectionToolPasteMode(fluidChangesArray); + ArrayList entityChanges = new ArrayList<>(); + int selectionX = selection.getX(); + int selectionY = selection.getY(); + int selectionZ = selection.getZ(); + selection.forEachEntity( + holder -> { + TransformComponent transform = holder.getComponent(TransformComponent.getComponentType()); + if (transform != null && transform.getPosition() != null) { + Vector3d pos = transform.getPosition(); + entityChanges.add( + new PrototypePlayerBuilderToolSettings.EntityChange( + pos.getX() + selectionX, pos.getY() + selectionY, pos.getZ() + selectionZ, holder.clone() + ) + ); + } + } + ); + prototypeSettings.setEntityChangesForPlaySelectionToolPasteMode(entityChanges.toArray(PrototypePlayerBuilderToolSettings.EntityChange[]::new)); + FluidChange[] packetFluids = new FluidChange[fluidChangesArray.length]; + + for (int i = 0; i < fluidChangesArray.length; i++) { + PrototypePlayerBuilderToolSettings.FluidChange fc = fluidChangesArray[i]; + packetFluids[i] = new FluidChange(fc.x(), fc.y(), fc.z(), fc.fluidId(), fc.fluidLevel()); + } + + playerRef.getPacketHandler().write(new BuilderToolSelectionToolReplyWithClipboard(blocksChange, packetFluids)); + } } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolStackArea packet. Player ref is invalid!"); + ); + } + } + + private void handleBuilderToolSelectionTransform( + @Nonnull BuilderToolSelectionTransform packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + boolean keepEmptyBlocks = true; + BuilderTool builderTool = BuilderTool.getActiveBuilderTool(playerComponent); + if (builderTool != null && builderTool.getId().equals("Selection")) { + BuilderTool.ArgData args = builderTool.getItemArgData(playerComponent.getInventory().getItemInHand()); + if (args != null && args.tool() != null) { + keepEmptyBlocks = (Boolean)args.tool().getOrDefault("KeepEmptyBlocks", true); + } + } + + boolean finalKeepEmptyBlocks = keepEmptyBlocks; + Quaterniond rotation = new Quaterniond(packet.rotation.x, packet.rotation.y, packet.rotation.z, packet.rotation.w); + Vector3i translationOffset = new Vector3i(packet.translationOffset.x, packet.translationOffset.y, packet.translationOffset.z); + Vector3i initialSelectionMin = new Vector3i(packet.initialSelectionMin.x, packet.initialSelectionMin.y, packet.initialSelectionMin.z); + Vector3i initialSelectionMax = new Vector3i(packet.initialSelectionMax.x, packet.initialSelectionMax.y, packet.initialSelectionMax.z); + Vector3f rotationOrigin = new Vector3f(packet.initialRotationOrigin.x, packet.initialRotationOrigin.y, packet.initialRotationOrigin.z); + PrototypePlayerBuilderToolSettings prototypeSettings = ToolOperation.getOrCreatePrototypeSettings(playerRef.getUuid()); + BuilderToolsPlugin.addToQueue( + playerComponent, + playerRef, + (r, s, componentAccessor) -> { + int blockCount = s.getSelection().getSelectionVolume(); + boolean large = blockCount > 20000; + if (large) { + playerComponent.sendMessage(Message.translation("server.builderTools.selection.large.warning")); + } + + if (prototypeSettings.getBlockChangesForPlaySelectionToolPasteMode() == null) { + s.select(initialSelectionMin, initialSelectionMax, "server.builderTools.selectReasons.selectionTranslatePacket", componentAccessor); + List> lastTransformRefs = prototypeSettings.getLastTransformEntityRefs(); + HashSet> skipSet = lastTransformRefs != null ? new HashSet<>(lastTransformRefs) : null; + if (packet.cutOriginal) { + s.copyOrCut( + r, + initialSelectionMin.x, + initialSelectionMin.y, + initialSelectionMin.z, + initialSelectionMax.x, + initialSelectionMax.y, + initialSelectionMax.z, + 154, + null, + skipSet, + store + ); + } else { + s.copyOrCut( + r, + initialSelectionMin.x, + initialSelectionMin.y, + initialSelectionMin.z, + initialSelectionMax.x, + initialSelectionMax.y, + initialSelectionMax.z, + 152, + store + ); + } + + BlockSelection selection = s.getSelection(); + BlockChange[] blocksChange = selection.toPacket().blocksChange; + prototypeSettings.setBlockChangesForPlaySelectionToolPasteMode(blocksChange); + ArrayList fluidChanges = new ArrayList<>(); + int anchorX = selection.getAnchorX(); + int anchorY = selection.getAnchorY(); + int anchorZ = selection.getAnchorZ(); + selection.forEachFluid( + (x, y, z, fluidId, fluidLevel) -> fluidChanges.add( + new PrototypePlayerBuilderToolSettings.FluidChange(x - anchorX, y - anchorY, z - anchorZ, fluidId, fluidLevel) + ) + ); + prototypeSettings.setFluidChangesForPlaySelectionToolPasteMode(fluidChanges.toArray(PrototypePlayerBuilderToolSettings.FluidChange[]::new)); + ArrayList entityChanges = new ArrayList<>(); + int selectionX = selection.getX(); + int selectionY = selection.getY(); + int selectionZ = selection.getZ(); + selection.forEachEntity( + holder -> { + TransformComponent transform = holder.getComponent(TransformComponent.getComponentType()); + if (transform != null && transform.getPosition() != null) { + Vector3d pos = transform.getPosition(); + entityChanges.add( + new PrototypePlayerBuilderToolSettings.EntityChange( + pos.getX() + selectionX, pos.getY() + selectionY, pos.getZ() + selectionZ, holder.clone() + ) + ); + } + } + ); + prototypeSettings.setEntityChangesForPlaySelectionToolPasteMode(entityChanges.toArray(PrototypePlayerBuilderToolSettings.EntityChange[]::new)); + prototypeSettings.setBlockChangeOffsetOrigin(new Vector3i(selection.getX(), selection.getY(), selection.getZ())); + } + + Vector3i blockChangeOffsetOrigin = prototypeSettings.getBlockChangeOffsetOrigin(); + if (packet.initialPastePointForClipboardPaste != null) { + blockChangeOffsetOrigin = new Vector3i( + packet.initialPastePointForClipboardPaste.x, packet.initialPastePointForClipboardPaste.y, packet.initialPastePointForClipboardPaste.z + ); + } + + if (blockChangeOffsetOrigin == null) { + playerComponent.sendMessage(Message.translation("server.builderTools.selection.noBlockChangeOffsetOrigin")); + } else { + s.transformThenPasteClipboard( + prototypeSettings.getBlockChangesForPlaySelectionToolPasteMode(), + prototypeSettings.getFluidChangesForPlaySelectionToolPasteMode(), + prototypeSettings.getEntityChangesForPlaySelectionToolPasteMode(), + rotation, + translationOffset, + rotationOrigin, + blockChangeOffsetOrigin, + finalKeepEmptyBlocks, + prototypeSettings, + componentAccessor + ); + s.select(initialSelectionMin, initialSelectionMax, "server.builderTools.selectReasons.selectionTranslatePacket", componentAccessor); + s.transformSelectionPoints(rotation, translationOffset, rotationOrigin); + if (large) { + playerComponent.sendMessage(Message.translation("server.builderTools.selection.large.complete")); + } + + if (packet.isExitingTransformMode) { + prototypeSettings.setInSelectionTransformationMode(false); + } + } + } + ); + } + } + + public void handleBuilderToolExtrudeAction( + @Nonnull BuilderToolExtrudeAction packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + BuilderTool builderTool = BuilderTool.getActiveBuilderTool(playerComponent); + if (builderTool != null && builderTool.getId().equals("Extrude")) { + ItemStack activeItemStack = playerComponent.getInventory().getItemInHand(); + BuilderTool.ArgData args = builderTool.getItemArgData(activeItemStack); + int extrudeDepth = (Integer)args.tool().get("ExtrudeDepth"); + int extrudeRadius = (Integer)args.tool().get("ExtrudeRadius"); + int blockId = ((BlockPattern)args.tool().get("ExtrudeMaterial")).firstBlock(); + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + BuilderToolsPlugin.addToQueue( + playerComponent, + playerRef, + (r, s, componentAccessor) -> s.extendFace( + packet.x, + packet.y, + packet.z, + packet.xNormal, + packet.yNormal, + packet.zNormal, + extrudeDepth, + extrudeRadius, + blockId, + null, + null, + componentAccessor + ) + ); + } + } + } + + public void handleBuilderToolStackArea( + @Nonnull BuilderToolStackArea packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + 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); + } + ); } } @@ -601,328 +606,292 @@ public class BuilderToolsPacketHandler implements SubPacketHandler { return new Vector3i(position.x, position.y, position.z); } - public void handle(@Nonnull BuilderToolRotateClipboard 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, "hytale.editor.selection.clipboard")) { - Axis axis = packet.axis == com.hypixel.hytale.protocol.packets.buildertools.Axis.X - ? Axis.X - : (packet.axis == com.hypixel.hytale.protocol.packets.buildertools.Axis.Y ? Axis.Y : Axis.Z); - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.rotate(r, axis, packet.angle, componentAccessor)); - } - } - ); - } else { - throw new RuntimeException("Unable to process BuilderToolPasteClipboard packet. Player ref is invalid!"); + public void handleBuilderToolRotateClipboard( + @Nonnull BuilderToolRotateClipboard packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + Axis axis = packet.axis == com.hypixel.hytale.protocol.packets.buildertools.Axis.X + ? Axis.X + : (packet.axis == com.hypixel.hytale.protocol.packets.buildertools.Axis.Y ? Axis.Y : Axis.Z); + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.rotate(r, axis, packet.angle, componentAccessor)); } } - public void handle(@Nonnull BuilderToolPasteClipboard 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, "hytale.editor.selection.clipboard")) { - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - BuilderToolsPlugin.addToQueue( - playerComponent, playerRef, (r, s, componentAccessor) -> s.paste(r, packet.x, packet.y, packet.z, componentAccessor) - ); - } - } - ); - } else { - throw new RuntimeException("Unable to process BuilderToolPasteClipboard packet. Player ref is invalid!"); + public void handleBuilderToolPasteClipboard( + @Nonnull BuilderToolPasteClipboard packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.paste(r, packet.x, packet.y, packet.z, componentAccessor)); } } - public void handle(@Nonnull BuilderToolLineAction 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, "hytale.editor.brush.use")) { - BuilderTool builderTool = BuilderTool.getActiveBuilderTool(playerComponent); - if (builderTool != null && builderTool.getId().equals("Line")) { - BuilderTool.ArgData args = builderTool.getItemArgData(playerComponent.getInventory().getItemInHand()); - BrushData.Values brushData = args.brush(); - int lineWidth = (Integer)args.tool().get("bLineWidth"); - int lineHeight = (Integer)args.tool().get("cLineHeight"); - BrushShape lineShape = BrushShape.valueOf((String)args.tool().get("dLineShape")); - BrushOrigin lineOrigin = BrushOrigin.valueOf((String)args.tool().get("eLineOrigin")); - int lineWallThickness = (Integer)args.tool().get("fLineWallThickness"); - int lineSpacing = (Integer)args.tool().get("gLineSpacing"); - int lineDensity = (Integer)args.tool().get("hLineDensity"); - BlockPattern lineMaterial = (BlockPattern)args.tool().get("aLineMaterial"); - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - BuilderToolsPlugin.addToQueue( - playerComponent, - playerRef, - (r, s, componentAccessor) -> s.editLine( - packet.xStart, - packet.yStart, - packet.zStart, - packet.xEnd, - packet.yEnd, - packet.zEnd, - lineMaterial, - lineWidth, - lineHeight, - lineWallThickness, - lineShape, - lineOrigin, - lineSpacing, - lineDensity, - ToolOperation.combineMasks(brushData, s.getGlobalMask()), - componentAccessor - ) - ); - } - } - } - ); - } else { - throw new RuntimeException("Unable to process BuilderToolLineAction packet. Player ref is invalid!"); - } - } - - public void handle(@Nonnull BuilderToolOnUseInteraction 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, "hytale.editor.brush.use")) { + public void handleBuilderToolLineAction( + @Nonnull BuilderToolLineAction packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + BuilderTool builderTool = BuilderTool.getActiveBuilderTool(playerComponent); + if (builderTool != null && builderTool.getId().equals("Line")) { + BuilderTool.ArgData args = builderTool.getItemArgData(playerComponent.getInventory().getItemInHand()); + BrushData.Values brushData = args.brush(); + Map tool = args.tool(); + if (tool != null) { + int lineWidth = (Integer)tool.get("bLineWidth"); + int lineHeight = (Integer)tool.get("cLineHeight"); + BrushShape lineShape = BrushShape.valueOf((String)tool.get("dLineShape")); + BrushOrigin lineOrigin = BrushOrigin.valueOf((String)tool.get("eLineOrigin")); + int lineWallThickness = (Integer)tool.get("fLineWallThickness"); + int lineSpacing = (Integer)tool.get("gLineSpacing"); + int lineDensity = (Integer)tool.get("hLineDensity"); + BlockPattern lineMaterial = (BlockPattern)tool.get("aLineMaterial"); LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.edit(ref, packet, componentAccessor)); + BuilderToolsPlugin.addToQueue( + playerComponent, + playerRef, + (r, s, componentAccessor) -> s.editLine( + packet.xStart, + packet.yStart, + packet.zStart, + packet.xEnd, + packet.yEnd, + packet.zEnd, + lineMaterial, + lineWidth, + lineHeight, + lineWallThickness, + lineShape, + lineOrigin, + lineSpacing, + lineDensity, + ToolOperation.combineMasks(brushData, s.getGlobalMask()), + componentAccessor + ) + ); } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolOnUseInteraction packet. Player ref is invalid!"); + } } } - public void handle(@Nonnull BuilderToolSetEntityTransform 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()); - - assert playerComponent != null; - - if (hasPermission(playerComponent)) { - Ref entityReference = world.getEntityStore().getRefFromNetworkId(packet.entityId); - if (entityReference != null) { - TransformComponent transformComponent = store.getComponent(entityReference, TransformComponent.getComponentType()); - - assert transformComponent != null; - - HeadRotation headRotation = store.getComponent(entityReference, HeadRotation.getComponentType()); - ModelTransform modelTransform = packet.modelTransform; - if (modelTransform != null) { - boolean hasPosition = modelTransform.position != null; - boolean hasLookOrientation = modelTransform.lookOrientation != null; - boolean hasBodyOrientation = modelTransform.bodyOrientation != null; - if (hasPosition) { - transformComponent.getPosition().assign(modelTransform.position.x, modelTransform.position.y, modelTransform.position.z); - } - - if (hasLookOrientation && headRotation != null) { - headRotation.getRotation() - .assign(modelTransform.lookOrientation.pitch, modelTransform.lookOrientation.yaw, modelTransform.lookOrientation.roll); - } - - if (hasBodyOrientation) { - transformComponent.getRotation() - .assign(modelTransform.bodyOrientation.pitch, modelTransform.bodyOrientation.yaw, modelTransform.bodyOrientation.roll); - } - - if (hasPosition || hasLookOrientation || hasBodyOrientation) { - transformComponent.markChunkDirty(store); - } - } - } - } - } - ); - } else { - throw new RuntimeException("Unable to process BuilderToolSetEntityTransform packet. Player ref is invalid!"); + public void handleBuilderToolOnUseInteraction( + @Nonnull BuilderToolOnUseInteraction packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> s.edit(ref, packet, componentAccessor)); } } - public void handle(@Nonnull PrefabUnselectPrefab 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)) { - LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); - PrefabEditSessionManager prefabEditSessionManager = BuilderToolsPlugin.get().getPrefabEditSessionManager(); - PrefabEditSession prefabEditSession = prefabEditSessionManager.getPrefabEditSession(playerRef.getUuid()); - if (prefabEditSession == null) { - playerComponent.sendMessage(Message.translation("server.commands.editprefab.notInEditSession")); - } else { - if (prefabEditSession.clearSelectedPrefab(ref, store)) { - playerComponent.sendMessage(Message.translation("server.commands.editprefab.unselected")); - } else { - playerComponent.sendMessage(Message.translation("server.commands.editprefab.noPrefabSelected")); - } + public void handleBuilderToolSetEntityTransform( + @Nonnull BuilderToolSetEntityTransform packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Ref targetRef = world.getEntityStore().getRefFromNetworkId(packet.entityId); + if (targetRef != null && targetRef.isValid()) { + TransformComponent transformComponent = store.getComponent(targetRef, TransformComponent.getComponentType()); + if (transformComponent != null) { + HeadRotation headRotation = store.getComponent(targetRef, HeadRotation.getComponentType()); + ModelTransform modelTransform = packet.modelTransform; + if (modelTransform != null) { + boolean hasPosition = modelTransform.position != null; + boolean hasLookOrientation = modelTransform.lookOrientation != null; + boolean hasBodyOrientation = modelTransform.bodyOrientation != null; + if (hasPosition) { + transformComponent.getPosition().assign(modelTransform.position.x, modelTransform.position.y, modelTransform.position.z); + } + + if (hasLookOrientation && headRotation != null) { + headRotation.getRotation() + .assign(modelTransform.lookOrientation.pitch, modelTransform.lookOrientation.yaw, modelTransform.lookOrientation.roll); + } + + if (hasBodyOrientation) { + transformComponent.getRotation() + .assign(modelTransform.bodyOrientation.pitch, modelTransform.bodyOrientation.yaw, modelTransform.bodyOrientation.roll); + } + + if (hasPosition || hasLookOrientation || hasBodyOrientation) { + transformComponent.markChunkDirty(store); } } - }); - } else { - throw new RuntimeException("Unable to process PrefabUnselectPrefab packet. Player ref is invalid!"); + } } } - public void handle(@Nonnull BuilderToolSetEntityScale 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()); - if (propComponent != null) { - EntityScaleComponent scaleComponent = store.getComponent(entityReference, EntityScaleComponent.getComponentType()); - if (scaleComponent == null) { - scaleComponent = new EntityScaleComponent(packet.scale); - store.addComponent(entityReference, EntityScaleComponent.getComponentType(), scaleComponent); - } else { - scaleComponent.setScale(packet.scale); - } - } - } + public void handlePrefabUnselectPrefab( + @Nonnull PrefabUnselectPrefab packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + LOGGER.at(Level.INFO).log("%s: %s", this.packetHandler.getIdentifier(), packet); + PrefabEditSessionManager prefabEditSessionManager = BuilderToolsPlugin.get().getPrefabEditSessionManager(); + PrefabEditSession prefabEditSession = prefabEditSessionManager.getPrefabEditSession(playerRef.getUuid()); + if (prefabEditSession == null) { + playerComponent.sendMessage(Message.translation("server.commands.editprefab.notInEditSession")); + } else { + if (prefabEditSession.clearSelectedPrefab(ref, store)) { + playerComponent.sendMessage(Message.translation("server.commands.editprefab.unselected")); + } else { + playerComponent.sendMessage(Message.translation("server.commands.editprefab.noPrefabSelected")); } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolSetEntityScale packet. Player ref is invalid!"); + } } } - public void handle(@Nonnull BuilderToolSetEntityPickupEnabled 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()); - if (propComponent != null) { - if (packet.enabled) { - store.ensureComponent(entityReference, Interactable.getComponentType()); - if (store.getComponent(entityReference, PreventPickup.getComponentType()) != null) { - store.removeComponent(entityReference, PreventPickup.getComponentType()); - } - - Interactions interactionsComponent = store.getComponent(entityReference, Interactions.getComponentType()); - if (interactionsComponent == null) { - interactionsComponent = new Interactions(); - store.addComponent(entityReference, Interactions.getComponentType(), interactionsComponent); - } - - interactionsComponent.setInteractionId(InteractionType.Use, "*PickupItem"); - interactionsComponent.setInteractionHint("server.interactionHints.pickup"); - } else { - if (store.getComponent(entityReference, Interactable.getComponentType()) != null) { - store.removeComponent(entityReference, Interactable.getComponentType()); - } - - if (store.getComponent(entityReference, Interactions.getComponentType()) != null) { - store.removeComponent(entityReference, Interactions.getComponentType()); - } - - store.ensureComponent(entityReference, PreventPickup.getComponentType()); - } - } - } + public void handleBuilderToolSetEntityScale( + @Nonnull BuilderToolSetEntityScale packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Ref targetRef = world.getEntityStore().getRefFromNetworkId(packet.entityId); + if (targetRef != null && targetRef.isValid()) { + PropComponent propComponent = store.getComponent(targetRef, PropComponent.getComponentType()); + if (propComponent != null) { + EntityScaleComponent scaleComponent = store.getComponent(targetRef, EntityScaleComponent.getComponentType()); + if (scaleComponent == null) { + scaleComponent = new EntityScaleComponent(packet.scale); + store.addComponent(targetRef, EntityScaleComponent.getComponentType(), scaleComponent); + } else { + scaleComponent.setScale(packet.scale); } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolSetEntityPickupEnabled packet. Player ref is invalid!"); + } } } - public void handle(@Nonnull BuilderToolSetEntityLight 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) { - if (packet.light == null) { - store.removeComponent(entityReference, DynamicLight.getComponentType()); - store.removeComponent(entityReference, PersistentDynamicLight.getComponentType()); - } else { - ColorLight colorLight = new ColorLight(packet.light.radius, packet.light.red, packet.light.green, packet.light.blue); - store.putComponent(entityReference, DynamicLight.getComponentType(), new DynamicLight(colorLight)); - store.putComponent(entityReference, PersistentDynamicLight.getComponentType(), new PersistentDynamicLight(colorLight)); - } + public void handleBuilderToolSetEntityPickupEnabled( + @Nonnull BuilderToolSetEntityPickupEnabled packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Ref targetRef = world.getEntityStore().getRefFromNetworkId(packet.entityId); + if (targetRef != null && targetRef.isValid()) { + PropComponent propComponent = store.getComponent(targetRef, PropComponent.getComponentType()); + if (propComponent != null) { + if (packet.enabled) { + store.ensureComponent(targetRef, Interactable.getComponentType()); + if (store.getComponent(targetRef, PreventPickup.getComponentType()) != null) { + store.removeComponent(targetRef, PreventPickup.getComponentType()); } + + Interactions interactionsComponent = store.getComponent(targetRef, Interactions.getComponentType()); + if (interactionsComponent == null) { + interactionsComponent = new Interactions(); + store.addComponent(targetRef, Interactions.getComponentType(), interactionsComponent); + } + + interactionsComponent.setInteractionId(InteractionType.Use, "*PickupItem"); + interactionsComponent.setInteractionHint("server.interactionHints.pickup"); + } else { + if (store.getComponent(targetRef, Interactable.getComponentType()) != null) { + store.removeComponent(targetRef, Interactable.getComponentType()); + } + + if (store.getComponent(targetRef, Interactions.getComponentType()) != null) { + store.removeComponent(targetRef, Interactions.getComponentType()); + } + + store.ensureComponent(targetRef, PreventPickup.getComponentType()); } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolSetEntityLight packet. Player ref is invalid!"); + } } } - public void handle(@Nonnull BuilderToolSetNPCDebug 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) { - 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); - } + public void handleBuilderToolSetEntityLight( + @Nonnull BuilderToolSetEntityLight packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Ref targetRef = world.getEntityStore().getRefFromNetworkId(packet.entityId); + if (targetRef != null && targetRef.isValid()) { + if (packet.light == null) { + store.removeComponent(targetRef, DynamicLight.getComponentType()); + store.removeComponent(targetRef, PersistentDynamicLight.getComponentType()); + } else { + ColorLight colorLight = new ColorLight(packet.light.radius, packet.light.red, packet.light.green, packet.light.blue); + store.putComponent(targetRef, DynamicLight.getComponentType(), new DynamicLight(colorLight)); + store.putComponent(targetRef, PersistentDynamicLight.getComponentType(), new PersistentDynamicLight(colorLight)); + } + } + } + + public void handleBuilderToolSetNPCDebug( + @Nonnull BuilderToolSetNPCDebug packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent != null) { + Ref targetRef = world.getEntityStore().getRefFromNetworkId(packet.entityId); + if (targetRef != null && targetRef.isValid()) { + NPCMarkerComponent npcMarkerComponent = store.getComponent(targetRef, NPCMarkerComponent.getComponentType()); + if (npcMarkerComponent != null) { + UUIDComponent uuidComponent = store.getComponent(targetRef, 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); } } - }); - } else { - throw new RuntimeException("Unable to process BuilderToolSetNPCDebug packet. Player ref is invalid!"); + } + } + } + + public void handleBuilderToolSetEntityCollision( + @Nonnull BuilderToolSetEntityCollision packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Ref targetRef = world.getEntityStore().getRefFromNetworkId(packet.entityId); + if (targetRef != null && targetRef.isValid()) { + PropComponent propComponent = store.getComponent(targetRef, PropComponent.getComponentType()); + NPCMarkerComponent npcMarkerComponent = store.getComponent(targetRef, NPCMarkerComponent.getComponentType()); + if (propComponent != null || npcMarkerComponent != null) { + if (packet.collisionType != null && !packet.collisionType.isEmpty()) { + HitboxCollisionConfig hitboxCollisionConfig = HitboxCollisionConfig.getAssetMap().getAsset(packet.collisionType); + if (hitboxCollisionConfig != null) { + store.putComponent(targetRef, HitboxCollision.getComponentType(), new HitboxCollision(hitboxCollisionConfig)); + } + } else { + store.removeComponent(targetRef, HitboxCollision.getComponentType()); + } + } } } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPlugin.java b/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPlugin.java index 68f6ac22..799406ac 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPlugin.java +++ b/src/com/hypixel/hytale/builtin/buildertools/BuilderToolsPlugin.java @@ -21,6 +21,7 @@ import com.hypixel.hytale.builtin.buildertools.commands.FlipCommand; import com.hypixel.hytale.builtin.buildertools.commands.GlobalMaskCommand; import com.hypixel.hytale.builtin.buildertools.commands.HollowCommand; import com.hypixel.hytale.builtin.buildertools.commands.HotbarSwitchCommand; +import com.hypixel.hytale.builtin.buildertools.commands.LayerCommand; import com.hypixel.hytale.builtin.buildertools.commands.MoveCommand; import com.hypixel.hytale.builtin.buildertools.commands.PasteCommand; import com.hypixel.hytale.builtin.buildertools.commands.Pos1Command; @@ -128,6 +129,7 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import com.hypixel.hytale.codec.validation.Validators; import com.hypixel.hytale.common.util.CompletableFutureUtil; import com.hypixel.hytale.common.util.PathUtil; +import com.hypixel.hytale.component.AddReason; import com.hypixel.hytale.component.Archetype; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.ComponentAccessor; @@ -146,13 +148,11 @@ import com.hypixel.hytale.math.block.BlockCubeUtil; import com.hypixel.hytale.math.block.BlockSphereUtil; import com.hypixel.hytale.math.block.BlockUtil; import com.hypixel.hytale.math.iterator.LineIterator; -import com.hypixel.hytale.math.matrix.Matrix4d; 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.math.vector.Vector3f; import com.hypixel.hytale.math.vector.Vector3i; -import com.hypixel.hytale.math.vector.Vector4d; import com.hypixel.hytale.math.vector.VectorBoxUtil; import com.hypixel.hytale.metrics.MetricProvider; import com.hypixel.hytale.metrics.MetricResults; @@ -194,13 +194,17 @@ import com.hypixel.hytale.server.core.command.system.CommandManager; import com.hypixel.hytale.server.core.command.system.CommandRegistry; import com.hypixel.hytale.server.core.command.system.CommandSender; import com.hypixel.hytale.server.core.entity.UUIDComponent; +import com.hypixel.hytale.server.core.entity.entities.BlockEntity; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.event.events.player.PlayerConnectEvent; import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.inventory.container.ItemContainer; import com.hypixel.hytale.server.core.io.ServerManager; +import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; +import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; +import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.RootInteraction; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.server.OpenCustomUIInteraction; @@ -222,7 +226,6 @@ import com.hypixel.hytale.server.core.prefab.selection.standard.FeedbackConsumer import com.hypixel.hytale.server.core.universe.PlayerRef; 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.accessor.BlockAccessor; import com.hypixel.hytale.server.core.universe.world.accessor.ChunkAccessor; import com.hypixel.hytale.server.core.universe.world.accessor.LocalCachedChunkAccessor; import com.hypixel.hytale.server.core.universe.world.accessor.OverridableChunkAccessor; @@ -245,6 +248,7 @@ import com.hypixel.hytale.server.core.util.TargetUtil; import com.hypixel.hytale.server.core.util.TempAssetIdUtil; import com.hypixel.hytale.sneakythrow.consumer.ThrowableConsumer; import com.hypixel.hytale.sneakythrow.consumer.ThrowableTriConsumer; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.Int2IntFunction; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntMaps; @@ -278,6 +282,7 @@ import java.util.function.Predicate; import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.joml.Quaterniond; public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, MetricProvider { public static final String EDITOR_BLOCK = "Editor_Block"; @@ -443,6 +448,7 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, commandRegistry.registerCommand(new SetToolHistorySizeCommand()); commandRegistry.registerCommand(new ObjImportCommand()); commandRegistry.registerCommand(new ImageImportCommand()); + commandRegistry.registerCommand(new LayerCommand()); OpenCustomUIInteraction.registerBlockCustomPage( this, PrefabSpawnerState.PrefabSpawnerSettingsPage.class, @@ -885,7 +891,8 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, EXTRUDE, UPDATE_SELECTION, WALLS, - HOLLOW; + HOLLOW, + LAYER; } public static class ActionEntry { @@ -908,15 +915,47 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, @Nonnull public BuilderToolsPlugin.ActionEntry restore(Ref ref, Player player, World world, ComponentAccessor componentAccessor) { List> collector = Collections.emptyList(); + List> recreatedEntityRefs = null; + if (this.action == BuilderToolsPlugin.Action.ROTATE) { + PrototypePlayerBuilderToolSettings protoSettings = ToolOperation.getOrCreatePrototypeSettings(player.getUuid()); + List> currentRefs = protoSettings.getLastTransformEntityRefs(); + if (currentRefs != null) { + Store entityStore = world.getEntityStore().getStore(); + + for (Ref currentRef : currentRefs) { + if (currentRef.isValid()) { + collector = (List>)(collector.isEmpty() ? new ObjectArrayList<>() : collector); + collector.add(new EntityRemoveSnapshot(currentRef)); + entityStore.removeEntity(currentRef, RemoveReason.UNLOAD); + } + } + + protoSettings.setLastTransformEntityRefs(null); + } + } for (SelectionSnapshot snapshot : this.snapshots) { - SelectionSnapshot nextSnapshot = snapshot.restore(ref, player, world, componentAccessor); - if (nextSnapshot != null) { - collector = (List>)(collector.isEmpty() ? new ObjectArrayList<>() : collector); - collector.add(nextSnapshot); + if (this.action != BuilderToolsPlugin.Action.ROTATE || !(snapshot instanceof EntityAddSnapshot)) { + SelectionSnapshot nextSnapshot = snapshot.restore(ref, player, world, componentAccessor); + if (nextSnapshot != null) { + collector = (List>)(collector.isEmpty() ? new ObjectArrayList<>() : collector); + collector.add(nextSnapshot); + if (nextSnapshot instanceof EntityAddSnapshot entityAddSnapshot) { + if (recreatedEntityRefs == null) { + recreatedEntityRefs = new ArrayList<>(); + } + + recreatedEntityRefs.add(entityAddSnapshot.getEntityRef()); + } + } } } + if (this.action == BuilderToolsPlugin.Action.ROTATE && recreatedEntityRefs != null && !recreatedEntityRefs.isEmpty()) { + PrototypePlayerBuilderToolSettings prototypeSettings = ToolOperation.getOrCreatePrototypeSettings(player.getUuid()); + prototypeSettings.setLastTransformEntityRefs(recreatedEntityRefs); + } + return new BuilderToolsPlugin.ActionEntry(this.action, collector); } } @@ -1921,88 +1960,94 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, this.pushHistory(BuilderToolsPlugin.Action.EXTRUDE, new BlockSelectionSnapshot(before)); BlockSelection after = new BlockSelection(totalBlocks, 0); after.copyPropertiesFrom(before); - this.extendFaceFindBlocks( - accessor, BlockType.getAssetMap(), before, after, x + normalX, y + normalY, z + normalZ, normalX, normalY, normalZ, extrudeDepth, blockId, min, max - ); - Vector3i offset = new Vector3i(0, 0, 0); - - for (int i = 0; i < extrudeDepth; i++) { - offset.x = normalX * i; - offset.y = normalY * i; - offset.z = normalZ * i; - after.placeNoReturn("Set", this.player, BuilderToolsPlugin.FEEDBACK_CONSUMER, world, offset, null, componentAccessor); + if (x >= min.getX() && x <= max.getX()) { + if (y >= min.getY() && y <= max.getY()) { + if (z >= min.getZ() && z <= max.getZ()) { + int testBlock = accessor.getBlock(x - normalX, y - normalY, z - normalZ); + BlockType testBlockType = BlockType.getAssetMap().getAsset(testBlock); + if (testBlockType != null && (testBlockType.getDrawType() == DrawType.Cube || testBlockType.getDrawType() == DrawType.CubeWithModel)) { + int xMod = Math.abs(normalX) == 1 ? 0 : 1; + int yMod = Math.abs(normalY) == 1 ? 0 : 1; + int zMod = Math.abs(normalZ) == 1 ? 0 : 1; + Vector3i surfaceMin = new Vector3i(x - radiusAllowed * xMod, y - radiusAllowed * yMod, z - radiusAllowed * zMod); + Vector3i surfaceMax = new Vector3i(x + radiusAllowed * xMod, y + radiusAllowed * yMod, z + radiusAllowed * zMod); + this.extendFaceFindBlocks(accessor, before, after, normalX, normalY, normalZ, extrudeDepth, blockId, min, max, surfaceMin, surfaceMax); + after.placeNoReturn("Set", this.player, BuilderToolsPlugin.FEEDBACK_CONSUMER, world, componentAccessor); + BuilderToolsPlugin.invalidateWorldMapForSelection(after, world); + long end = System.nanoTime(); + long diff = end - start; + BuilderToolsPlugin.get() + .getLogger() + .at(Level.FINE) + .log("Took: %dns (%dms) to execute set of %d blocks", diff, TimeUnit.NANOSECONDS.toMillis(diff), after.getBlockCount()); + this.sendUpdate(); + this.sendArea(); + } + } + } } - - BuilderToolsPlugin.invalidateWorldMapForSelection(after, world); - long end = System.nanoTime(); - long diff = end - start; - BuilderToolsPlugin.get() - .getLogger() - .at(Level.FINE) - .log("Took: %dns (%dms) to execute set of %d blocks", diff, TimeUnit.NANOSECONDS.toMillis(diff), after.getBlockCount()); - this.sendUpdate(); - this.sendArea(); } private void extendFaceFindBlocks( - @Nonnull ChunkAccessor accessor, - @Nonnull BlockTypeAssetMap assetMap, + @Nonnull LocalCachedChunkAccessor accessor, @Nonnull BlockSelection before, @Nonnull BlockSelection after, - int x, - int y, - int z, int normalX, int normalY, int normalZ, int extrudeDepth, int blockId, @Nonnull Vector3i min, - @Nonnull Vector3i max + @Nonnull Vector3i max, + @Nonnull Vector3i surfaceMin, + @Nonnull Vector3i surfaceMax ) { - if (x >= min.getX() && x <= max.getX()) { - if (y >= min.getY() && y <= max.getY()) { - if (z >= min.getZ() && z <= max.getZ()) { - int block = accessor.getBlock(x, y, z); - int testBlock = accessor.getBlock(x - normalX, y - normalY, z - normalZ); - BlockType testBlockType = assetMap.getAsset(testBlock); - if (testBlockType != null && (testBlockType.getDrawType() == DrawType.Cube || testBlockType.getDrawType() == DrawType.CubeWithModel)) { - if (!before.hasBlockAtWorldPos(x, y, z)) { - BlockAccessor blocks = accessor.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(x, z)); - if (blocks != null) { - before.addBlockAtWorldPos( - x, - y, - z, - block, - blocks.getRotationIndex(x, y, z), - blocks.getFiller(x, y, z), - blocks.getSupportValue(x, y, z), - blocks.getBlockComponentHolder(x, y, z) - ); - after.addBlockAtWorldPos(x, y, z, blockId, 0, 0, 0); + int xMin = surfaceMin.getX(); + int yMin = surfaceMin.getY(); + int zMin = surfaceMin.getZ(); + int xMax = surfaceMax.getX(); + int yMax = surfaceMax.getY(); + int zMax = surfaceMax.getZ(); - for (Vector3i side : Vector3i.BLOCK_SIDES) { - if ((normalX == 0 || side.getX() == 0) && (normalY == 0 || side.getY() == 0) && (normalZ == 0 || side.getZ() == 0)) { - this.extendFaceFindBlocks( - accessor, - assetMap, - before, - after, - x + side.getX(), - y + side.getY(), - z + side.getZ(), - normalX, - normalY, - normalZ, - extrudeDepth, - blockId, - min, - max - ); - } - } - } + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { + WorldChunk chunk = accessor.getChunk(ChunkUtil.indexChunkFromBlock(x, z)); + + for (int y = yMax; y >= yMin; y--) { + int currentBlock = chunk.getBlock(x, y, z); + int currentFluid = chunk.getFluidId(x, y, z); + if (currentBlock > 0) { + int xRes = x + normalX; + int yRes = y + normalY; + int zRes = z + normalZ; + currentBlock = chunk.getBlock(xRes, yRes, zRes); + before.addBlockAtWorldPos( + xRes, + yRes, + zRes, + currentBlock, + chunk.getRotationIndex(xRes, yRes, zRes), + chunk.getFiller(xRes, yRes, zRes), + chunk.getSupportValue(xRes, yRes, zRes), + chunk.getBlockComponentHolder(xRes, yRes, zRes) + ); + after.addBlockAtWorldPos(xRes, yRes, zRes, blockId, 0, 0, 0); + + for (int i = 0; i < extrudeDepth; i++) { + int extrudedBlockX = xRes + normalX * i; + int extrudedBlockY = yRes + normalY * i; + int extrudedBlockZ = zRes + normalZ * i; + before.addBlockAtWorldPos( + extrudedBlockX, + extrudedBlockY, + extrudedBlockZ, + currentBlock, + chunk.getRotationIndex(extrudedBlockX, extrudedBlockY, extrudedBlockZ), + chunk.getFiller(extrudedBlockX, extrudedBlockY, extrudedBlockZ), + chunk.getSupportValue(extrudedBlockX, extrudedBlockY, extrudedBlockZ), + chunk.getBlockComponentHolder(extrudedBlockX, extrudedBlockY, extrudedBlockZ) + ); + after.addBlockAtWorldPos(extrudedBlockX, extrudedBlockY, extrudedBlockZ, blockId, 0, 0, 0); } } } @@ -2161,7 +2206,7 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, int settings, @Nonnull ComponentAccessor componentAccessor ) throws PrefabCopyException { - return this.copyOrCut(ref, xMin, yMin, zMin, xMax, yMax, zMax, settings, null, componentAccessor); + return this.copyOrCut(ref, xMin, yMin, zMin, xMax, yMax, zMax, settings, null, null, componentAccessor); } public int copyOrCut( @@ -2175,6 +2220,22 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, int settings, @Nullable Vector3i playerAnchor, @Nonnull ComponentAccessor componentAccessor + ) throws PrefabCopyException { + return this.copyOrCut(ref, xMin, yMin, zMin, xMax, yMax, zMax, settings, playerAnchor, null, componentAccessor); + } + + public int copyOrCut( + @Nonnull Ref ref, + int xMin, + int yMin, + int zMin, + int xMax, + int yMax, + int zMax, + int settings, + @Nullable Vector3i playerAnchor, + @Nullable Set> skipEntityRemoveSnapshotFor, + @Nonnull ComponentAccessor componentAccessor ) throws PrefabCopyException { World world = componentAccessor.getExternalData().getWorld(); long start = System.nanoTime(); @@ -2312,8 +2373,11 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, Holder holder = store.copyEntity(e); this.selection.addEntityFromWorld(holder); if (cut) { - snapshots.add(new EntityRemoveSnapshot(e)); - entitiesToRemove.add(e); + boolean shouldSkip = skipEntityRemoveSnapshotFor != null && skipEntityRemoveSnapshotFor.contains(e); + if (!shouldSkip) { + snapshots.add(new EntityRemoveSnapshot(e)); + entitiesToRemove.add(e); + } } }); if (cut && entitiesToRemove != null) { @@ -2429,36 +2493,48 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, return size; } - public static RotationTuple transformRotation(RotationTuple prevRot, Matrix4d transformationMatrix) { + public static RotationTuple transformRotation(RotationTuple prevRot, Quaterniond rotation) { Vector3f forwardVec = new Vector3f(1.0F, 0.0F, 0.0F); Vector3f upVec = new Vector3f(0.0F, 1.0F, 0.0F); forwardVec = Rotation.rotate(forwardVec, prevRot.yaw(), prevRot.pitch(), prevRot.roll()); upVec = Rotation.rotate(upVec, prevRot.yaw(), prevRot.pitch(), prevRot.roll()); - Vector3f newForward = transformationMatrix.multiplyDirection(forwardVec.toVector3d()).toVector3f(); - Vector3f newUp = transformationMatrix.multiplyDirection(upVec.toVector3d()).toVector3f(); + org.joml.Vector3d fwd = rotation.transform(new org.joml.Vector3d(forwardVec.x, forwardVec.y, forwardVec.z)); + org.joml.Vector3d up = rotation.transform(new org.joml.Vector3d(upVec.x, upVec.y, upVec.z)); + Vector3f newForward = new Vector3f((float)fwd.x, (float)fwd.y, (float)fwd.z); + Vector3f newUp = new Vector3f((float)up.x, (float)up.y, (float)up.z); float bestScore = Float.MIN_VALUE; RotationTuple bestRot = prevRot; - for (RotationTuple rotation : RotationTuple.VALUES) { - Vector3f rotForward = Rotation.rotate(new Vector3f(1.0F, 0.0F, 0.0F), rotation.yaw(), rotation.pitch(), rotation.roll()); - Vector3f rotUp = Rotation.rotate(new Vector3f(0.0F, 1.0F, 0.0F), rotation.yaw(), rotation.pitch(), rotation.roll()); + for (RotationTuple rot : RotationTuple.VALUES) { + Vector3f rotForward = Rotation.rotate(new Vector3f(1.0F, 0.0F, 0.0F), rot.yaw(), rot.pitch(), rot.roll()); + Vector3f rotUp = Rotation.rotate(new Vector3f(0.0F, 1.0F, 0.0F), rot.yaw(), rot.pitch(), rot.roll()); float score = rotForward.dot(newForward) + rotUp.dot(newUp); if (score > bestScore) { bestScore = score; - bestRot = rotation; + bestRot = rot; } } return bestRot; } + private void transformEntityRotation(Vector3f rotation, Quaterniond deltaQuat) { + Quaterniond originalQuat = new Quaterniond().rotationYXZ(rotation.y, rotation.x, rotation.z); + Quaterniond resultQuat = deltaQuat.mul(originalQuat, new Quaterniond()); + org.joml.Vector3d eulerAngles = resultQuat.getEulerAnglesYXZ(new org.joml.Vector3d()); + rotation.assign((float)eulerAngles.x, (float)eulerAngles.y, (float)eulerAngles.z); + } + public void transformThenPasteClipboard( @Nonnull BlockChange[] blockChanges, @Nullable PrototypePlayerBuilderToolSettings.FluidChange[] fluidChanges, - @Nonnull Matrix4d transformationMatrix, + @Nullable PrototypePlayerBuilderToolSettings.EntityChange[] entityChanges, + @Nonnull Quaterniond rotation, + @Nonnull Vector3i translationOffset, @Nonnull Vector3f rotationOrigin, @Nonnull Vector3i initialPastePoint, boolean keepEmptyBlocks, + @Nonnull PrototypePlayerBuilderToolSettings prototypeSettings, ComponentAccessor componentAccessor ) { World world = componentAccessor.getExternalData().getWorld(); @@ -2473,35 +2549,33 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, } } - Vector4d translationEndResult = new Vector4d(0.0, 0.0, 0.0, 1.0); - transformationMatrix.multiply(translationEndResult); - translationEndResult.x = translationEndResult.x + rotationOrigin.x; - translationEndResult.y = translationEndResult.y + rotationOrigin.y; - translationEndResult.z = translationEndResult.z + rotationOrigin.z; + int centerX = translationOffset.x + (int)rotationOrigin.x; + int centerY = translationOffset.y + (int)rotationOrigin.y; + int centerZ = translationOffset.z + (int)rotationOrigin.z; BlockSelection before = new BlockSelection(); - before.setPosition((int)translationEndResult.x, (int)translationEndResult.y, (int)translationEndResult.z); + before.setPosition(centerX, centerY, centerZ); BlockSelection after = new BlockSelection(before); - LocalCachedChunkAccessor accessor = LocalCachedChunkAccessor.atWorldCoords(world, (int)translationEndResult.x, (int)translationEndResult.z, 50); + LocalCachedChunkAccessor accessor = LocalCachedChunkAccessor.atWorldCoords(world, centerX, centerZ, 50); int minX = Integer.MAX_VALUE; int minY = Integer.MAX_VALUE; int minZ = Integer.MAX_VALUE; int maxX = Integer.MIN_VALUE; int maxY = Integer.MIN_VALUE; int maxZ = Integer.MIN_VALUE; - Vector4d mutable4d = new Vector4d(0.0, 0.0, 0.0, 1.0); + org.joml.Vector3d mutableVec = new org.joml.Vector3d(); for (BlockChange blockChangex : blockChanges) { - mutable4d.assign( + mutableVec.set( blockChangex.x - rotationOrigin.x + initialPastePoint.x + 0.5, blockChangex.y - rotationOrigin.y + initialPastePoint.y + 0.5 + yOffsetOutOfGround, - blockChangex.z - rotationOrigin.z + initialPastePoint.z + 0.5, - 1.0 + blockChangex.z - rotationOrigin.z + initialPastePoint.z + 0.5 ); - transformationMatrix.multiply(mutable4d); + rotation.transform(mutableVec); + mutableVec.add(translationOffset.x, translationOffset.y, translationOffset.z); Vector3i rotatedLocation = new Vector3i( - (int)Math.floor(mutable4d.x + 0.1 + rotationOrigin.x - 0.5), - (int)Math.floor(mutable4d.y + 0.1 + rotationOrigin.y - 0.5), - (int)Math.floor(mutable4d.z + 0.1 + rotationOrigin.z - 0.5) + (int)Math.floor(mutableVec.x + 0.1 + rotationOrigin.x - 0.5), + (int)Math.floor(mutableVec.y + 0.1 + rotationOrigin.y - 0.5), + (int)Math.floor(mutableVec.z + 0.1 + rotationOrigin.z - 0.5) ); minX = Math.min(minX, rotatedLocation.x); minY = Math.min(minY, rotatedLocation.y); @@ -2513,12 +2587,12 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, Holder holder = currentChunk.getBlockComponentHolder(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z); int blockIdInRotatedLocation = currentChunk.getBlock(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z); int filler = currentChunk.getFiller(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z); - int rotation = currentChunk.getRotationIndex(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z); - before.addBlockAtWorldPos(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z, blockIdInRotatedLocation, rotation, filler, 0, holder); + int blockRotation = currentChunk.getRotationIndex(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z); + before.addBlockAtWorldPos(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z, blockIdInRotatedLocation, blockRotation, filler, 0, holder); int originalFluidId = currentChunk.getFluidId(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z); byte originalFluidLevel = currentChunk.getFluidLevel(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z); before.addFluidAtWorldPos(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z, originalFluidId, originalFluidLevel); - int newRotation = transformRotation(RotationTuple.get(blockChangex.rotation), transformationMatrix).index(); + int newRotation = transformRotation(RotationTuple.get(blockChangex.rotation), rotation).index(); int blockIdToPlace = blockChangex.block; if (blockChangex.block == 0 && keepEmptyBlocks) { blockIdToPlace = editorBlockPrefabAir; @@ -2553,27 +2627,92 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, int finalYOffsetOutOfGround = yOffsetOutOfGround; if (fluidChanges != null) { for (PrototypePlayerBuilderToolSettings.FluidChange fluidChange : fluidChanges) { - mutable4d.assign( + mutableVec.set( fluidChange.x() - rotationOrigin.x + initialPastePoint.x + 0.5, fluidChange.y() - rotationOrigin.y + initialPastePoint.y + 0.5 + finalYOffsetOutOfGround, - fluidChange.z() - rotationOrigin.z + initialPastePoint.z + 0.5, - 1.0 + fluidChange.z() - rotationOrigin.z + initialPastePoint.z + 0.5 ); - transformationMatrix.multiply(mutable4d); + rotation.transform(mutableVec); + mutableVec.add(translationOffset.x, translationOffset.y, translationOffset.z); Vector3i rotatedLocationx = new Vector3i( - (int)Math.floor(mutable4d.x + 0.1 + rotationOrigin.x - 0.5), - (int)Math.floor(mutable4d.y + 0.1 + rotationOrigin.y - 0.5), - (int)Math.floor(mutable4d.z + 0.1 + rotationOrigin.z - 0.5) + (int)Math.floor(mutableVec.x + 0.1 + rotationOrigin.x - 0.5), + (int)Math.floor(mutableVec.y + 0.1 + rotationOrigin.y - 0.5), + (int)Math.floor(mutableVec.z + 0.1 + rotationOrigin.z - 0.5) ); after.addFluidAtWorldPos(rotatedLocationx.x, rotatedLocationx.y, rotatedLocationx.z, fluidChange.fluidId(), fluidChange.fluidLevel()); } } + List> previousEntityRefs = prototypeSettings.getLastTransformEntityRefs(); + List previousEntitySnapshots = new ArrayList<>(); + if (previousEntityRefs != null) { + Store entityStore = world.getEntityStore().getStore(); + + for (Ref ref : previousEntityRefs) { + if (ref.isValid()) { + previousEntitySnapshots.add(new EntityRemoveSnapshot(ref)); + entityStore.removeEntity(ref, RemoveReason.UNLOAD); + } + } + } + + List> addedEntityRefs = new ArrayList<>(); + if (entityChanges != null && entityChanges.length > 0) { + org.joml.Vector3d mutableEntityPos = new org.joml.Vector3d(); + + for (PrototypePlayerBuilderToolSettings.EntityChange entityChange : entityChanges) { + boolean isBlockEntity = entityChange.entityHolder().getComponent(BlockEntity.getComponentType()) != null; + double blockCenterOffset = isBlockEntity ? 0.5 : 0.0; + mutableEntityPos.set( + entityChange.x() - rotationOrigin.x, + entityChange.y() + blockCenterOffset - rotationOrigin.y + finalYOffsetOutOfGround, + entityChange.z() - rotationOrigin.z + ); + rotation.transform(mutableEntityPos); + mutableEntityPos.add(translationOffset.x, translationOffset.y, translationOffset.z); + double newX = mutableEntityPos.x + rotationOrigin.x; + double newY = mutableEntityPos.y + rotationOrigin.y - blockCenterOffset; + double newZ = mutableEntityPos.z + rotationOrigin.z; + Holder clonedHolder = entityChange.entityHolder().clone(); + TransformComponent transformComponent = clonedHolder.getComponent(TransformComponent.getComponentType()); + if (transformComponent != null && transformComponent.getPosition() != null) { + transformComponent.getPosition().assign(newX, newY, newZ); + Vector3f entityRotation = transformComponent.getRotation(); + if (entityRotation != null) { + this.transformEntityRotation(entityRotation, rotation); + } + } + + HeadRotation headRotation = clonedHolder.getComponent(HeadRotation.getComponentType()); + if (headRotation != null && headRotation.getRotation() != null) { + this.transformEntityRotation(headRotation.getRotation(), rotation); + } + + clonedHolder.putComponent(UUIDComponent.getComponentType(), new UUIDComponent(UUID.randomUUID())); + clonedHolder.removeComponent(EntityTrackerSystems.Visible.getComponentType()); + clonedHolder.removeComponent(NetworkId.getComponentType()); + Ref entityRef = componentAccessor.addEntity(clonedHolder, AddReason.LOAD); + addedEntityRefs.add(entityRef); + } + } + if (minX != Integer.MAX_VALUE) { before.setSelectionArea(new Vector3i(minX, minY, minZ), new Vector3i(maxX, maxY, maxZ)); } - this.pushHistory(BuilderToolsPlugin.Action.ROTATE, new BlockSelectionSnapshot(before)); + prototypeSettings.setLastTransformEntityRefs(new ArrayList<>(addedEntityRefs)); + List> snapshots = new ObjectArrayList<>(addedEntityRefs.size() + previousEntitySnapshots.size() + 1); + + for (Ref entityRef : addedEntityRefs) { + snapshots.add(new EntityAddSnapshot(entityRef)); + } + + for (EntityRemoveSnapshot snapshot : previousEntitySnapshots) { + snapshots.add(snapshot); + } + + snapshots.add(new BlockSelectionSnapshot(before)); + this.pushHistory(BuilderToolsPlugin.Action.ROTATE, snapshots); after.placeNoReturn("Transform 1/1", this.player, BuilderToolsPlugin.FEEDBACK_CONSUMER, world, componentAccessor); BuilderToolsPlugin.invalidateWorldMapForSelection(after, world); long end = System.nanoTime(); @@ -2586,27 +2725,135 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, this.sendArea(); } - public void transformSelectionPoints(@Nonnull Matrix4d transformationMatrix, @Nonnull Vector3f rotationOrigin) { - Vector3i newMin = this.transformBlockLocation(this.selection.getSelectionMin(), transformationMatrix, rotationOrigin); - Vector3i newMax = this.transformBlockLocation(this.selection.getSelectionMax(), transformationMatrix, rotationOrigin); + public void transformSelectionPoints(@Nonnull Quaterniond rotation, @Nonnull Vector3i translationOffset, @Nonnull Vector3f rotationOrigin) { + Vector3i newMin = this.transformBlockLocation(this.selection.getSelectionMin(), rotation, translationOffset, rotationOrigin); + Vector3i newMax = this.transformBlockLocation(this.selection.getSelectionMax(), rotation, translationOffset, rotationOrigin); this.selection.setSelectionArea(Vector3i.min(newMin, newMax), Vector3i.max(newMin, newMax)); this.sendUpdate(); this.sendArea(); } @Nonnull - public Vector3i transformBlockLocation(@Nonnull Vector3i blockLocation, @Nonnull Matrix4d transformationMatrix, @Nonnull Vector3f rotationOrigin) { - Vector4d relativeOffset = new Vector4d( - blockLocation.x - rotationOrigin.x + 0.5, blockLocation.y - rotationOrigin.y + 0.5, blockLocation.z - rotationOrigin.z + 0.5, 1.0 + public Vector3i transformBlockLocation( + @Nonnull Vector3i blockLocation, @Nonnull Quaterniond rotation, @Nonnull Vector3i translationOffset, @Nonnull Vector3f rotationOrigin + ) { + org.joml.Vector3d relative = new org.joml.Vector3d( + blockLocation.x - rotationOrigin.x + 0.5, blockLocation.y - rotationOrigin.y + 0.5, blockLocation.z - rotationOrigin.z + 0.5 ); - transformationMatrix.multiply(relativeOffset); + rotation.transform(relative); + relative.add(translationOffset.x, translationOffset.y, translationOffset.z); return new Vector3i( - (int)Math.floor(relativeOffset.x + rotationOrigin.x - 0.5 + 0.1), - (int)Math.floor(relativeOffset.y + rotationOrigin.y - 0.5 + 0.1), - (int)Math.floor(relativeOffset.z + rotationOrigin.z - 0.5 + 0.1) + (int)Math.floor(relative.x + rotationOrigin.x - 0.5 + 0.1), + (int)Math.floor(relative.y + rotationOrigin.y - 0.5 + 0.1), + (int)Math.floor(relative.z + rotationOrigin.z - 0.5 + 0.1) ); } + public void layer( + int x, + int y, + int z, + @Nonnull List> layers, + int depth, + Vector3i direction, + WorldChunk chunk, + BlockSelection before, + BlockSelection after + ) { + int xModifier = direction.x == 1 ? -1 : (direction.x == -1 ? 1 : 0); + int yModifier = direction.y == 1 ? -1 : (direction.y == -1 ? 1 : 0); + int zModifier = direction.z == 1 ? -1 : (direction.z == -1 ? 1 : 0); + + for (int i = 0; i < depth; i++) { + if (chunk.getBlock(x + i * xModifier + xModifier, y + i * yModifier + yModifier, z + i * zModifier + zModifier) <= 0 + && this.attemptSetLayer(x, y, z, i, layers, chunk, before, after)) { + return; + } + } + } + + public void layer(@Nonnull List> layers, Vector3i direction, ComponentAccessor componentAccessor) { + if (this.selection == null) { + this.sendFeedback(Message.translation("server.builderTools.noSelection"), componentAccessor); + } else if (!this.selection.hasSelectionBounds()) { + this.sendFeedback(Message.translation("server.builderTools.noSelectionBounds"), componentAccessor); + } else { + int maxDepth = 0; + + for (Pair layer : layers) { + maxDepth += layer.left(); + } + + long start = System.nanoTime(); + Vector3i min = Vector3i.min(this.selection.getSelectionMin(), this.selection.getSelectionMax()); + Vector3i max = Vector3i.max(this.selection.getSelectionMin(), this.selection.getSelectionMax()); + int xMin = min.getX(); + int xMax = max.getX(); + int yMin = min.getY(); + int yMax = max.getY(); + int zMin = min.getZ(); + int zMax = max.getZ(); + BlockSelection before = new BlockSelection(); + int width = xMax - xMin; + int depth = zMax - zMin; + int halfWidth = width / 2; + int halfDepth = depth / 2; + before.setPosition(xMin + halfWidth, yMin, zMin + halfDepth); + before.setSelectionArea(min, max); + this.pushHistory(BuilderToolsPlugin.Action.LAYER, new BlockSelectionSnapshot(before)); + BlockSelection after = new BlockSelection(before); + World world = componentAccessor.getExternalData().getWorld(); + LocalCachedChunkAccessor accessor = LocalCachedChunkAccessor.atWorldCoords(world, xMin + halfWidth, zMin + halfDepth, Math.max(width, depth)); + + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { + WorldChunk chunk = accessor.getChunk(ChunkUtil.indexChunkFromBlock(x, z)); + + for (int y = yMax; y >= yMin; y--) { + int currentBlock = chunk.getBlock(x, y, z); + int currentFluid = chunk.getFluidId(x, y, z); + if (currentBlock > 0 && (this.globalMask == null || !this.globalMask.isExcluded(accessor, x, y, z, min, max, currentBlock, currentFluid))) { + this.layer(x, y, z, layers, maxDepth, direction, chunk, before, after); + } + } + } + } + + after.placeNoReturn("Finished layer", this.player, BuilderToolsPlugin.FEEDBACK_CONSUMER, world, componentAccessor); + BuilderToolsPlugin.invalidateWorldMapForSelection(after, world); + long end = System.nanoTime(); + long diff = end - start; + BuilderToolsPlugin.get().getLogger().at(Level.FINE).log("Took: %dns (%dms) to execute layer", diff, TimeUnit.NANOSECONDS.toMillis(diff)); + this.sendUpdate(); + this.sendArea(); + } + } + + private boolean attemptSetLayer( + int x, int y, int z, int depth, List> layers, WorldChunk chunk, BlockSelection before, BlockSelection after + ) { + int currentDepth = 0; + + for (Pair layer : layers) { + currentDepth += layer.left(); + if (depth < currentDepth) { + int currentBlock = chunk.getBlock(x, y, z); + int currentBlockFiller = chunk.getFiller(x, y, z); + Holder holder = chunk.getBlockComponentHolder(x, y, z); + int rotation = chunk.getRotationIndex(x, y, z); + int supportValue = chunk.getSupportValue(x, y, z); + BlockPattern pattern = BlockPattern.parse(layer.right()); + int materialId = pattern.nextBlock(this.random); + Holder newHolder = BuilderToolsPlugin.createBlockComponent(chunk, x, y, z, materialId, currentBlock, holder, true); + before.addBlockAtWorldPos(x, y, z, currentBlock, rotation, currentBlockFiller, supportValue, holder); + after.addBlockAtWorldPos(x, y, z, materialId, rotation, 0, 0, newHolder); + return true; + } + } + + return false; + } + public int paste(@Nonnull Ref ref, int x, int y, int z, @Nonnull ComponentAccessor componentAccessor) { return this.paste(ref, x, y, z, false, componentAccessor); } @@ -3716,10 +3963,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 +4356,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 +4383,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 +4424,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 +4435,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 +4533,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/PrototypePlayerBuilderToolSettings.java b/src/com/hypixel/hytale/builtin/buildertools/PrototypePlayerBuilderToolSettings.java index 7f22a4de..a1d9f7f2 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/PrototypePlayerBuilderToolSettings.java +++ b/src/com/hypixel/hytale/builtin/buildertools/PrototypePlayerBuilderToolSettings.java @@ -4,6 +4,7 @@ import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfig; import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfigCommandExecutor; import com.hypixel.hytale.builtin.buildertools.tooloperations.ToolOperation; import com.hypixel.hytale.component.ComponentAccessor; +import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.math.block.BlockUtil; import com.hypixel.hytale.math.vector.Vector3i; @@ -14,6 +15,7 @@ import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import java.util.LinkedList; +import java.util.List; import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -38,9 +40,13 @@ public class PrototypePlayerBuilderToolSettings { @Nullable private PrototypePlayerBuilderToolSettings.FluidChange[] fluidChangesForPlaySelectionToolPasteMode = null; @Nullable + private PrototypePlayerBuilderToolSettings.EntityChange[] entityChangesForPlaySelectionToolPasteMode = null; + @Nullable private Vector3i lastBrushPosition = null; @Nullable private Vector3i blockChangeOffsetOrigin = null; + @Nullable + private List> lastTransformEntityRefs = null; public PrototypePlayerBuilderToolSettings(UUID player) { this.player = player; @@ -60,6 +66,7 @@ public class PrototypePlayerBuilderToolSettings { if (!this.isInSelectionTransformationMode) { this.blockChangesForPlaySelectionToolPasteMode = null; this.fluidChangesForPlaySelectionToolPasteMode = null; + this.entityChangesForPlaySelectionToolPasteMode = null; this.blockChangeOffsetOrigin = null; } } @@ -98,6 +105,15 @@ public class PrototypePlayerBuilderToolSettings { return this.fluidChangesForPlaySelectionToolPasteMode; } + public void setEntityChangesForPlaySelectionToolPasteMode(@Nullable PrototypePlayerBuilderToolSettings.EntityChange[] entityChanges) { + this.entityChangesForPlaySelectionToolPasteMode = entityChanges; + } + + @Nullable + public PrototypePlayerBuilderToolSettings.EntityChange[] getEntityChangesForPlaySelectionToolPasteMode() { + return this.entityChangesForPlaySelectionToolPasteMode; + } + public void setBlockChangeOffsetOrigin(@Nullable Vector3i blockChangeOffsetOrigin) { this.blockChangeOffsetOrigin = blockChangeOffsetOrigin; } @@ -107,6 +123,19 @@ public class PrototypePlayerBuilderToolSettings { return this.blockChangeOffsetOrigin; } + public void setLastTransformEntityRefs(@Nullable List> refs) { + this.lastTransformEntityRefs = refs; + } + + @Nullable + public List> getLastTransformEntityRefs() { + return this.lastTransformEntityRefs; + } + + public void clearLastTransformEntityRefs() { + this.lastTransformEntityRefs = null; + } + @Nonnull public LongOpenHashSet addIgnoredPaintOperation() { LongOpenHashSet longs = new LongOpenHashSet(); @@ -202,6 +231,9 @@ public class PrototypePlayerBuilderToolSettings { } } + public record EntityChange(double x, double y, double z, Holder entityHolder) { + } + public record FluidChange(int x, int y, int z, int fluidId, byte fluidLevel) { } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/commands/ContractSelectionCommand.java b/src/com/hypixel/hytale/builtin/buildertools/commands/ContractSelectionCommand.java index 406959fd..77dcdf36 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/commands/ContractSelectionCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/commands/ContractSelectionCommand.java @@ -25,7 +25,9 @@ public class ContractSelectionCommand extends AbstractPlayerCommand { @Nonnull private final RequiredArg distanceArg = this.withRequiredArg("distance", "server.commands.contract.arg.distance.desc", ArgTypes.INTEGER); @Nonnull - private final OptionalArg> axisArg = this.withListOptionalArg("axis", "command.contract.arg.axis.desc", ArgTypes.forEnum("Axis", Axis.class)); + private final OptionalArg> axisArg = this.withListOptionalArg( + "axis", "server.commands.contract.arg.axis.desc", ArgTypes.forEnum("Axis", Axis.class) + ); public ContractSelectionCommand() { super("contractSelection", "server.commands.contract.desc"); diff --git a/src/com/hypixel/hytale/builtin/buildertools/commands/LayerCommand.java b/src/com/hypixel/hytale/builtin/buildertools/commands/LayerCommand.java new file mode 100644 index 00000000..55269d41 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/buildertools/commands/LayerCommand.java @@ -0,0 +1,78 @@ +package com.hypixel.hytale.builtin.buildertools.commands; + +import com.hypixel.hytale.builtin.buildertools.BuilderToolsPlugin; +import com.hypixel.hytale.builtin.buildertools.PrototypePlayerBuilderToolSettings; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.math.vector.Vector3i; +import com.hypixel.hytale.protocol.GameMode; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.command.system.CommandContext; +import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg; +import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; +import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand; +import com.hypixel.hytale.server.core.entity.entities.Player; +import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; +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.Pair; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; + +public class LayerCommand extends AbstractPlayerCommand { + private static Map directions = Map.of( + "up", Vector3i.UP, "down", Vector3i.DOWN, "north", Vector3i.NORTH, "south", Vector3i.SOUTH, "east", Vector3i.EAST, "west", Vector3i.WEST + ); + @Nonnull + private final RequiredArg layerDirectionArg = this.withRequiredArg("direction", "server.commands.layer.direction.desc", ArgTypes.STRING); + @Nonnull + private final RequiredArg>> layersArg = this.withListRequiredArg( + "layers", "server.commands.layer.layers.desc", ArgTypes.LAYER_ENTRY_TYPE + ); + + public LayerCommand() { + super("layer", "server.commands.layer.desc"); + this.setPermissionGroup(GameMode.Creative); + this.requirePermission("hytale.editor.selection.clipboard"); + } + + @Override + protected void execute( + @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; + + if (PrototypePlayerBuilderToolSettings.isOkayToDoCommandsOnSelection(ref, playerComponent, store)) { + String direction = this.layerDirectionArg.get(context).toLowerCase(); + List> layers = this.layersArg.get(context); + if (layers != null && direction != null) { + boolean directionValid = directions.containsKey(direction); + if (directionValid) { + BuilderToolsPlugin.addToQueue(playerComponent, playerRef, (r, s, componentAccessor) -> { + HeadRotation headRotationComponent = componentAccessor.getComponent(ref, HeadRotation.getComponentType()); + + assert headRotationComponent != null; + + Vector3i layerDirection = Vector3i.ZERO; + if (direction.equalsIgnoreCase("camera")) { + layerDirection = headRotationComponent.getAxisDirection(); + } else { + layerDirection = directions.get(direction); + } + + s.layer(layers, layerDirection, componentAccessor); + }); + } else { + context.sendMessage(Message.translation("server.commands.layer.directionInvalid").param("direction", direction)); + context.sendMessage(Message.translation("server.commands.help.useHelpToLearnMore").param("command", this.getFullyQualifiedName())); + } + } else { + context.sendMessage(Message.translation("server.commands.help.useHelpToLearnMore").param("command", this.getFullyQualifiedName())); + } + } + } +} 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/imageimport/ImageImportPage.java b/src/com/hypixel/hytale/builtin/buildertools/imageimport/ImageImportPage.java index 428a1c16..8c89424c 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/imageimport/ImageImportPage.java +++ b/src/com/hypixel/hytale/builtin/buildertools/imageimport/ImageImportPage.java @@ -14,6 +14,7 @@ import com.hypixel.hytale.protocol.packets.interface_.CustomPageLifetime; import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType; import com.hypixel.hytale.protocol.packets.interface_.Page; import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.pages.InteractiveCustomUIPage; import com.hypixel.hytale.server.core.prefab.selection.standard.BlockSelection; @@ -259,7 +260,9 @@ public class ImageImportPage extends InteractiveCustomUIPage pickupItemHolder = ItemComponent.generatePickedUpItem(targetRef, commandBuffer, ref, itemEntityPosition); + if (pickupItemHolder != null) { + commandBuffer.addEntity(pickupItemHolder, AddReason.SPAWN); + } + } else if (!remainder.equals(itemStack)) { + int quantity = itemStack.getQuantity() - remainder.getQuantity(); + itemComponent.setItemStack(remainder); + Holder pickupItemHolder = ItemComponent.generatePickedUpItem(targetRef, commandBuffer, ref, itemEntityPosition); + if (pickupItemHolder != null) { + commandBuffer.addEntity(pickupItemHolder, AddReason.SPAWN); + } - ItemContainer itemContainer = playerComponent.getInventory().getContainerForItemPickup(item, playerSettings); - ItemStackTransaction transaction = itemContainer.addItemStack(itemStack); - ItemStack remainder = transaction.getRemainder(); - if (ItemStack.isEmpty(remainder)) { - itemComponent.setRemovedByPlayerPickup(true); - commandBuffer.removeEntity(targetRef, RemoveReason.REMOVE); - playerComponent.notifyPickupItem(ref, itemStack, itemEntityPosition, commandBuffer); - Holder pickupItemHolder = ItemComponent.generatePickedUpItem(targetRef, commandBuffer, ref, itemEntityPosition); - commandBuffer.addEntity(pickupItemHolder, AddReason.SPAWN); - } else if (!remainder.equals(itemStack)) { - int quantity = itemStack.getQuantity() - remainder.getQuantity(); - itemComponent.setItemStack(remainder); - Holder pickupItemHolder = ItemComponent.generatePickedUpItem(targetRef, commandBuffer, ref, itemEntityPosition); - commandBuffer.addEntity(pickupItemHolder, AddReason.SPAWN); - if (quantity > 0) { - playerComponent.notifyPickupItem(ref, itemStack.withQuantity(quantity), itemEntityPosition, commandBuffer); + if (quantity > 0) { + playerComponent.notifyPickupItem(ref, itemStack.withQuantity(quantity), itemEntityPosition, commandBuffer); + } } } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/objimport/ObjImportPage.java b/src/com/hypixel/hytale/builtin/buildertools/objimport/ObjImportPage.java index 6fecf350..ff8026c0 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/objimport/ObjImportPage.java +++ b/src/com/hypixel/hytale/builtin/buildertools/objimport/ObjImportPage.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.builtin.buildertools.utils.PasteToolUtil; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.common.util.StringUtil; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; @@ -14,6 +15,7 @@ import com.hypixel.hytale.protocol.packets.interface_.CustomPageLifetime; import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType; import com.hypixel.hytale.protocol.packets.interface_.Page; import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.pages.InteractiveCustomUIPage; @@ -401,12 +403,14 @@ public class ObjImportPage extends InteractiveCustomUIPage ref, @Nonnull Store store) { if (this.objPath.isEmpty()) { this.setError("Please enter a path to an OBJ file"); + } else if (!this.objPath.toLowerCase().endsWith(".obj")) { + this.setError("File must be a .obj file"); } else { Path path = Paths.get(this.objPath); - if (!Files.exists(path)) { + if (!AssetModule.get().isWithinPackSubDir(path, "Server/Imports/Models")) { + this.setError("File must be within an asset pack's imports directory"); + } else if (!Files.exists(path)) { this.setError("File not found: " + this.objPath); - } else if (!this.objPath.toLowerCase().endsWith(".obj")) { - this.setError("File must be a .obj file"); } else { List blocks = this.parseBlockPattern(this.blockPattern); if (blocks == null) { @@ -577,8 +581,8 @@ public class ObjImportPage extends InteractiveCustomUIPage materials = MtlParser.parse(mtlPath); Path textureDir = mtlPath.getParent(); @@ -591,7 +595,11 @@ public class ObjImportPage extends InteractiveCustomUIPage { 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/PrefabEditCreateNewCommand.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditCreateNewCommand.java index 65dd783b..b653e58d 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditCreateNewCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditCreateNewCommand.java @@ -5,6 +5,7 @@ import com.hypixel.hytale.builtin.buildertools.prefabeditor.PrefabEditorCreation import com.hypixel.hytale.builtin.buildertools.prefabeditor.enums.PrefabRootDirectory; import com.hypixel.hytale.builtin.buildertools.prefabeditor.enums.WorldGenType; import com.hypixel.hytale.codec.validation.Validators; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.server.core.Message; @@ -72,11 +73,8 @@ public class PrefabEditCreateNewCommand extends AbstractAsyncPlayerCommand { prefabName = prefabName + ".prefab.json"; } - Path prefabPath = prefabBaseDirectory.resolve(prefabName); - if (prefabPath.toString().endsWith("/")) { - context.sendMessage(MESSAGE_COMMANDS_EDIT_PREFAB_NEW_ERRORS_NOT_A_FILE); - return CompletableFuture.completedFuture(null); - } else { + Path prefabPath = PathUtil.resolvePathWithinDir(prefabBaseDirectory, prefabName); + if (prefabPath != null && !prefabPath.toString().endsWith("/")) { PrefabEditorCreationSettings prefabEditorLoadCommandSettings = new PrefabEditorCreationSettings( this.prefabPathArg.get(context), List.of(prefabName), @@ -98,6 +96,9 @@ public class PrefabEditCreateNewCommand extends AbstractAsyncPlayerCommand { return BuilderToolsPlugin.get() .getPrefabEditSessionManager() .createEditSessionForNewPrefab(ref, playerComponent, prefabEditorLoadCommandSettings, store); + } else { + context.sendMessage(MESSAGE_COMMANDS_EDIT_PREFAB_NEW_ERRORS_NOT_A_FILE); + return CompletableFuture.completedFuture(null); } } } 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..853d8995 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveCommand.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/commands/PrefabEditSaveCommand.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.arguments.system.FlagArg; import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncPlayerCommand; @@ -39,12 +40,19 @@ 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(); - return PathUtil.isChildOf(prefabStore.getServerPrefabsPath(), path) - || PathUtil.isChildOf(prefabStore.getAssetPrefabsPath(), path) - || PathUtil.isChildOf(prefabStore.getWorldGenPrefabsPath(), path); + if (PathUtil.isChildOf(prefabStore.getServerPrefabsPath(), path)) { + return true; + } else if (PathUtil.isChildOf(prefabStore.getWorldGenPrefabsPath(), path)) { + return true; + } else { + AssetModule assetModule = AssetModule.get(); + return assetModule.isWithinPackSubDir(path, "Server/Prefabs") && !assetModule.isAssetPathImmutable(path); + } } public PrefabEditSaveCommand() { @@ -71,6 +79,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/PrefabEditorLoadSettingsPage.java b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/ui/PrefabEditorLoadSettingsPage.java index 176a8aae..194c6f36 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/ui/PrefabEditorLoadSettingsPage.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefabeditor/ui/PrefabEditorLoadSettingsPage.java @@ -627,7 +627,7 @@ public class PrefabEditorLoadSettingsPage 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 { this.buildFileList(commandBuilder, eventBuilder); this.sendUpdate(commandBuilder, eventBuilder, false); } else { - Path file; - if (isSearchResult) { - file = this.browser.resolveSecure(selectedPath); - } else { - file = this.browser.resolveFromCurrent(selectedPath); - } - + Path baseDir = isSearchResult ? this.browser.getRoot() : this.browser.getRoot().resolve(this.browser.getCurrentDir().toString()); + Path file = PathUtil.resolvePathWithinDir(baseDir, selectedPath); if (file != null && !Files.isDirectory(file)) { this.handlePrefabSelection(ref, store, file, selectedPath); } else { diff --git a/src/com/hypixel/hytale/builtin/buildertools/prefablist/PrefabSavePage.java b/src/com/hypixel/hytale/builtin/buildertools/prefablist/PrefabSavePage.java index ef1583fd..ab1267af 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/prefablist/PrefabSavePage.java +++ b/src/com/hypixel/hytale/builtin/buildertools/prefablist/PrefabSavePage.java @@ -43,6 +43,7 @@ public class PrefabSavePage 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/buildertools/scriptedbrushes/operations/sequential/LayerOperation.java b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/operations/sequential/LayerOperation.java index 192066cd..5ab44dcf 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/operations/sequential/LayerOperation.java +++ b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/operations/sequential/LayerOperation.java @@ -1,5 +1,6 @@ package com.hypixel.hytale.builtin.buildertools.scriptedbrushes.operations.sequential; +import com.hypixel.hytale.builtin.buildertools.BuilderToolsPlugin; import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfig; import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfigCommandExecutor; import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfigEditStore; @@ -9,13 +10,18 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; -import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +import com.hypixel.hytale.math.util.ChunkUtil; +import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.server.core.asset.type.buildertool.config.BuilderTool; import com.hypixel.hytale.server.core.codec.LayerEntryCodec; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.prefab.selection.mask.BlockPattern; +import com.hypixel.hytale.server.core.universe.PlayerRef; +import com.hypixel.hytale.server.core.universe.world.accessor.BlockAccessor; +import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import it.unimi.dsi.fastutil.Pair; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -51,58 +57,50 @@ public class LayerOperation extends SequenceBrushOperation { int z, ComponentAccessor componentAccessor ) { - int maxDepth = 0; + Player playerComponent = componentAccessor.getComponent(ref, Player.getComponentType()); - for (LayerEntryCodec entry : this.layerArgs) { - maxDepth += entry.getDepth(); - } + assert playerComponent != null; + PlayerRef playerRefComponent = componentAccessor.getComponent(ref, PlayerRef.getComponentType()); + + assert playerRefComponent != null; + + BuilderToolsPlugin.BuilderState builderState = BuilderToolsPlugin.getState(playerComponent, playerRefComponent); if (edit.getBlock(x, y, z) <= 0) { return true; } else { Map toolArgs = this.getToolArgs(ref, componentAccessor); + List> layers = new ArrayList<>(); + int maxDepth = 0; - for (int depth = 0; depth < maxDepth; depth++) { - if (edit.getBlock(x, y + depth + 1, z) <= 0) { - int depthTestingAt = 0; - - for (LayerEntryCodec entry : this.layerArgs) { - depthTestingAt += entry.getDepth(); - if (depth < depthTestingAt) { - if (entry.isSkip()) { - return true; - } - - int blockId = this.resolveBlockId(entry, toolArgs, brushConfig); - if (blockId >= 0) { - edit.setBlock(x, y, z, blockId); - } - - return true; - } - } + for (LayerEntryCodec layer : this.layerArgs) { + if (!layer.isSkip()) { + maxDepth += layer.getDepth(); + layers.add(Pair.of(layer.getDepth(), this.resolveBlockPattern(layer, toolArgs, brushConfig))); } } + BlockAccessor chunk = edit.getAccessor().getChunk(ChunkUtil.indexChunkFromBlock(x, z)); + builderState.layer(x, y, z, layers, maxDepth, Vector3i.DOWN, (WorldChunk)chunk, edit.getBefore(), edit.getAfter()); return true; } } - private int resolveBlockId(LayerEntryCodec entry, @Nullable Map toolArgs, BrushConfig brushConfig) { + private String resolveBlockPattern(LayerEntryCodec entry, @Nullable Map toolArgs, BrushConfig brushConfig) { if (entry.isUseToolArg()) { if (toolArgs != null && toolArgs.containsKey(entry.getMaterial())) { if (toolArgs.get(entry.getMaterial()) instanceof BlockPattern blockPattern) { - return blockPattern.nextBlock(brushConfig.getRandom()); + return blockPattern.toString(); } else { brushConfig.setErrorFlag("Layer: Tool arg '" + entry.getMaterial() + "' is not a Block type"); - return -1; + return ""; } } else { brushConfig.setErrorFlag("Layer: Tool arg '" + entry.getMaterial() + "' not found"); - return -1; + return ""; } } else { - return BlockType.getAssetMap().getIndex(entry.getMaterial()); + return entry.getMaterial(); } } diff --git a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/operations/sequential/ShapeOperation.java b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/operations/sequential/ShapeOperation.java index 4be9ed6e..96ee9ebf 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/operations/sequential/ShapeOperation.java +++ b/src/com/hypixel/hytale/builtin/buildertools/scriptedbrushes/operations/sequential/ShapeOperation.java @@ -20,7 +20,7 @@ public class ShapeOperation extends SequenceBrushOperation { .documentation("Changes the shape of the brush editing area") .build(); @Nonnull - public BrushShape brushShapeArg = BrushShape.Cube; + public BrushShape brushShapeArg = BrushShape.Sphere; public ShapeOperation() { super("Shape", "Changes the shape of the brush editing area", false); diff --git a/src/com/hypixel/hytale/builtin/buildertools/tooloperations/LayersOperation.java b/src/com/hypixel/hytale/builtin/buildertools/tooloperations/LayersOperation.java index 53bbd6f0..ad7e5153 100644 --- a/src/com/hypixel/hytale/builtin/buildertools/tooloperations/LayersOperation.java +++ b/src/com/hypixel/hytale/builtin/buildertools/tooloperations/LayersOperation.java @@ -2,13 +2,18 @@ package com.hypixel.hytale.builtin.buildertools.tooloperations; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolOnUseInteraction; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; -import com.hypixel.hytale.server.core.prefab.selection.mask.BlockPattern; +import com.hypixel.hytale.server.core.universe.world.accessor.BlockAccessor; +import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import it.unimi.dsi.fastutil.Pair; +import java.util.ArrayList; +import java.util.List; import javax.annotation.Nonnull; public class LayersOperation extends ToolOperation { @@ -18,17 +23,16 @@ public class LayersOperation extends ToolOperation { private final boolean enableLayerTwo; private final int layerThreeLength; private final boolean enableLayerThree; - private final BlockPattern layerOneBlockPattern; - private final BlockPattern layerTwoBlockPattern; - private final BlockPattern layerThreeBlockPattern; + private final String layerOneBlockPattern; + private final String layerTwoBlockPattern; + private final String layerThreeBlockPattern; private final int brushDensity; private final int maxDepthNecessary; private boolean failed; - private final int layerTwoDepthEnd; - private final int layerThreeDepthEnd; private final boolean skipLayerOne; private final boolean skipLayerTwo; private final boolean skipLayerThree; + private List> layers; public LayersOperation( @Nonnull Ref ref, @@ -72,17 +76,28 @@ public class LayersOperation extends ToolOperation { this.layerOneLength = (Integer)this.args.tool().get("bLayerOneLength"); this.layerTwoLength = (Integer)this.args.tool().get("eLayerTwoLength"); this.layerThreeLength = (Integer)this.args.tool().get("hLayerThreeLength"); - this.layerOneBlockPattern = (BlockPattern)this.args.tool().get("cLayerOneMaterial"); - this.layerTwoBlockPattern = (BlockPattern)this.args.tool().get("fLayerTwoMaterial"); - this.layerThreeBlockPattern = (BlockPattern)this.args.tool().get("iLayerThreeMaterial"); + this.layerOneBlockPattern = this.args.tool().get("cLayerOneMaterial").toString(); + this.layerTwoBlockPattern = this.args.tool().get("fLayerTwoMaterial").toString(); + this.layerThreeBlockPattern = this.args.tool().get("iLayerThreeMaterial").toString(); this.enableLayerTwo = (Boolean)this.args.tool().get("dEnableLayerTwo"); this.enableLayerThree = (Boolean)this.args.tool().get("gEnableLayerThree"); this.skipLayerOne = (Boolean)this.args.tool().getOrDefault("kSkipLayerOne", false); this.skipLayerTwo = (Boolean)this.args.tool().getOrDefault("lSkipLayerTwo", false); this.skipLayerThree = (Boolean)this.args.tool().getOrDefault("mSkipLayerThree", false); + this.layers = new ArrayList<>(); + if (!this.skipLayerOne) { + this.layers.add(Pair.of(this.layerOneLength, this.layerOneBlockPattern)); + } + + if (!this.skipLayerTwo && this.enableLayerTwo) { + this.layers.add(Pair.of(this.layerTwoLength, this.layerTwoBlockPattern)); + } + + if (!this.skipLayerThree && this.enableLayerThree) { + this.layers.add(Pair.of(this.layerThreeLength, this.layerThreeBlockPattern)); + } + this.maxDepthNecessary = this.layerOneLength + (this.enableLayerTwo ? this.layerTwoLength : 0) + (this.enableLayerThree ? this.layerThreeLength : 0); - this.layerTwoDepthEnd = this.layerOneLength + this.layerTwoLength; - this.layerThreeDepthEnd = this.layerTwoDepthEnd + this.layerThreeLength; if (this.enableLayerThree && !this.enableLayerTwo) { player.sendMessage(Message.translation("server.builderTools.layerOperation.layerTwoRequired")); this.failed = true; @@ -95,75 +110,13 @@ public class LayersOperation extends ToolOperation { return false; } else if (this.random.nextInt(100) > this.brushDensity) { return true; - } else { - int currentBlock = this.edit.getBlock(x, y, z); - if (currentBlock <= 0) { - return true; - } else { - if (this.depthDirection.x == 1) { - for (int i = 0; i < this.maxDepthNecessary; i++) { - if (this.edit.getBlock(x - i - 1, y, z) <= 0 && this.attemptSetBlock(x, y, z, i)) { - return true; - } - } - } else if (this.depthDirection.x == -1) { - for (int ix = 0; ix < this.maxDepthNecessary; ix++) { - if (this.edit.getBlock(x + ix + 1, y, z) <= 0 && this.attemptSetBlock(x, y, z, ix)) { - return true; - } - } - } else if (this.depthDirection.y == 1) { - for (int ixx = 0; ixx < this.maxDepthNecessary; ixx++) { - if (this.edit.getBlock(x, y - ixx - 1, z) <= 0 && this.attemptSetBlock(x, y, z, ixx)) { - return true; - } - } - } else if (this.depthDirection.y == -1) { - for (int ixxx = 0; ixxx < this.maxDepthNecessary; ixxx++) { - if (this.edit.getBlock(x, y + ixxx + 1, z) <= 0 && this.attemptSetBlock(x, y, z, ixxx)) { - return true; - } - } - } else if (this.depthDirection.z == 1) { - for (int ixxxx = 0; ixxxx < this.maxDepthNecessary; ixxxx++) { - if (this.edit.getBlock(x, y, z - ixxxx - 1) <= 0 && this.attemptSetBlock(x, y, z, ixxxx)) { - return true; - } - } - } else if (this.depthDirection.z == -1) { - for (int ixxxxx = 0; ixxxxx < this.maxDepthNecessary; ixxxxx++) { - if (this.edit.getBlock(x, y, z + ixxxxx + 1) <= 0 && this.attemptSetBlock(x, y, z, ixxxxx)) { - return true; - } - } - } - - return true; - } - } - } - - public boolean attemptSetBlock(int x, int y, int z, int depth) { - if (depth < this.layerOneLength) { - if (!this.skipLayerOne) { - this.edit.setBlock(x, y, z, this.layerOneBlockPattern.nextBlock(this.random)); - } - - return true; - } else if (this.enableLayerTwo && depth < this.layerTwoDepthEnd) { - if (!this.skipLayerTwo && !this.layerTwoBlockPattern.isEmpty()) { - this.edit.setBlock(x, y, z, this.layerTwoBlockPattern.nextBlock(this.random)); - } - - return true; - } else if (this.enableLayerThree && depth < this.layerThreeDepthEnd) { - if (!this.skipLayerThree && !this.layerThreeBlockPattern.isEmpty()) { - this.edit.setBlock(x, y, z, this.layerThreeBlockPattern.nextBlock(this.random)); - } - + } else if (this.edit.getBlock(x, y, z) <= 0) { return true; } else { - return false; + BlockAccessor chunk = this.edit.getAccessor().getChunk(ChunkUtil.indexChunkFromBlock(x, z)); + this.builderState + .layer(x, y, z, this.layers, this.maxDepthNecessary, this.depthDirection, (WorldChunk)chunk, this.edit.getBefore(), this.edit.getAfter()); + return true; } } } diff --git a/src/com/hypixel/hytale/builtin/commandmacro/EchoCommand.java b/src/com/hypixel/hytale/builtin/commandmacro/EchoCommand.java index 3703f082..e740212f 100644 --- a/src/com/hypixel/hytale/builtin/commandmacro/EchoCommand.java +++ b/src/com/hypixel/hytale/builtin/commandmacro/EchoCommand.java @@ -8,10 +8,11 @@ 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); + @Nonnull + 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/commandmacro/MacroCommandBase.java b/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandBase.java index ce5cb7a1..ec895e06 100644 --- a/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandBase.java +++ b/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandBase.java @@ -24,9 +24,15 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MacroCommandBase extends AbstractAsyncCommand { + @Nonnull public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull private static final Pattern regexBracketPattern = Pattern.compile("\\{(.*?)}"); + @Nonnull + private static final Pattern PATTERN = Pattern.compile("\\\\\\{"); + @Nonnull private final Map> arguments = new Object2ObjectOpenHashMap<>(); + @Nonnull private final List>> commandReplacements = new ObjectArrayList<>(); private final Map defaultValueStrings = new Object2ObjectOpenHashMap<>(); @@ -96,7 +102,7 @@ public class MacroCommandBase extends AbstractAsyncCommand { } } - command = command.replaceAll("\\\\\\{", "{"); + command = PATTERN.matcher(command).replaceAll("{"); commands[i] = command; this.commandReplacements.add(Pair.of(command, replacements)); } diff --git a/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandBuilder.java b/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandBuilder.java index affae38f..899e0736 100644 --- a/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandBuilder.java +++ b/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandBuilder.java @@ -12,6 +12,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MacroCommandBuilder implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( MacroCommandBuilder.class, MacroCommandBuilder::new, diff --git a/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandParameter.java b/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandParameter.java index ddd056d2..0e814bca 100644 --- a/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandParameter.java +++ b/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandParameter.java @@ -6,8 +6,10 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.codecs.EnumCodec; import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; import com.hypixel.hytale.server.core.command.system.arguments.types.ArgumentType; +import javax.annotation.Nonnull; public class MacroCommandParameter { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(MacroCommandParameter.class, MacroCommandParameter::new) .append(new KeyedCodec<>("Name", Codec.STRING, true), (macroParameter, name) -> macroParameter.name = name, macroParameter -> macroParameter.name) .add() diff --git a/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandPlugin.java b/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandPlugin.java index 0993f281..e8c6d6da 100644 --- a/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandPlugin.java +++ b/src/com/hypixel/hytale/builtin/commandmacro/MacroCommandPlugin.java @@ -13,6 +13,7 @@ import javax.annotation.Nonnull; public class MacroCommandPlugin extends JavaPlugin { private static MacroCommandPlugin instance; + @Nonnull private final Map macroCommandRegistrations = new Object2ObjectOpenHashMap<>(); public static MacroCommandPlugin get() { diff --git a/src/com/hypixel/hytale/builtin/commandmacro/WaitCommand.java b/src/com/hypixel/hytale/builtin/commandmacro/WaitCommand.java index 348fe1b4..0e71b7f8 100644 --- a/src/com/hypixel/hytale/builtin/commandmacro/WaitCommand.java +++ b/src/com/hypixel/hytale/builtin/commandmacro/WaitCommand.java @@ -14,10 +14,13 @@ import javax.annotation.Nonnull; public class WaitCommand extends AbstractAsyncCommand { private static final long MILLISECONDS_TO_SECONDS_MULTIPLIER = 1000L; + @Nonnull public static final Runnable EMPTY_RUNNABLE = () -> {}; + @Nonnull private final RequiredArg timeArg = this.withRequiredArg("time", "server.commands.wait.arg.time", ArgTypes.FLOAT) .addValidator(Validators.greaterThan(0.0F)) .addValidator(Validators.lessThan(1000.0F)); + @Nonnull private final FlagArg printArg = this.withFlagArg("print", "server.commands.wait.arg.print"); public WaitCommand() { diff --git a/src/com/hypixel/hytale/builtin/crafting/BenchRecipeRegistry.java b/src/com/hypixel/hytale/builtin/crafting/BenchRecipeRegistry.java index 86f5ead6..6f2cf69a 100644 --- a/src/com/hypixel/hytale/builtin/crafting/BenchRecipeRegistry.java +++ b/src/com/hypixel/hytale/builtin/crafting/BenchRecipeRegistry.java @@ -19,16 +19,22 @@ import javax.annotation.Nullable; public class BenchRecipeRegistry { private final String benchId; + @Nonnull private final Map> categoryMap = new Object2ObjectOpenHashMap<>(); + @Nonnull private final Map> itemToIncomingRecipe = new Object2ObjectOpenHashMap<>(); + @Nonnull private final Set uncategorizedRecipes = new ObjectOpenHashSet<>(); + @Nonnull private final Set allMaterialIds = new ObjectOpenHashSet<>(); + @Nonnull private final Set allMaterialResourceType = new ObjectOpenHashSet<>(); public BenchRecipeRegistry(String benchId) { this.benchId = benchId; } + @Nonnull public Iterable getIncomingRecipesForItem(@Nonnull String itemId) { Set recipes = this.itemToIncomingRecipe.get(itemId); return recipes == null ? Collections.emptySet() : recipes; @@ -88,7 +94,7 @@ public class BenchRecipeRegistry { this.extractMaterialFromRecipes(this.uncategorizedRecipes); } - private void extractMaterialFromRecipes(Set recipes) { + private void extractMaterialFromRecipes(@Nonnull Set recipes) { for (String recipeId : recipes) { CraftingRecipe recipe = CraftingRecipe.getAssetMap().getAsset(recipeId); if (recipe != null) { @@ -141,7 +147,7 @@ public class BenchRecipeRegistry { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o != null && this.getClass() == o.getClass()) { BenchRecipeRegistry that = (BenchRecipeRegistry)o; return Objects.equals(this.benchId, that.benchId) @@ -159,6 +165,7 @@ public class BenchRecipeRegistry { return Objects.hash(this.benchId, this.categoryMap, this.uncategorizedRecipes, this.allMaterialIds, this.allMaterialResourceType); } + @Nonnull @Override public String toString() { return "BenchRecipeRegistry{benchId='" diff --git a/src/com/hypixel/hytale/builtin/crafting/CraftingPlugin.java b/src/com/hypixel/hytale/builtin/crafting/CraftingPlugin.java index d7f1f144..e77b1bba 100644 --- a/src/com/hypixel/hytale/builtin/crafting/CraftingPlugin.java +++ b/src/com/hypixel/hytale/builtin/crafting/CraftingPlugin.java @@ -25,6 +25,7 @@ import com.hypixel.hytale.component.RemoveReason; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefSystem; +import com.hypixel.hytale.event.EventRegistry; import com.hypixel.hytale.protocol.BenchRequirement; import com.hypixel.hytale.protocol.BenchType; import com.hypixel.hytale.protocol.ItemResourceType; @@ -59,7 +60,9 @@ import javax.annotation.Nullable; public class CraftingPlugin extends JavaPlugin { private static CraftingPlugin instance; + @Nonnull private static final Map registries = new Object2ObjectOpenHashMap<>(); + @Nonnull private static final Map itemGeneratedRecipes = new Object2ObjectOpenHashMap<>(); private ComponentType craftingManagerComponentType; @@ -69,17 +72,17 @@ public class CraftingPlugin extends JavaPlugin { } @Nullable - public static Set getAvailableRecipesForCategory(String benchId, String benchCategoryId) { + public static Set getAvailableRecipesForCategory(@Nonnull String benchId, @Nonnull String benchCategoryId) { BenchRecipeRegistry benchRecipeRegistry = registries.get(benchId); return benchRecipeRegistry == null ? null : benchRecipeRegistry.getRecipesForCategory(benchCategoryId); } - public static boolean isValidCraftingMaterialForBench(BenchState benchState, ItemStack itemStack) { + public static boolean isValidCraftingMaterialForBench(@Nonnull BenchState benchState, @Nonnull ItemStack itemStack) { BenchRecipeRegistry benchRecipeRegistry = registries.get(benchState.getBench().getId()); return benchRecipeRegistry == null ? false : benchRecipeRegistry.isValidCraftingMaterial(itemStack); } - public static boolean isValidUpgradeMaterialForBench(BenchState benchState, ItemStack itemStack) { + public static boolean isValidUpgradeMaterialForBench(@Nonnull BenchState benchState, @Nonnull ItemStack itemStack) { BenchUpgradeRequirement nextLevelUpgradeMaterials = benchState.getNextLevelUpgradeMaterials(); if (nextLevelUpgradeMaterials == null) { return false; @@ -92,7 +95,7 @@ public class CraftingPlugin extends JavaPlugin { ItemResourceType[] resourceTypeId = itemStack.getItem().getResourceTypes(); if (resourceTypeId != null) { for (ItemResourceType resTypeId : resourceTypeId) { - if (resTypeId.id.equals(upgradeMaterial.getResourceTypeId())) { + if (resTypeId.id != null && resTypeId.id.equals(upgradeMaterial.getResourceTypeId())) { return true; } } @@ -118,10 +121,8 @@ public class CraftingPlugin extends JavaPlugin { ) ); ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); + EventRegistry eventRegistry = this.getEventRegistry(); this.craftingManagerComponentType = entityStoreRegistry.registerComponent(CraftingManager.class, CraftingManager::new); - entityStoreRegistry.registerSystem(new PlayerCraftingSystems.CraftingTickingSystem(this.craftingManagerComponentType)); - entityStoreRegistry.registerSystem(new PlayerCraftingSystems.CraftingHolderSystem(this.craftingManagerComponentType)); - entityStoreRegistry.registerSystem(new PlayerCraftingSystems.CraftingRefSystem(this.craftingManagerComponentType)); this.getCodecRegistry(Interaction.CODEC) .register("OpenBenchPage", OpenBenchPageInteraction.class, OpenBenchPageInteraction.CODEC) .register("OpenProcessingBench", OpenProcessingBenchInteraction.class, OpenProcessingBenchInteraction.CODEC); @@ -132,16 +133,21 @@ public class CraftingPlugin extends JavaPlugin { blockStateRegistry.registerBlockState(ProcessingBenchState.class, "processingBench", ProcessingBenchState.CODEC); blockStateRegistry.registerBlockState(BenchState.class, "crafting", BenchState.CODEC); Window.CLIENT_REQUESTABLE_WINDOW_TYPES.put(WindowType.PocketCrafting, FieldCraftingWindow::new); - this.getEventRegistry().register(LoadedAssetsEvent.class, CraftingRecipe.class, CraftingPlugin::onRecipeLoad); - this.getEventRegistry().register(RemovedAssetsEvent.class, CraftingRecipe.class, CraftingPlugin::onRecipeRemove); - this.getEventRegistry().register(LoadedAssetsEvent.class, Item.class, CraftingPlugin::onItemAssetLoad); - this.getEventRegistry().register(RemovedAssetsEvent.class, Item.class, CraftingPlugin::onItemAssetRemove); + eventRegistry.register(LoadedAssetsEvent.class, CraftingRecipe.class, CraftingPlugin::onRecipeLoad); + eventRegistry.register(RemovedAssetsEvent.class, CraftingRecipe.class, CraftingPlugin::onRecipeRemove); + eventRegistry.register(LoadedAssetsEvent.class, Item.class, CraftingPlugin::onItemAssetLoad); + eventRegistry.register(RemovedAssetsEvent.class, Item.class, CraftingPlugin::onItemAssetRemove); Interaction.CODEC.register("LearnRecipe", LearnRecipeInteraction.class, LearnRecipeInteraction.CODEC); CommandManager.get().registerSystemCommand(new RecipeCommand()); - entityStoreRegistry.registerSystem(new CraftingPlugin.PlayerAddedSystem()); + ComponentType playerComponentType = Player.getComponentType(); + ComponentType playerRefComponentType = PlayerRef.getComponentType(); + entityStoreRegistry.registerSystem(new PlayerCraftingSystems.CraftingTickingSystem(this.craftingManagerComponentType)); + entityStoreRegistry.registerSystem(new PlayerCraftingSystems.CraftingHolderSystem(playerComponentType, this.craftingManagerComponentType)); + entityStoreRegistry.registerSystem(new PlayerCraftingSystems.CraftingRefSystem(playerComponentType, this.craftingManagerComponentType)); + entityStoreRegistry.registerSystem(new CraftingPlugin.PlayerAddedSystem(playerComponentType, playerRefComponentType)); } - private static void onItemAssetLoad(LoadedAssetsEvent> event) { + private static void onItemAssetLoad(@Nonnull LoadedAssetsEvent> event) { List recipesToLoad = new ObjectArrayList<>(); for (Item item : event.getLoadedAssets().values()) { @@ -174,7 +180,7 @@ public class CraftingPlugin extends JavaPlugin { } } - private static void onRecipeLoad(LoadedAssetsEvent> event) { + private static void onRecipeLoad(@Nonnull LoadedAssetsEvent> event) { for (CraftingRecipe recipe : event.getLoadedAssets().values()) { for (BenchRecipeRegistry registry : registries.values()) { registry.removeRecipe(recipe.getId()); @@ -191,7 +197,7 @@ public class CraftingPlugin extends JavaPlugin { computeBenchRecipeRegistries(); } - private static void onRecipeRemove(RemovedAssetsEvent> event) { + private static void onRecipeRemove(@Nonnull RemovedAssetsEvent> event) { for (String removedRecipeId : event.getRemovedAssets()) { for (BenchRecipeRegistry registry : registries.values()) { registry.removeRecipe(removedRecipeId); @@ -322,11 +328,19 @@ public class CraftingPlugin extends JavaPlugin { } public static class PlayerAddedSystem extends RefSystem { - private static final Query QUERY = Archetype.of(Player.getComponentType(), PlayerRef.getComponentType()); + @Nonnull + private final Query query; + public PlayerAddedSystem( + @Nonnull ComponentType playerComponentType, @Nonnull ComponentType playerRefComponentType + ) { + this.query = Archetype.of(playerComponentType, playerRefComponentType); + } + + @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } @Override diff --git a/src/com/hypixel/hytale/builtin/crafting/component/CraftingManager.java b/src/com/hypixel/hytale/builtin/crafting/component/CraftingManager.java index ab29b794..aaa9155a 100644 --- a/src/com/hypixel/hytale/builtin/crafting/component/CraftingManager.java +++ b/src/com/hypixel/hytale/builtin/crafting/component/CraftingManager.java @@ -49,6 +49,7 @@ import com.hypixel.hytale.server.core.inventory.container.filter.FilterType; 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.modules.entity.player.PlayerSettings; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.SoundUtil; import com.hypixel.hytale.server.core.universe.world.World; @@ -422,7 +423,18 @@ public class CraftingManager implements Component { } else { List itemStacks = getOutputItemStacks(craftingRecipe, quantity); Inventory inventory = playerComponent.getInventory(); - SimpleItemContainer.addOrDropItemStacks(componentAccessor, ref, inventory.getCombinedArmorHotbarStorage(), itemStacks); + PlayerSettings playerSettings = componentAccessor.getComponent(ref, PlayerSettings.getComponentType()); + if (playerSettings == null) { + playerSettings = PlayerSettings.defaults(); + } + + for (ItemStack itemStack : itemStacks) { + if (!ItemStack.isEmpty(itemStack)) { + SimpleItemContainer.addOrDropItemStack( + componentAccessor, ref, inventory.getContainerForItemPickup(itemStack.getItem(), playerSettings), itemStack + ); + } + } } } @@ -872,6 +884,7 @@ public class CraftingManager implements Component { this.timeSeconds = timeSeconds; } + @Nonnull @Override public String toString() { return "BenchUpgradingJob{window=" + this.window + ", timeSeconds=" + this.timeSeconds + "}"; diff --git a/src/com/hypixel/hytale/builtin/crafting/interaction/LearnRecipeInteraction.java b/src/com/hypixel/hytale/builtin/crafting/interaction/LearnRecipeInteraction.java index e9f4f743..e85b004e 100644 --- a/src/com/hypixel/hytale/builtin/crafting/interaction/LearnRecipeInteraction.java +++ b/src/com/hypixel/hytale/builtin/crafting/interaction/LearnRecipeInteraction.java @@ -24,6 +24,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class LearnRecipeInteraction extends SimpleInstantInteraction { + @Nonnull public static final KeyedCodec ITEM_ID = new KeyedCodec<>("ItemId", Codec.STRING); @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( @@ -35,7 +36,6 @@ public class LearnRecipeInteraction extends SimpleInstantInteraction { ) .add() .build(); - public static final Message MESSAGE_MODULES_LEARN_RECIPE_INVALID_ITEM = Message.translation("server.modules.learnrecipe.invalidItem"); @Nullable protected String itemId; diff --git a/src/com/hypixel/hytale/builtin/crafting/interaction/OpenBenchPageInteraction.java b/src/com/hypixel/hytale/builtin/crafting/interaction/OpenBenchPageInteraction.java index 30352943..be748414 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; @@ -30,17 +30,23 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class OpenBenchPageInteraction extends SimpleBlockInteraction { + @Nonnull public static final OpenBenchPageInteraction SIMPLE_CRAFTING = new OpenBenchPageInteraction( "*Simple_Crafting_Default", OpenBenchPageInteraction.PageType.SIMPLE_CRAFTING ); + @Nonnull public static final RootInteraction SIMPLE_CRAFTING_ROOT = new RootInteraction(SIMPLE_CRAFTING.getId(), SIMPLE_CRAFTING.getId()); + @Nonnull public static final OpenBenchPageInteraction DIAGRAM_CRAFTING = new OpenBenchPageInteraction( "*Diagram_Crafting_Default", OpenBenchPageInteraction.PageType.DIAGRAM_CRAFTING ); + @Nonnull public static final RootInteraction DIAGRAM_CRAFTING_ROOT = new RootInteraction(DIAGRAM_CRAFTING.getId(), DIAGRAM_CRAFTING.getId()); + @Nonnull public static final OpenBenchPageInteraction STRUCTURAL_CRAFTING = new OpenBenchPageInteraction( "*Structural_Crafting_Default", OpenBenchPageInteraction.PageType.STRUCTURAL_CRAFTING ); + @Nonnull public static final RootInteraction STRUCTURAL_CRAFTING_ROOT = new RootInteraction(STRUCTURAL_CRAFTING.getId(), STRUCTURAL_CRAFTING.getId()); @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( @@ -82,19 +88,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 +117,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..e80f2fa0 100644 --- a/src/com/hypixel/hytale/builtin/crafting/interaction/OpenProcessingBenchInteraction.java +++ b/src/com/hypixel/hytale/builtin/crafting/interaction/OpenProcessingBenchInteraction.java @@ -33,6 +33,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class OpenProcessingBenchInteraction extends SimpleBlockInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( OpenProcessingBenchInteraction.class, OpenProcessingBenchInteraction::new, SimpleBlockInteraction.CODEC ) @@ -70,36 +71,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, benchState.getBaseBlockType(), benchState.getTierStateName()); + } - 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/BenchState.java b/src/com/hypixel/hytale/builtin/crafting/state/BenchState.java index dc92c06f..c3784e24 100644 --- a/src/com/hypixel/hytale/builtin/crafting/state/BenchState.java +++ b/src/com/hypixel/hytale/builtin/crafting/state/BenchState.java @@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public class BenchState extends BlockState implements DestroyableBlockState { + @Nonnull public static BuilderCodec CODEC = BuilderCodec.builder(BenchState.class, BenchState::new, BlockState.BASE_CODEC) .appendInherited( new KeyedCodec<>("TierLevel", Codec.INTEGER), @@ -47,6 +48,7 @@ public class BenchState extends BlockState implements DestroyableBlockState { private int tierLevel = 1; protected ItemStack[] upgradeItems = ItemStack.EMPTY_ARRAY; protected Bench bench; + @Nonnull protected final Map windows = new ConcurrentHashMap<>(); public int getTierLevel() { @@ -71,7 +73,7 @@ public class BenchState extends BlockState implements DestroyableBlockState { } } - public void addUpgradeItems(List consumed) { + public void addUpgradeItems(@Nonnull List consumed) { consumed.addAll(Arrays.asList(this.upgradeItems)); this.upgradeItems = consumed.toArray(ItemStack[]::new); this.markNeedsSave(); @@ -111,6 +113,7 @@ public class BenchState extends BlockState implements DestroyableBlockState { this.getChunk().setBlockInteractionState(this.getBlockPosition(), this.getBaseBlockType(), this.getTierStateName()); } + @Nonnull public BlockType getBaseBlockType() { BlockType currentBlockType = this.getBlockType(); String baseBlockKey = currentBlockType.getDefaultStateKey(); @@ -122,6 +125,7 @@ public class BenchState extends BlockState implements DestroyableBlockState { return baseBlockType; } + @Nonnull public String getTierStateName() { return this.tierLevel > 1 ? "Tier" + this.tierLevel : "default"; } diff --git a/src/com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.java b/src/com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.java index 726d4f3c..25fbd709 100644 --- a/src/com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.java +++ b/src/com/hypixel/hytale/builtin/crafting/state/ProcessingBenchState.java @@ -16,13 +16,12 @@ import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.event.EventPriority; import com.hypixel.hytale.logger.HytaleLogger; +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.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 +29,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,21 +45,18 @@ 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; import com.hypixel.hytale.server.core.universe.world.accessor.BlockAccessor; +import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.core.universe.world.chunk.state.TickableBlockState; 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,22 +65,17 @@ 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 { + @Nonnull public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static final boolean EXACT_RESOURCE_AMOUNTS = true; + @Nonnull public static final Codec CODEC = BuilderCodec.builder(ProcessingBenchState.class, ProcessingBenchState::new, BenchState.CODEC) .append(new KeyedCodec<>("InputContainer", ItemContainer.CODEC), (state, o) -> state.inputContainer = o, state -> state.inputContainer) .add() @@ -101,17 +91,16 @@ 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(); private static final float EJECT_VELOCITY = 2.0F; private static final float EJECT_SPREAD_VELOCITY = 1.0F; private static final float EJECT_VERTICAL_VELOCITY = 3.25F; + @Nonnull public static final String PROCESSING = "Processing"; + @Nonnull public static final String PROCESS_COMPLETED = "ProcessCompleted"; - protected WorldMapManager.MarkerReference marker; private ProcessingBench processingBench; private ItemContainer inputContainer; private ItemContainer fuelContainer; @@ -121,7 +110,9 @@ public class ProcessingBenchState private float fuelTime; private int lastConsumedFuelTotal; private int nextExtra = -1; + @Nonnull private final Set processingSlots = new HashSet<>(); + @Nonnull private final Set processingFuelSlots = new HashSet<>(); @Nullable private String recipeId; @@ -647,10 +638,6 @@ public class ProcessingBenchState world.execute(() -> entityStore.addEntities(itemEntityHolders, AddReason.SPAWN)); } } - - if (this.marker != null) { - this.marker.remove(); - } } public CombinedItemContainer getItemContainer() { @@ -775,12 +762,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,34 +769,21 @@ 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) { if (soundEventIndex != 0) { Vector3i pos = this.getBlockPosition(); - SoundUtil.playSoundEvent3d(soundEventIndex, SoundCategory.SFX, pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, componentAccessor); + WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(pos.x, pos.z)); + int rotationIndex = chunk.getRotationIndex(pos.x, pos.y, pos.z); + Vector3d soundPos = new Vector3d(); + BlockType blockType = this.getBlockType(); + if (blockType != null) { + blockType.getBlockCenter(rotationIndex, soundPos); + } + + soundPos.add(pos); + SoundUtil.playSoundEvent3d(soundEventIndex, SoundCategory.SFX, soundPos, componentAccessor); } } diff --git a/src/com/hypixel/hytale/builtin/crafting/system/PlayerCraftingSystems.java b/src/com/hypixel/hytale/builtin/crafting/system/PlayerCraftingSystems.java index 5ecc8c81..572f65d9 100644 --- a/src/com/hypixel/hytale/builtin/crafting/system/PlayerCraftingSystems.java +++ b/src/com/hypixel/hytale/builtin/crafting/system/PlayerCraftingSystems.java @@ -21,11 +21,14 @@ import javax.annotation.Nonnull; public class PlayerCraftingSystems { public static class CraftingHolderSystem extends HolderSystem { @Nonnull - private final ComponentType playerComponentType = Player.getComponentType(); + private final ComponentType playerComponentType; @Nonnull private final ComponentType craftingManagerComponentType; - public CraftingHolderSystem(@Nonnull ComponentType craftingManagerComponentType) { + public CraftingHolderSystem( + @Nonnull ComponentType playerComponentType, @Nonnull ComponentType craftingManagerComponentType + ) { + this.playerComponentType = playerComponentType; this.craftingManagerComponentType = craftingManagerComponentType; } @@ -54,19 +57,22 @@ public class PlayerCraftingSystems { } public static class CraftingRefSystem extends RefSystem { - @Nonnull - private final ComponentType playerComponentType = Player.getComponentType(); @Nonnull private final ComponentType craftingManagerComponentType; + @Nonnull + private final Query query; - public CraftingRefSystem(@Nonnull ComponentType craftingManagerComponentType) { + public CraftingRefSystem( + @Nonnull ComponentType playerComponentType, @Nonnull ComponentType craftingManagerComponentType + ) { this.craftingManagerComponentType = craftingManagerComponentType; + this.query = Query.and(playerComponentType, craftingManagerComponentType); } @Nonnull @Override public Query getQuery() { - return Query.and(this.playerComponentType, this.craftingManagerComponentType); + return this.query; } @Override @@ -79,7 +85,7 @@ public class PlayerCraftingSystems { public void onEntityRemove( @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - CraftingManager craftingManagerComponent = commandBuffer.getComponent(ref, CraftingManager.getComponentType()); + CraftingManager craftingManagerComponent = commandBuffer.getComponent(ref, this.craftingManagerComponentType); assert craftingManagerComponent != null; diff --git a/src/com/hypixel/hytale/builtin/crafting/window/BenchWindow.java b/src/com/hypixel/hytale/builtin/crafting/window/BenchWindow.java index e409ee96..7318dac6 100644 --- a/src/com/hypixel/hytale/builtin/crafting/window/BenchWindow.java +++ b/src/com/hypixel/hytale/builtin/crafting/window/BenchWindow.java @@ -7,8 +7,10 @@ import com.hypixel.hytale.builtin.crafting.state.BenchState; 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.SoundCategory; import com.hypixel.hytale.protocol.packets.window.WindowType; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.Bench; import com.hypixel.hytale.server.core.asset.type.gameplay.CraftingConfig; import com.hypixel.hytale.server.core.asset.type.item.config.Item; @@ -17,17 +19,21 @@ import com.hypixel.hytale.server.core.entity.entities.player.windows.MaterialCon import com.hypixel.hytale.server.core.entity.entities.player.windows.MaterialExtraResourcesSection; 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.WorldChunk; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public abstract class BenchWindow extends BlockWindow implements MaterialContainerWindow { private static final float CRAFTING_UPDATE_MIN_PERCENT = 0.05F; private static final long CRAFTING_UPDATE_INTERVAL_MS = 500L; + @Nonnull protected static final String BENCH_UPGRADING = "BenchUpgrading"; private float lastUpdatePercent; private long lastUpdateTimeMs; protected final Bench bench; + @Nonnull protected final BenchState benchState; + @Nonnull protected final JsonObject windowData = new JsonObject(); @Nonnull private final MaterialExtraResourcesSection extraResourcesSection = new MaterialExtraResourcesSection(); @@ -83,6 +89,8 @@ public abstract class BenchWindow extends BlockWindow implements MaterialContain @Override public void onClose0(@Nonnull Ref ref, @Nonnull ComponentAccessor componentAccessor) { + World world = componentAccessor.getExternalData().getWorld(); + this.setBlockInteractionState(this.benchState.getTierStateName(), world); CraftingManager craftingManagerComponent = componentAccessor.getComponent(ref, CraftingManager.getComponentType()); if (craftingManagerComponent != null) { if (craftingManagerComponent.clearBench(ref, componentAccessor) && this.bench.getFailedSoundEventIndex() != 0) { @@ -91,6 +99,16 @@ public abstract class BenchWindow extends BlockWindow implements MaterialContain } } + public void setBlockInteractionState(@Nonnull String state, @Nonnull World world) { + WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(this.x, this.z)); + if (worldChunk != null) { + BlockType blockType = worldChunk.getBlockType(this.x, this.y, this.z); + if (blockType != null) { + worldChunk.setBlockInteractionState(this.x, this.y, this.z, blockType, state, true); + } + } + } + public void updateCraftingJob(float percent) { this.windowData.addProperty("progress", percent); this.checkProgressInvalidate(percent); diff --git a/src/com/hypixel/hytale/builtin/crafting/window/CraftingWindow.java b/src/com/hypixel/hytale/builtin/crafting/window/CraftingWindow.java index 303305ad..2022ad43 100644 --- a/src/com/hypixel/hytale/builtin/crafting/window/CraftingWindow.java +++ b/src/com/hypixel/hytale/builtin/crafting/window/CraftingWindow.java @@ -9,19 +9,15 @@ import com.hypixel.hytale.builtin.crafting.state.BenchState; 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.SoundCategory; import com.hypixel.hytale.protocol.packets.window.CraftRecipeAction; import com.hypixel.hytale.protocol.packets.window.WindowType; -import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.CraftingBench; import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig; import com.hypixel.hytale.server.core.asset.type.item.config.CraftingRecipe; 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.SoundUtil; -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.storage.EntityStore; import java.util.Set; import javax.annotation.Nonnull; @@ -102,23 +98,11 @@ public abstract class CraftingWindow extends BenchWindow { @Override public void onClose0(@Nonnull Ref ref, @Nonnull ComponentAccessor componentAccessor) { super.onClose0(ref, componentAccessor); - World world = componentAccessor.getExternalData().getWorld(); - this.setBlockInteractionState(this.benchState.getTierStateName(), world); if (this.bench.getLocalCloseSoundEventIndex() != 0) { SoundUtil.playSoundEvent2d(ref, this.bench.getLocalCloseSoundEventIndex(), SoundCategory.UI, componentAccessor); } } - public void setBlockInteractionState(@Nonnull String state, @Nonnull World world) { - WorldChunk worldChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(this.x, this.z)); - if (worldChunk != null) { - BlockType blockType = worldChunk.getBlockType(this.x, this.y, this.z); - if (blockType != null) { - worldChunk.setBlockInteractionState(this.x, this.y, this.z, blockType, state, true); - } - } - } - public static boolean craftSimpleItem( @Nonnull Store store, @Nonnull Ref ref, @Nonnull CraftingManager craftingManager, @Nonnull CraftRecipeAction action ) { diff --git a/src/com/hypixel/hytale/builtin/crafting/window/DiagramCraftingWindow.java b/src/com/hypixel/hytale/builtin/crafting/window/DiagramCraftingWindow.java index f2ff8ae0..b3510dfa 100644 --- a/src/com/hypixel/hytale/builtin/crafting/window/DiagramCraftingWindow.java +++ b/src/com/hypixel/hytale/builtin/crafting/window/DiagramCraftingWindow.java @@ -44,6 +44,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class DiagramCraftingWindow extends CraftingWindow implements ItemContainerWindow { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); private String category; private String itemCategory; diff --git a/src/com/hypixel/hytale/builtin/crafting/window/ProcessingBenchWindow.java b/src/com/hypixel/hytale/builtin/crafting/window/ProcessingBenchWindow.java index c5c7c379..139ea46b 100644 --- a/src/com/hypixel/hytale/builtin/crafting/window/ProcessingBenchWindow.java +++ b/src/com/hypixel/hytale/builtin/crafting/window/ProcessingBenchWindow.java @@ -38,10 +38,12 @@ public class ProcessingBenchWindow extends BenchWindow implements ItemContainerW private int maxFuel; private float progress; private boolean active; + @Nonnull private final Set processingSlots = new HashSet<>(); + @Nonnull private final Set processingFuelSlots = new HashSet<>(); - public ProcessingBenchWindow(ProcessingBenchState benchState) { + public ProcessingBenchWindow(@Nonnull ProcessingBenchState benchState) { super(WindowType.Processing, benchState); ProcessingBench processingBench = (ProcessingBench)this.blockType.getBench(); CraftingRecipe recipe = benchState.getRecipe(); @@ -132,7 +134,7 @@ public class ProcessingBenchWindow extends BenchWindow implements ItemContainerW } } - public void setProcessingSlots(Set slots) { + public void setProcessingSlots(@Nonnull Set slots) { if (!this.processingSlots.equals(slots)) { this.processingSlots.clear(); this.processingSlots.addAll(slots); @@ -147,7 +149,7 @@ public class ProcessingBenchWindow extends BenchWindow implements ItemContainerW } } - public void setProcessingFuelSlots(Set slots) { + public void setProcessingFuelSlots(@Nonnull Set slots) { if (!this.processingFuelSlots.equals(slots)) { this.processingFuelSlots.clear(); this.processingFuelSlots.addAll(slots); diff --git a/src/com/hypixel/hytale/builtin/crafting/window/SimpleCraftingWindow.java b/src/com/hypixel/hytale/builtin/crafting/window/SimpleCraftingWindow.java index 58b7b929..b3fe6aa8 100644 --- a/src/com/hypixel/hytale/builtin/crafting/window/SimpleCraftingWindow.java +++ b/src/com/hypixel/hytale/builtin/crafting/window/SimpleCraftingWindow.java @@ -22,7 +22,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class SimpleCraftingWindow extends CraftingWindow implements MaterialContainerWindow { - public SimpleCraftingWindow(BenchState benchState) { + public SimpleCraftingWindow(@Nonnull BenchState benchState) { super(WindowType.BasicCrafting, benchState); } @@ -42,12 +42,19 @@ public class SimpleCraftingWindow extends CraftingWindow implements MaterialCont CraftingRecipe craftRecipe = CraftingRecipe.getAssetMap().getAsset(recipeId); if (craftRecipe == null) { PlayerRef playerRef = store.getComponent(ref, PlayerRef.getComponentType()); - playerRef.getPacketHandler().disconnect("Attempted to craft unknown recipe!"); + if (playerRef != null) { + playerRef.getPacketHandler().disconnect("Attempted to craft unknown recipe!"); + } + return; } - Player player = store.getComponent(ref, Player.getComponentType()); - CombinedItemContainer combined = player.getInventory().getCombinedBackpackStorageHotbar(); + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (playerComponent == null) { + return; + } + + CombinedItemContainer combined = playerComponent.getInventory().getCombinedBackpackStorageHotbar(); CombinedItemContainer playerAndContainerInventory = new CombinedItemContainer(combined, this.getExtraResourcesSection().getItemContainer()); boolean accepted; if (craftRecipe.getTimeSeconds() > 0.0F) { diff --git a/src/com/hypixel/hytale/builtin/crafting/window/StructuralCraftingWindow.java b/src/com/hypixel/hytale/builtin/crafting/window/StructuralCraftingWindow.java index 64b029e5..62c2dd59 100644 --- a/src/com/hypixel/hytale/builtin/crafting/window/StructuralCraftingWindow.java +++ b/src/com/hypixel/hytale/builtin/crafting/window/StructuralCraftingWindow.java @@ -11,7 +11,6 @@ import com.hypixel.hytale.event.EventRegistration; import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.protocol.BenchRequirement; import com.hypixel.hytale.protocol.ItemSoundEvent; -import com.hypixel.hytale.protocol.SoundCategory; import com.hypixel.hytale.protocol.packets.window.ChangeBlockAction; import com.hypixel.hytale.protocol.packets.window.CraftRecipeAction; import com.hypixel.hytale.protocol.packets.window.SelectSlotAction; @@ -21,8 +20,6 @@ import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.Structur import com.hypixel.hytale.server.core.asset.type.item.config.BlockGroup; 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.asset.type.itemsound.config.ItemSoundSet; -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.entity.entities.player.windows.ItemContainerWindow; import com.hypixel.hytale.server.core.inventory.Inventory; @@ -45,15 +42,19 @@ import javax.annotation.Nullable; public class StructuralCraftingWindow extends CraftingWindow implements ItemContainerWindow { private static final int MAX_OPTIONS = 64; + @Nonnull private final SimpleItemContainer inputContainer; + @Nonnull private final SimpleItemContainer optionsContainer; + @Nonnull private final CombinedItemContainer combinedItemContainer; + @Nonnull private final Int2ObjectMap optionSlotToRecipeMap = new Int2ObjectOpenHashMap<>(); private int selectedSlot; @Nullable private EventRegistration inventoryRegistration; - public StructuralCraftingWindow(BenchState benchState) { + public StructuralCraftingWindow(@Nonnull BenchState benchState) { super(WindowType.StructuralCrafting, benchState); this.inputContainer = new SimpleItemContainer((short)1); this.inputContainer.registerChangeEvent(e -> this.updateRecipes()); @@ -76,7 +77,7 @@ public class StructuralCraftingWindow extends CraftingWindow implements ItemCont } } - private static void sortRecipes(ObjectList matching, StructuralCraftingBench structuralBench) { + private static void sortRecipes(@Nonnull ObjectList matching, @Nonnull StructuralCraftingBench structuralBench) { matching.sort((a, b) -> { boolean aHasHeaderCategory = hasHeaderCategory(structuralBench, a); boolean bHasHeaderCategory = hasHeaderCategory(structuralBench, b); @@ -91,7 +92,7 @@ public class StructuralCraftingWindow extends CraftingWindow implements ItemCont }); } - private static boolean hasHeaderCategory(StructuralCraftingBench bench, CraftingRecipe recipe) { + private static boolean hasHeaderCategory(@Nonnull StructuralCraftingBench bench, @Nonnull CraftingRecipe recipe) { for (BenchRequirement requirement : recipe.getBenchRequirement()) { if (requirement.type == bench.getType() && requirement.id.equals(bench.getId()) && requirement.categories != null) { for (String category : requirement.categories) { @@ -105,7 +106,7 @@ public class StructuralCraftingWindow extends CraftingWindow implements ItemCont return false; } - private static int getSortingPriority(StructuralCraftingBench bench, CraftingRecipe recipe) { + private static int getSortingPriority(@Nonnull StructuralCraftingBench bench, @Nonnull CraftingRecipe recipe) { int priority = Integer.MAX_VALUE; for (BenchRequirement requirement : recipe.getBenchRequirement()) { @@ -122,61 +123,50 @@ public class StructuralCraftingWindow extends CraftingWindow implements ItemCont @Override public void handleAction(@Nonnull Ref ref, @Nonnull Store store, @Nonnull WindowAction action) { - CraftingManager craftingManager = store.getComponent(ref, CraftingManager.getComponentType()); - switch (action) { - case SelectSlotAction selectAction: - int newSlot = MathUtil.clamp(selectAction.slot, 0, this.optionsContainer.getCapacity()); - if (newSlot != this.selectedSlot) { - this.selectedSlot = newSlot; - this.windowData.addProperty("selected", this.selectedSlot); - this.invalidate(); - } - break; - case CraftRecipeAction craftAction: - ItemStack output = this.optionsContainer.getItemStack((short)this.selectedSlot); - if (output != null) { - int quantity = craftAction.quantity; - String recipeId = this.optionSlotToRecipeMap.get(this.selectedSlot); - if (recipeId == null) { - return; + CraftingManager craftingManagerComponent = store.getComponent(ref, CraftingManager.getComponentType()); + if (craftingManagerComponent != null) { + switch (action) { + case SelectSlotAction selectAction: + int newSlot = MathUtil.clamp(selectAction.slot, 0, this.optionsContainer.getCapacity()); + if (newSlot != this.selectedSlot) { + this.selectedSlot = newSlot; + this.windowData.addProperty("selected", this.selectedSlot); + this.invalidate(); } - - CraftingRecipe recipe = CraftingRecipe.getAssetMap().getAsset(recipeId); - if (recipe == null) { - return; - } - - MaterialQuantity primaryOutput = recipe.getPrimaryOutput(); - String primaryOutputItemId = primaryOutput.getItemId(); - if (primaryOutputItemId != null) { - Item primaryOutputItem = Item.getAssetMap().getAsset(primaryOutputItemId); - if (primaryOutputItem != null) { - this.playCraftSound(ref, store, primaryOutputItem); + break; + case CraftRecipeAction craftAction: + ItemStack output = this.optionsContainer.getItemStack((short)this.selectedSlot); + if (output != null) { + int quantity = craftAction.quantity; + String recipeId = this.optionSlotToRecipeMap.get(this.selectedSlot); + if (recipeId == null) { + return; } + + CraftingRecipe recipe = CraftingRecipe.getAssetMap().getAsset(recipeId); + if (recipe == null) { + return; + } + + MaterialQuantity primaryOutput = recipe.getPrimaryOutput(); + String primaryOutputItemId = primaryOutput.getItemId(); + if (primaryOutputItemId != null) { + Item primaryOutputItem = Item.getAssetMap().getAsset(primaryOutputItemId); + if (primaryOutputItem != null) { + SoundUtil.playItemSoundEvent(ref, store, primaryOutputItem, ItemSoundEvent.Drop); + } + } + + craftingManagerComponent.queueCraft(ref, store, this, 0, recipe, quantity, this.inputContainer, CraftingManager.InputRemovalType.ORDERED); + this.invalidate(); } - - craftingManager.queueCraft(ref, store, this, 0, recipe, quantity, this.inputContainer, CraftingManager.InputRemovalType.ORDERED); - this.invalidate(); - } - break; - case ChangeBlockAction changeBlockAction: - if (((StructuralCraftingBench)this.bench).shouldAllowBlockGroupCycling()) { - this.changeBlockType(ref, changeBlockAction.down, store); - } - break; - default: - } - } - - private void playCraftSound(Ref ref, Store store, Item item) { - ItemSoundSet soundSet = ItemSoundSet.getAssetMap().getAsset(item.getItemSoundSetIndex()); - if (soundSet != null) { - String dragSound = soundSet.getSoundEventIds().get(ItemSoundEvent.Drop); - if (dragSound != null) { - int dragSoundIndex = SoundEvent.getAssetMap().getIndex(dragSound); - if (dragSoundIndex != 0) { - SoundUtil.playSoundEvent2d(ref, dragSoundIndex, SoundCategory.UI, store); - } + break; + case ChangeBlockAction changeBlockAction: + if (((StructuralCraftingBench)this.bench).shouldAllowBlockGroupCycling()) { + this.changeBlockType(ref, changeBlockAction.down, store); + } + break; + default: } } } @@ -207,7 +197,7 @@ public class StructuralCraftingWindow extends CraftingWindow implements ItemCont Item desiredItem = Item.getAssetMap().getAsset(next); if (desiredItem != null) { this.inputContainer.replaceItemStackInSlot((short)0, item, new ItemStack(next, item.getQuantity())); - this.playCraftSound(ref, store, desiredItem); + SoundUtil.playItemSoundEvent(ref, store, desiredItem, ItemSoundEvent.Drop); } } } diff --git a/src/com/hypixel/hytale/builtin/creativehub/CreativeHubPlugin.java b/src/com/hypixel/hytale/builtin/creativehub/CreativeHubPlugin.java index c663142c..9ba90fa2 100644 --- a/src/com/hypixel/hytale/builtin/creativehub/CreativeHubPlugin.java +++ b/src/com/hypixel/hytale/builtin/creativehub/CreativeHubPlugin.java @@ -4,6 +4,8 @@ import com.hypixel.hytale.builtin.creativehub.command.HubCommand; import com.hypixel.hytale.builtin.creativehub.config.CreativeHubEntityConfig; import com.hypixel.hytale.builtin.creativehub.config.CreativeHubWorldConfig; import com.hypixel.hytale.builtin.creativehub.interactions.HubPortalInteraction; +import com.hypixel.hytale.builtin.creativehub.systems.ReturnToHubButtonSystem; +import com.hypixel.hytale.builtin.creativehub.ui.ReturnToHubButtonUI; import com.hypixel.hytale.builtin.instances.InstancesPlugin; import com.hypixel.hytale.builtin.instances.config.InstanceEntityConfig; import com.hypixel.hytale.builtin.instances.config.InstanceWorldConfig; @@ -43,6 +45,7 @@ public class CreativeHubPlugin extends JavaPlugin { @Nonnull private static final Message MESSAGE_HUB_RETURN_HINT = Message.translation("server.creativehub.portal.returnHint"); private static CreativeHubPlugin instance; + @Nonnull private final Map activeHubInstances = new ConcurrentHashMap<>(); private ComponentType creativeHubEntityConfigComponentType; @@ -92,14 +95,17 @@ public class CreativeHubPlugin extends JavaPlugin { return universe.loadWorld(permanentWorldName); } else { Path assetPath = InstancesPlugin.getInstanceAssetPath(instanceAssetName); - Path worldPath = universe.getPath().resolve("worlds").resolve(permanentWorldName); + Path worldPath = universe.validateWorldPath(permanentWorldName); return WorldConfig.load(assetPath.resolve("instance.bson")) .thenApplyAsync( SneakyThrow.sneakyFunction( config -> { config.setUuid(UUID.randomUUID()); config.setDeleteOnRemove(false); - config.setDisplayName(WorldConfig.formatDisplayName(instanceAssetName)); + if (config.getDisplayName() == null) { + config.setDisplayName(WorldConfig.formatDisplayName(instanceAssetName)); + } + config.getPluginConfig().remove(InstanceWorldConfig.class); config.markChanged(); long start = System.nanoTime(); @@ -147,9 +153,11 @@ public class CreativeHubPlugin extends JavaPlugin { this.getCodecRegistry(WorldConfig.PLUGIN_CODEC).register(CreativeHubWorldConfig.class, "CreativeHub", CreativeHubWorldConfig.CODEC); this.creativeHubEntityConfigComponentType = this.getEntityStoreRegistry() .registerComponent(CreativeHubEntityConfig.class, "CreativeHub", CreativeHubEntityConfig.CODEC); + this.getEntityStoreRegistry().registerSystem(new ReturnToHubButtonSystem()); this.getEventRegistry().registerGlobal(PlayerConnectEvent.class, CreativeHubPlugin::onPlayerConnect); this.getEventRegistry().registerGlobal(RemoveWorldEvent.class, CreativeHubPlugin::onWorldRemove); this.getEventRegistry().registerGlobal(AddPlayerToWorldEvent.class, CreativeHubPlugin::onPlayerAddToWorld); + ReturnToHubButtonUI.register(); } private static void onWorldRemove(@Nonnull RemoveWorldEvent event) { @@ -211,9 +219,11 @@ public class CreativeHubPlugin extends JavaPlugin { World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid()); if (parentWorld != null) { World hubInstance = get().getActiveHubInstance(parentWorld); - if (hubInstance == null || !world.equals(hubInstance)) { - PlayerRef playerRef = holder.getComponent(PlayerRef.getComponentType()); - if (playerRef != null) { + boolean isInHubInstance = world.equals(hubInstance); + PlayerRef playerRef = holder.getComponent(PlayerRef.getComponentType()); + if (playerRef != null) { + ReturnToHubButtonUI.send(playerRef, isInHubInstance); + if (!isInHubInstance) { world.execute(() -> playerRef.sendMessage(MESSAGE_HUB_RETURN_HINT)); } } diff --git a/src/com/hypixel/hytale/builtin/creativehub/command/HubCommand.java b/src/com/hypixel/hytale/builtin/creativehub/command/HubCommand.java index cad6df71..8cc00547 100644 --- a/src/com/hypixel/hytale/builtin/creativehub/command/HubCommand.java +++ b/src/com/hypixel/hytale/builtin/creativehub/command/HubCommand.java @@ -27,7 +27,7 @@ public class HubCommand extends AbstractPlayerCommand { public HubCommand() { super("hub", "server.commands.hub.desc"); - this.addAliases("converge", "convergence"); + this.addAliases("cosmos", "crossroads"); this.setPermissionGroup(GameMode.Creative); } @@ -35,14 +35,14 @@ public class HubCommand extends AbstractPlayerCommand { protected void execute( @Nonnull CommandContext context, @Nonnull Store store, @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world ) { - World parentWorld = this.findParentHubWorld(store, ref); + World parentWorld = findParentHubWorld(store, ref); if (parentWorld == null) { playerRef.sendMessage(MESSAGE_NOT_IN_HUB_WORLD); } else { CreativeHubWorldConfig hubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig()); if (hubConfig != null && hubConfig.getStartupInstance() != null) { World currentHub = CreativeHubPlugin.get().getActiveHubInstance(parentWorld); - if (currentHub != null && world.equals(currentHub)) { + if (world.equals(currentHub)) { playerRef.sendMessage(MESSAGE_ALREADY_IN_HUB); } else { ISpawnProvider spawnProvider = parentWorld.getWorldConfig().getSpawnProvider(); @@ -57,7 +57,7 @@ public class HubCommand extends AbstractPlayerCommand { } @Nullable - private World findParentHubWorld(@Nonnull Store store, @Nonnull Ref ref) { + private static World findParentHubWorld(@Nonnull Store store, @Nonnull Ref ref) { CreativeHubEntityConfig hubEntityConfig = store.getComponent(ref, CreativeHubEntityConfig.getComponentType()); if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) { World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid()); diff --git a/src/com/hypixel/hytale/builtin/creativehub/config/CreativeHubEntityConfig.java b/src/com/hypixel/hytale/builtin/creativehub/config/CreativeHubEntityConfig.java index c1c8e0f5..04663d83 100644 --- a/src/com/hypixel/hytale/builtin/creativehub/config/CreativeHubEntityConfig.java +++ b/src/com/hypixel/hytale/builtin/creativehub/config/CreativeHubEntityConfig.java @@ -13,6 +13,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CreativeHubEntityConfig implements Component { + @Nonnull public static final String ID = "CreativeHub"; @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CreativeHubEntityConfig.class, CreativeHubEntityConfig::new) diff --git a/src/com/hypixel/hytale/builtin/creativehub/config/CreativeHubWorldConfig.java b/src/com/hypixel/hytale/builtin/creativehub/config/CreativeHubWorldConfig.java index 87e3cd5c..cec3360c 100644 --- a/src/com/hypixel/hytale/builtin/creativehub/config/CreativeHubWorldConfig.java +++ b/src/com/hypixel/hytale/builtin/creativehub/config/CreativeHubWorldConfig.java @@ -8,6 +8,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CreativeHubWorldConfig { + @Nonnull public static final String ID = "CreativeHub"; @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CreativeHubWorldConfig.class, CreativeHubWorldConfig::new) diff --git a/src/com/hypixel/hytale/builtin/creativehub/interactions/HubPortalInteraction.java b/src/com/hypixel/hytale/builtin/creativehub/interactions/HubPortalInteraction.java index 7233ef0f..263314bb 100644 --- a/src/com/hypixel/hytale/builtin/creativehub/interactions/HubPortalInteraction.java +++ b/src/com/hypixel/hytale/builtin/creativehub/interactions/HubPortalInteraction.java @@ -39,7 +39,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class HubPortalInteraction extends SimpleInstantInteraction { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( HubPortalInteraction.class, HubPortalInteraction::new, SimpleInstantInteraction.CODEC ) @@ -76,6 +78,9 @@ public class HubPortalInteraction extends SimpleInstantInteraction { @Override protected void firstRun(@Nonnull InteractionType type, @Nonnull InteractionContext context, @Nonnull CooldownHandler cooldownHandler) { CommandBuffer commandBuffer = context.getCommandBuffer(); + + assert commandBuffer != null; + Ref ref = context.getEntity(); Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType()); if (playerComponent != null && !playerComponent.isWaitingForClientReady()) { @@ -85,7 +90,7 @@ public class HubPortalInteraction extends SimpleInstantInteraction { Universe universe = Universe.get(); World targetWorld = universe.getWorld(this.worldName); if (targetWorld != null) { - this.teleportToLoadedWorld(ref, commandBuffer, targetWorld, playerComponent); + teleportToLoadedWorld(ref, commandBuffer, targetWorld, playerComponent); } else { CompletableFuture worldFuture; if (this.instanceTemplate != null) { @@ -101,13 +106,13 @@ public class HubPortalInteraction extends SimpleInstantInteraction { }); } - this.teleportToLoadingWorld(ref, commandBuffer, worldFuture, currentWorld, playerComponent); + teleportToLoadingWorld(ref, commandBuffer, worldFuture, currentWorld, playerComponent); } } } } - private void teleportToLoadedWorld( + private static void teleportToLoadedWorld( @Nonnull Ref playerRef, @Nonnull ComponentAccessor componentAccessor, @Nonnull World targetWorld, @@ -131,7 +136,7 @@ public class HubPortalInteraction extends SimpleInstantInteraction { componentAccessor.addComponent(playerRef, Teleport.getComponentType(), teleportComponent); } - private void teleportToLoadingWorld( + private static void teleportToLoadingWorld( @Nonnull Ref playerRef, @Nonnull ComponentAccessor componentAccessor, @Nonnull CompletableFuture worldFuture, @@ -139,61 +144,66 @@ public class HubPortalInteraction extends SimpleInstantInteraction { @Nonnull Player playerComponent ) { TransformComponent transformComponent = componentAccessor.getComponent(playerRef, TransformComponent.getComponentType()); - - assert transformComponent != null; - - Transform originalPosition = transformComponent.getTransform().clone(); - PlayerRef playerRefComponent = componentAccessor.getComponent(playerRef, PlayerRef.getComponentType()); - - assert playerRefComponent != null; - - Map perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(); - UUIDComponent uuidComponent = componentAccessor.getComponent(playerRef, UUIDComponent.getComponentType()); - - assert uuidComponent != null; - - UUID playerUUID = uuidComponent.getUuid(); - CreativeHubEntityConfig hubEntityConfig = componentAccessor.getComponent(playerRef, CreativeHubEntityConfig.getComponentType()); - originalWorld.execute(playerRefComponent::removeFromStore); - worldFuture.orTimeout(1L, TimeUnit.MINUTES).thenCompose(world -> { - PlayerWorldData worldData = perWorldData.get(world.getName()); - if (worldData != null && worldData.getLastPosition() != null) { - return world.addPlayer(playerRefComponent, worldData.getLastPosition(), Boolean.TRUE, Boolean.FALSE); + if (transformComponent == null) { + LOGGER.at(Level.SEVERE).log("Cannot teleport player %s to permanent world - missing TransformComponent", playerRef); + } else { + Transform originalPosition = transformComponent.getTransform().clone(); + PlayerRef playerRefComponent = componentAccessor.getComponent(playerRef, PlayerRef.getComponentType()); + if (playerRefComponent == null) { + LOGGER.at(Level.SEVERE).log("Cannot teleport player %s to permanent world - missing PlayerRef component", playerRef); } else { - ISpawnProvider spawnProvider = world.getWorldConfig().getSpawnProvider(); - Transform spawnPoint = spawnProvider != null ? spawnProvider.getSpawnPoint(world, playerUUID) : null; - return world.addPlayer(playerRefComponent, spawnPoint, Boolean.TRUE, Boolean.FALSE); - } - }).whenComplete((ret, ex) -> { - if (ex != null) { - LOGGER.at(Level.SEVERE).withCause(ex).log("Failed to teleport %s to permanent world", playerRefComponent.getUsername()); - } - - if (ret == null) { - if (originalWorld.isAlive()) { - originalWorld.addPlayer(playerRefComponent, originalPosition, Boolean.TRUE, Boolean.FALSE); + Map perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(); + UUIDComponent uuidComponent = componentAccessor.getComponent(playerRef, UUIDComponent.getComponentType()); + if (uuidComponent == null) { + LOGGER.at(Level.SEVERE).log("Cannot teleport player %s to permanent world - missing UUIDComponent", playerRef); } else { - if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) { - World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid()); - if (parentWorld != null) { - CreativeHubWorldConfig parentHubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig()); - if (parentHubConfig != null && parentHubConfig.getStartupInstance() != null) { - World hubInstance = CreativeHubPlugin.get().getOrSpawnHubInstance(parentWorld, parentHubConfig, new Transform()); - hubInstance.addPlayer(playerRefComponent, null, Boolean.TRUE, Boolean.FALSE); - return; + UUID playerUUID = uuidComponent.getUuid(); + CreativeHubEntityConfig hubEntityConfig = componentAccessor.getComponent(playerRef, CreativeHubEntityConfig.getComponentType()); + CompletableFuture.runAsync(playerRefComponent::removeFromStore, originalWorld) + .thenCombine(worldFuture.orTimeout(1L, TimeUnit.MINUTES), (v, world) -> (World)world) + .thenCompose(world -> { + PlayerWorldData worldData = perWorldData.get(world.getName()); + if (worldData != null && worldData.getLastPosition() != null) { + return world.addPlayer(playerRefComponent, worldData.getLastPosition(), Boolean.TRUE, Boolean.FALSE); + } else { + ISpawnProvider spawnProvider = world.getWorldConfig().getSpawnProvider(); + Transform spawnPoint = spawnProvider != null ? spawnProvider.getSpawnPoint(world, playerUUID) : null; + return world.addPlayer(playerRefComponent, spawnPoint, Boolean.TRUE, Boolean.FALSE); + } + }) + .whenComplete((ret, ex) -> { + if (ex != null) { + LOGGER.at(Level.SEVERE).withCause(ex).log("Failed to teleport %s to permanent world", playerRefComponent.getUsername()); } - } - } - World defaultWorld = Universe.get().getDefaultWorld(); - if (defaultWorld != null) { - defaultWorld.addPlayer(playerRefComponent, null, Boolean.TRUE, Boolean.FALSE); - } else { - LOGGER.at(Level.SEVERE).log("No fallback world available for %s, disconnecting", playerRefComponent.getUsername()); - playerRefComponent.getPacketHandler().disconnect("Failed to teleport - no world available"); - } + if (ret == null) { + if (originalWorld.isAlive()) { + originalWorld.addPlayer(playerRefComponent, originalPosition, Boolean.TRUE, Boolean.FALSE); + } else { + if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) { + World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid()); + if (parentWorld != null) { + CreativeHubWorldConfig parentHubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig()); + if (parentHubConfig != null && parentHubConfig.getStartupInstance() != null) { + World hubInstance = CreativeHubPlugin.get().getOrSpawnHubInstance(parentWorld, parentHubConfig, new Transform()); + hubInstance.addPlayer(playerRefComponent, null, Boolean.TRUE, Boolean.FALSE); + return; + } + } + } + + World defaultWorld = Universe.get().getDefaultWorld(); + if (defaultWorld != null) { + defaultWorld.addPlayer(playerRefComponent, null, Boolean.TRUE, Boolean.FALSE); + } else { + LOGGER.at(Level.SEVERE).log("No fallback world available for %s, disconnecting", playerRefComponent.getUsername()); + playerRefComponent.getPacketHandler().disconnect("Failed to teleport - no world available"); + } + } + } + }); } } - }); + } } } diff --git a/src/com/hypixel/hytale/builtin/creativehub/systems/ReturnToHubButtonSystem.java b/src/com/hypixel/hytale/builtin/creativehub/systems/ReturnToHubButtonSystem.java new file mode 100644 index 00000000..4d501946 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/creativehub/systems/ReturnToHubButtonSystem.java @@ -0,0 +1,66 @@ +package com.hypixel.hytale.builtin.creativehub.systems; + +import com.hypixel.hytale.builtin.creativehub.CreativeHubPlugin; +import com.hypixel.hytale.builtin.creativehub.config.CreativeHubEntityConfig; +import com.hypixel.hytale.builtin.creativehub.ui.ReturnToHubButtonUI; +import com.hypixel.hytale.component.AddReason; +import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.RemoveReason; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.component.query.Query; +import com.hypixel.hytale.component.system.RefSystem; +import com.hypixel.hytale.server.core.entity.entities.Player; +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 java.util.Optional; +import javax.annotation.Nonnull; + +public class ReturnToHubButtonSystem extends RefSystem { + @Override + public void onEntityAdded( + @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { + Optional isInChildWorld = this.getCreativeHubWorldStatus(store, commandBuffer, ref); + if (!isInChildWorld.isEmpty()) { + PlayerRef playerRef = commandBuffer.getComponent(ref, PlayerRef.getComponentType()); + boolean disabled = !isInChildWorld.get(); + ReturnToHubButtonUI.send(playerRef, disabled); + } + } + + @Override + public void onEntityRemove( + @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { + if (!this.getCreativeHubWorldStatus(store, commandBuffer, ref).isEmpty()) { + PlayerRef playerRef = commandBuffer.getComponent(ref, PlayerRef.getComponentType()); + ReturnToHubButtonUI.clear(playerRef); + } + } + + @Override + public Query getQuery() { + return Query.and(Player.getComponentType(), PlayerRef.getComponentType()); + } + + private Optional getCreativeHubWorldStatus( + @Nonnull Store store, @Nonnull CommandBuffer commandBuffer, @Nonnull Ref ref + ) { + CreativeHubEntityConfig hubEntityConfig = commandBuffer.getComponent(ref, CreativeHubEntityConfig.getComponentType()); + if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) { + World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid()); + if (parentWorld == null) { + return Optional.empty(); + } else { + World currentWorld = store.getExternalData().getWorld(); + World hubInstance = CreativeHubPlugin.get().getActiveHubInstance(parentWorld); + return Optional.of(!currentWorld.equals(hubInstance)); + } + } else { + return Optional.empty(); + } + } +} diff --git a/src/com/hypixel/hytale/builtin/creativehub/ui/ReturnToHubButtonUI.java b/src/com/hypixel/hytale/builtin/creativehub/ui/ReturnToHubButtonUI.java new file mode 100644 index 00000000..5153a45f --- /dev/null +++ b/src/com/hypixel/hytale/builtin/creativehub/ui/ReturnToHubButtonUI.java @@ -0,0 +1,87 @@ +package com.hypixel.hytale.builtin.creativehub.ui; + +import com.hypixel.hytale.builtin.creativehub.CreativeHubPlugin; +import com.hypixel.hytale.builtin.creativehub.config.CreativeHubEntityConfig; +import com.hypixel.hytale.builtin.creativehub.config.CreativeHubWorldConfig; +import com.hypixel.hytale.builtin.instances.InstancesPlugin; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.math.vector.Transform; +import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType; +import com.hypixel.hytale.protocol.packets.interface_.UpdateAnchorUI; +import com.hypixel.hytale.server.core.modules.anchoraction.AnchorActionModule; +import com.hypixel.hytale.server.core.ui.builder.EventData; +import com.hypixel.hytale.server.core.ui.builder.UICommandBuilder; +import com.hypixel.hytale.server.core.ui.builder.UIEventBuilder; +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.spawn.ISpawnProvider; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public final class ReturnToHubButtonUI { + public static final String ANCHOR_ID = "MapServerContent"; + public static final String ACTION_RETURN_TO_HUB = "returnToHub"; + + private ReturnToHubButtonUI() { + } + + public static void register() { + AnchorActionModule.get().register("returnToHub", (playerRef, ref, store, data) -> executeReturnToHub(playerRef, ref, store)); + } + + public static void send(@Nonnull PlayerRef playerRef) { + send(playerRef, false); + } + + public static void send(@Nonnull PlayerRef playerRef, boolean disabled) { + UICommandBuilder commandBuilder = new UICommandBuilder(); + commandBuilder.append("Hud/ReturnToHubButton.ui"); + commandBuilder.set("#ReturnToHubButton.Disabled", disabled); + UIEventBuilder eventBuilder = new UIEventBuilder(); + if (!disabled) { + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#ReturnToHubButton", EventData.of("action", "returnToHub"), false); + } + + playerRef.getPacketHandler().writeNoCache(new UpdateAnchorUI("MapServerContent", true, commandBuilder.getCommands(), eventBuilder.getEvents())); + } + + public static void clear(@Nonnull PlayerRef playerRef) { + playerRef.getPacketHandler().writeNoCache(new UpdateAnchorUI("MapServerContent", true, null, null)); + } + + public static void executeReturnToHub(@Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull Store store) { + World parentWorld = findParentHubWorld(store, ref); + if (parentWorld != null) { + CreativeHubWorldConfig hubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig()); + if (hubConfig != null && hubConfig.getStartupInstance() != null) { + World world = store.getExternalData().getWorld(); + World currentHub = CreativeHubPlugin.get().getActiveHubInstance(parentWorld); + if (!world.equals(currentHub)) { + ISpawnProvider spawnProvider = parentWorld.getWorldConfig().getSpawnProvider(); + Transform returnPoint = spawnProvider != null ? spawnProvider.getSpawnPoint(parentWorld, playerRef.getUuid()) : new Transform(); + World hubInstance = CreativeHubPlugin.get().getOrSpawnHubInstance(parentWorld, hubConfig, returnPoint); + InstancesPlugin.teleportPlayerToInstance(ref, store, hubInstance, null); + } + } + } + } + + @Nullable + private static World findParentHubWorld(@Nonnull Store store, @Nonnull Ref ref) { + CreativeHubEntityConfig hubEntityConfig = store.getComponent(ref, CreativeHubEntityConfig.getComponentType()); + if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) { + World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid()); + if (parentWorld != null) { + CreativeHubWorldConfig hubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig()); + if (hubConfig != null && hubConfig.getStartupInstance() != null) { + return parentWorld; + } + } + } + + return null; + } +} diff --git a/src/com/hypixel/hytale/builtin/deployables/DeployablesPlugin.java b/src/com/hypixel/hytale/builtin/deployables/DeployablesPlugin.java index 91349936..7e895017 100644 --- a/src/com/hypixel/hytale/builtin/deployables/DeployablesPlugin.java +++ b/src/com/hypixel/hytale/builtin/deployables/DeployablesPlugin.java @@ -25,6 +25,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 DeployablesPlugin extends JavaPlugin { private static DeployablesPlugin instance; @@ -33,7 +34,7 @@ public class DeployablesPlugin extends JavaPlugin { private ComponentType deployableProjectileShooterComponentType; private ComponentType deployableProjectileComponentType; - public DeployablesPlugin(JavaPluginInit init) { + public DeployablesPlugin(@Nonnull JavaPluginInit init) { super(init); } diff --git a/src/com/hypixel/hytale/builtin/deployables/DeployablesUtils.java b/src/com/hypixel/hytale/builtin/deployables/DeployablesUtils.java index 4b066caf..87c92397 100644 --- a/src/com/hypixel/hytale/builtin/deployables/DeployablesUtils.java +++ b/src/com/hypixel/hytale/builtin/deployables/DeployablesUtils.java @@ -47,6 +47,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class DeployablesUtils { + @Nonnull private static final String DEPLOYABLE_MAX_STAT_MODIFIER = "DEPLOYABLE_MAX"; @Nonnull @@ -122,16 +123,18 @@ public class DeployablesUtils { int statIndex = EntityStatType.getAssetMap().getIndex(statEntry.getKey()); EntityStatValue stat = entityStatMapComponent.get(statIndex); if (stat != null) { - EntityStatType asset = EntityStatType.getAssetMap().getAsset(statIndex); - StaticModifier modifier = new StaticModifier( - Modifier.ModifierTarget.MAX, StaticModifier.CalculationType.ADDITIVE, statConfig.getMax() - asset.getMax() - ); - entityStatMapComponent.putModifier(statIndex, "DEPLOYABLE_MAX", modifier); - float initialValue = statConfig.getInitial(); - if (initialValue == Float.MAX_VALUE) { - entityStatMapComponent.maximizeStatValue(statIndex); - } else { - entityStatMapComponent.setStatValue(statIndex, initialValue); + EntityStatType statType = EntityStatType.getAssetMap().getAsset(statIndex); + if (statType != null) { + StaticModifier modifier = new StaticModifier( + Modifier.ModifierTarget.MAX, StaticModifier.CalculationType.ADDITIVE, statConfig.getMax() - statType.getMax() + ); + entityStatMapComponent.putModifier(statIndex, "DEPLOYABLE_MAX", modifier); + float initialValue = statConfig.getInitial(); + if (initialValue == Float.MAX_VALUE) { + entityStatMapComponent.maximizeStatValue(statIndex); + } else { + entityStatMapComponent.setStatValue(statIndex, initialValue); + } } } } diff --git a/src/com/hypixel/hytale/builtin/deployables/component/DeployableComponent.java b/src/com/hypixel/hytale/builtin/deployables/component/DeployableComponent.java index ccb639bc..98966570 100644 --- a/src/com/hypixel/hytale/builtin/deployables/component/DeployableComponent.java +++ b/src/com/hypixel/hytale/builtin/deployables/component/DeployableComponent.java @@ -17,6 +17,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class DeployableComponent implements Component { @Nonnull @@ -26,7 +27,8 @@ public class DeployableComponent implements Component { private UUID ownerUUID; private Instant spawnInstant; private float timeSinceLastAttack; - private Vector3f debugColor = null; + @Nullable + private Vector3f debugColor; private boolean firstTickRan; private String spawnFace; @@ -113,6 +115,7 @@ public class DeployableComponent implements Component { this.flags.put(key, value); } + @Nonnull public Vector3f getDebugColor() { if (this.debugColor == null) { ThreadLocalRandom random = ThreadLocalRandom.current(); diff --git a/src/com/hypixel/hytale/builtin/deployables/component/DeployableOwnerComponent.java b/src/com/hypixel/hytale/builtin/deployables/component/DeployableOwnerComponent.java index 3a373226..d48903a5 100644 --- a/src/com/hypixel/hytale/builtin/deployables/component/DeployableOwnerComponent.java +++ b/src/com/hypixel/hytale/builtin/deployables/component/DeployableOwnerComponent.java @@ -28,6 +28,7 @@ public class DeployableOwnerComponent implements Component { private final Object2IntMap deployableCountPerId = new Object2IntOpenHashMap<>(); @Nonnull private final List> deployablesForDestruction = new ObjectArrayList<>(); + @Nonnull private final List>> tempDestructionList = new ObjectArrayList<>(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/deployables/component/DeployableProjectileShooterComponent.java b/src/com/hypixel/hytale/builtin/deployables/component/DeployableProjectileShooterComponent.java index e56dab90..12659bde 100644 --- a/src/com/hypixel/hytale/builtin/deployables/component/DeployableProjectileShooterComponent.java +++ b/src/com/hypixel/hytale/builtin/deployables/component/DeployableProjectileShooterComponent.java @@ -14,7 +14,9 @@ import java.util.UUID; import javax.annotation.Nonnull; public class DeployableProjectileShooterComponent implements Component { + @Nonnull protected final List> projectiles = new ObjectArrayList<>(); + @Nonnull protected final List> projectilesForRemoval = new ObjectArrayList<>(); protected Ref activeTarget; @@ -33,10 +35,12 @@ public class DeployableProjectileShooterComponent implements Component {}); } + @Nonnull public List> getProjectiles() { return this.projectiles; } + @Nonnull public List> getProjectilesForRemoval() { return this.projectilesForRemoval; } diff --git a/src/com/hypixel/hytale/builtin/deployables/config/DeployableAoeConfig.java b/src/com/hypixel/hytale/builtin/deployables/config/DeployableAoeConfig.java index 76447299..c0a23e9f 100644 --- a/src/com/hypixel/hytale/builtin/deployables/config/DeployableAoeConfig.java +++ b/src/com/hypixel/hytale/builtin/deployables/config/DeployableAoeConfig.java @@ -26,8 +26,10 @@ import java.time.Duration; import java.time.Instant; import java.util.function.Consumer; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class DeployableAoeConfig extends DeployableConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DeployableAoeConfig.class, DeployableAoeConfig::new, DeployableConfig.BASE_CODEC ) @@ -119,6 +121,7 @@ public class DeployableAoeConfig extends DeployableConfig { protected boolean attackEnemies = true; protected DeployableAoeConfig.Shape shape = DeployableAoeConfig.Shape.Sphere; protected float height = 1.0F; + @Nullable protected DamageCause processedDamageCause; protected DeployableAoeConfig() { @@ -133,46 +136,49 @@ public class DeployableAoeConfig extends DeployableConfig { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - Vector3d position = archetypeChunk.getComponent(index, TransformComponent.getComponentType()).getPosition(); - World world = store.getExternalData().getWorld(); - Ref entityRef = archetypeChunk.getReferenceTo(index); - float radius = this.getRadius(store, deployableComponent.getSpawnInstant()); - this.handleDebugGraphics(world, deployableComponent.getDebugColor(), position, radius * 2.0F); - switch (deployableComponent.getFlag(DeployableComponent.DeployableFlag.STATE)) { - case 0: - deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 1); - break; - case 1: - deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 2); - playAnimation(store, entityRef, this, "Grow"); - break; - case 2: - if (radius >= this.endRadius) { - deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 3); - playAnimation(store, entityRef, this, "Looping"); - } - } + TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + if (transformComponent != null) { + Vector3d position = transformComponent.getPosition(); + World world = store.getExternalData().getWorld(); + Ref entityRef = archetypeChunk.getReferenceTo(index); + float radius = this.getRadius(store, deployableComponent.getSpawnInstant()); + this.handleDebugGraphics(world, deployableComponent.getDebugColor(), position, radius * 2.0F); + switch (deployableComponent.getFlag(DeployableComponent.DeployableFlag.STATE)) { + case 0: + deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 1); + break; + case 1: + deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 2); + playAnimation(store, entityRef, this, "Grow"); + break; + case 2: + if (radius >= this.endRadius) { + deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 3); + playAnimation(store, entityRef, this, "Looping"); + } + } - Ref deployableRef = archetypeChunk.getReferenceTo(index); - if (deployableComponent.incrementTimeSinceLastAttack(dt) > this.damageInterval) { - deployableComponent.setTimeSinceLastAttack(0.0F); - this.handleDetection(store, commandBuffer, deployableRef, deployableComponent, position, radius, DamageCause.PHYSICAL); - } + Ref deployableRef = archetypeChunk.getReferenceTo(index); + if (deployableComponent.incrementTimeSinceLastAttack(dt) > this.damageInterval) { + deployableComponent.setTimeSinceLastAttack(0.0F); + this.handleDetection(store, commandBuffer, deployableRef, deployableComponent, position, radius, DamageCause.PHYSICAL); + } - super.tick(deployableComponent, dt, index, archetypeChunk, store, commandBuffer); + super.tick(deployableComponent, dt, index, archetypeChunk, store, commandBuffer); + } } protected void handleDetection( - final Store store, - final CommandBuffer commandBuffer, - final Ref deployableRef, - DeployableComponent deployableComponent, - Vector3d position, + @Nonnull final Store store, + @Nonnull final CommandBuffer commandBuffer, + @Nonnull final Ref deployableRef, + @Nonnull DeployableComponent deployableComponent, + @Nonnull Vector3d position, float radius, - final DamageCause damageCause + @Nonnull final DamageCause damageCause ) { var attackConsumer = new Consumer>() { - public void accept(Ref entityStoreRef) { + public void accept(@Nonnull Ref entityStoreRef) { if (entityStoreRef != deployableRef) { DeployableAoeConfig.this.attackTarget(entityStoreRef, deployableRef, damageCause, commandBuffer); DeployableAoeConfig.this.applyEffectToTarget(store, entityStoreRef); @@ -198,7 +204,12 @@ public class DeployableAoeConfig extends DeployableConfig { } } - protected void attackTarget(Ref targetRef, Ref ownerRef, DamageCause damageCause, CommandBuffer commandBuffer) { + protected void attackTarget( + @Nonnull Ref targetRef, + @Nonnull Ref ownerRef, + @Nonnull DamageCause damageCause, + @Nonnull CommandBuffer commandBuffer + ) { if (!(this.damageAmount <= 0.0F)) { Damage damageEntry = new Damage(new Damage.EntitySource(ownerRef), damageCause, this.damageAmount); if (targetRef.equals(ownerRef)) { @@ -209,15 +220,15 @@ public class DeployableAoeConfig extends DeployableConfig { } } - protected void applyEffectToTarget(Store store, Ref targetRef) { + protected void applyEffectToTarget(@Nonnull Store store, @Nonnull Ref targetRef) { if (this.effectsToApply != null) { - EffectControllerComponent effectController = store.getComponent(targetRef, EffectControllerComponent.getComponentType()); - if (effectController != null) { + EffectControllerComponent effectControllerComponent = store.getComponent(targetRef, EffectControllerComponent.getComponentType()); + if (effectControllerComponent != null) { for (String effect : this.effectsToApply) { if (effect != null) { EntityEffect effectAsset = EntityEffect.getAssetMap().getAsset(effect); if (effectAsset != null) { - effectController.addEffect(targetRef, effectAsset, store); + effectControllerComponent.addEffect(targetRef, effectAsset, store); } } } @@ -225,12 +236,12 @@ public class DeployableAoeConfig extends DeployableConfig { } } - protected boolean canAttackEntity(Ref target, DeployableComponent deployable) { - boolean isOwner = target.equals(deployable.getOwner()); + protected boolean canAttackEntity(@Nonnull Ref targetRef, @Nonnull DeployableComponent deployable) { + boolean isOwner = targetRef.equals(deployable.getOwner()); return !isOwner || this.attackOwner; } - protected float getRadius(Store store, Instant startInstant) { + protected float getRadius(@Nonnull Store store, @Nonnull Instant startInstant) { if (!(this.radiusChangeTime <= 0.0F) && !(this.endRadius < 0.0F)) { float radiusDiff = this.endRadius - this.startRadius; float increment = radiusDiff / this.radiusChangeTime; @@ -247,6 +258,7 @@ public class DeployableAoeConfig extends DeployableConfig { } } + @Nullable protected DamageCause getDamageCause() { if (this.processedDamageCause == null) { this.processedDamageCause = DamageCause.getAssetMap().getAsset(this.damageCause); diff --git a/src/com/hypixel/hytale/builtin/deployables/config/DeployableConfig.java b/src/com/hypixel/hytale/builtin/deployables/config/DeployableConfig.java index 32acdc59..e9cd1cf7 100644 --- a/src/com/hypixel/hytale/builtin/deployables/config/DeployableConfig.java +++ b/src/com/hypixel/hytale/builtin/deployables/config/DeployableConfig.java @@ -27,7 +27,9 @@ import java.util.Map; import javax.annotation.Nonnull; public abstract class DeployableConfig implements NetworkSerializable { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(DeployableConfig.class) .appendInherited(new KeyedCodec<>("Id", Codec.STRING), (o, i) -> o.id = i, o -> o.id, (o, p) -> o.id = p.id) .documentation("Used to identify this deployable for uses such as MaxLiveCount") @@ -192,7 +194,7 @@ public abstract class DeployableConfig implements NetworkSerializable store, @Nonnull Ref ref, @Nonnull DeployableConfig config, @Nonnull String animationSetKey ) { - EntityStore externalData = store.getExternalData(); NetworkId networkIdComponent = store.getComponent(ref, NetworkId.getComponentType()); - DeployablesUtils.playAnimation(store, networkIdComponent.getId(), ref, config, AnimationSlot.Action, null, animationSetKey); + if (networkIdComponent != null) { + DeployablesUtils.playAnimation(store, networkIdComponent.getId(), ref, config, AnimationSlot.Action, null, animationSetKey); + } } protected static void stopAnimation(@Nonnull Store store, @Nonnull ArchetypeChunk archetypeChunk, int index) { - EntityStore externalData = store.getExternalData(); Ref ref = archetypeChunk.getReferenceTo(index); - if (ref != null && ref.isValid()) { + if (ref.isValid()) { NetworkId networkIdComponent = archetypeChunk.getComponent(index, NetworkId.getComponentType()); - DeployablesUtils.stopAnimation(store, networkIdComponent.getId(), ref, AnimationSlot.Action); + if (networkIdComponent != null) { + DeployablesUtils.stopAnimation(store, networkIdComponent.getId(), ref, AnimationSlot.Action); + } } } @@ -347,6 +351,7 @@ public abstract class DeployableConfig implements NetworkSerializable CODEC = BuilderCodec.builder( DeployableConfig.StatConfig.class, DeployableConfig.StatConfig::new ) diff --git a/src/com/hypixel/hytale/builtin/deployables/config/DeployableSpawner.java b/src/com/hypixel/hytale/builtin/deployables/config/DeployableSpawner.java index fce62376..e7a80d42 100644 --- a/src/com/hypixel/hytale/builtin/deployables/config/DeployableSpawner.java +++ b/src/com/hypixel/hytale/builtin/deployables/config/DeployableSpawner.java @@ -10,8 +10,10 @@ import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import com.hypixel.hytale.codec.validation.Validators; import com.hypixel.hytale.math.vector.Vector3d; +import javax.annotation.Nonnull; public class DeployableSpawner implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( DeployableSpawner.class, DeployableSpawner::new, Codec.STRING, (t, k) -> t.id = k, t -> t.id, (asset, data) -> asset.data = data, asset -> asset.data ) diff --git a/src/com/hypixel/hytale/builtin/deployables/config/DeployableTrapConfig.java b/src/com/hypixel/hytale/builtin/deployables/config/DeployableTrapConfig.java index 4b844338..ff63d7b4 100644 --- a/src/com/hypixel/hytale/builtin/deployables/config/DeployableTrapConfig.java +++ b/src/com/hypixel/hytale/builtin/deployables/config/DeployableTrapConfig.java @@ -24,6 +24,7 @@ import java.util.function.Consumer; import javax.annotation.Nonnull; public class DeployableTrapConfig extends DeployableAoeConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DeployableTrapConfig.class, DeployableTrapConfig::new, DeployableAoeConfig.CODEC ) @@ -62,66 +63,69 @@ public class DeployableTrapConfig extends DeployableAoeConfig { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - Vector3d pos = archetypeChunk.getComponent(index, TransformComponent.getComponentType()).getPosition(); - World world = store.getExternalData().getWorld(); - Ref entityRef = archetypeChunk.getReferenceTo(index); - if (!deployableComponent.getOwner().isValid()) { - world.execute(() -> { - if (entityRef.isValid()) { - DespawnComponent despawn = store.ensureAndGetComponent(entityRef, DespawnComponent.getComponentType()); - WorldTimeResource timeManager = commandBuffer.getResource(WorldTimeResource.getResourceType()); - despawn.setDespawn(timeManager.getGameTime()); - } - }); - } else { - float radius = this.getRadius(store, deployableComponent.getSpawnInstant()); - this.handleDebugGraphics(world, deployableComponent.getDebugColor(), pos, radius * 2.0F); - switch (deployableComponent.getFlag(DeployableComponent.DeployableFlag.STATE)) { - case 0: - deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 1); - break; - case 1: - deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 2); - playAnimation(store, entityRef, this, "Grow"); - break; - case 2: - if (radius >= this.endRadius) { - deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 3); - playAnimation(store, entityRef, this, "Looping"); + TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + if (transformComponent != null) { + Vector3d pos = transformComponent.getPosition(); + World world = store.getExternalData().getWorld(); + Ref entityRef = archetypeChunk.getReferenceTo(index); + if (!deployableComponent.getOwner().isValid()) { + world.execute(() -> { + if (entityRef.isValid()) { + DespawnComponent despawn = store.ensureAndGetComponent(entityRef, DespawnComponent.getComponentType()); + WorldTimeResource timeManager = commandBuffer.getResource(WorldTimeResource.getResourceType()); + despawn.setDespawn(timeManager.getGameTime()); } - } + }); + } else { + float radius = this.getRadius(store, deployableComponent.getSpawnInstant()); + this.handleDebugGraphics(world, deployableComponent.getDebugColor(), pos, radius * 2.0F); + switch (deployableComponent.getFlag(DeployableComponent.DeployableFlag.STATE)) { + case 0: + deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 1); + break; + case 1: + deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 2); + playAnimation(store, entityRef, this, "Grow"); + break; + case 2: + if (radius >= this.endRadius) { + deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 3); + playAnimation(store, entityRef, this, "Looping"); + } + } - Ref trapRef = archetypeChunk.getReferenceTo(index); - deployableComponent.setTimeSinceLastAttack(deployableComponent.getTimeSinceLastAttack() + dt); - if (deployableComponent.getTimeSinceLastAttack() > this.damageInterval && this.isLive(store, deployableComponent)) { - deployableComponent.setTimeSinceLastAttack(0.0F); - this.handleDetection(store, commandBuffer, trapRef, deployableComponent, pos, radius, DamageCause.PHYSICAL); + Ref trapRef = archetypeChunk.getReferenceTo(index); + deployableComponent.setTimeSinceLastAttack(deployableComponent.getTimeSinceLastAttack() + dt); + if (deployableComponent.getTimeSinceLastAttack() > this.damageInterval && this.isLive(store, deployableComponent)) { + deployableComponent.setTimeSinceLastAttack(0.0F); + this.handleDetection(store, commandBuffer, trapRef, deployableComponent, pos, radius, DamageCause.PHYSICAL); + } } } } @Override protected void handleDetection( - final Store store, - final CommandBuffer commandBuffer, - final Ref deployableRef, - final DeployableComponent deployableComponent, - Vector3d position, + @Nonnull final Store store, + @Nonnull final CommandBuffer commandBuffer, + @Nonnull final Ref deployableRef, + @Nonnull final DeployableComponent deployableComponent, + @Nonnull Vector3d position, float radius, - final DamageCause damageCause + @Nonnull final DamageCause damageCause ) { World world = store.getExternalData().getWorld(); var consumer = new Consumer>() { - public void accept(Ref entityStoreRef) { - if (entityStoreRef != deployableRef) { - if (store.getComponent(entityStoreRef, DeployableComponent.getComponentType()) == null) { - DeployableTrapConfig.this.attackTarget(entityStoreRef, deployableRef, damageCause, commandBuffer); + public void accept(@Nonnull Ref ref) { + if (ref != deployableRef) { + if (store.getComponent(ref, DeployableComponent.getComponentType()) == null) { + DeployableTrapConfig.this.attackTarget(ref, deployableRef, damageCause, commandBuffer); if (DeployableTrapConfig.this.destroyOnTriggered && deployableComponent.getFlag(DeployableComponent.DeployableFlag.TRIGGERED) == 0) { DeployableTrapConfig.this.onTriggered(store, deployableRef); deployableComponent.setFlag(DeployableComponent.DeployableFlag.TRIGGERED, 1); } - DeployableTrapConfig.this.applyEffectToTarget(store, entityStoreRef); + DeployableTrapConfig.this.applyEffectToTarget(store, ref); } } } diff --git a/src/com/hypixel/hytale/builtin/deployables/config/DeployableTrapSpawnerConfig.java b/src/com/hypixel/hytale/builtin/deployables/config/DeployableTrapSpawnerConfig.java index cfd70aae..11d9db74 100644 --- a/src/com/hypixel/hytale/builtin/deployables/config/DeployableTrapSpawnerConfig.java +++ b/src/com/hypixel/hytale/builtin/deployables/config/DeployableTrapSpawnerConfig.java @@ -23,6 +23,7 @@ import java.time.temporal.ChronoUnit; import javax.annotation.Nonnull; public class DeployableTrapSpawnerConfig extends DeployableTrapConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DeployableTrapSpawnerConfig.class, DeployableTrapSpawnerConfig::new, DeployableTrapConfig.CODEC ) @@ -85,7 +86,7 @@ public class DeployableTrapSpawnerConfig extends DeployableTrapConfig { playAnimation(store, entityRef, this, "Deploy"); } - private void tickDeployAnimationState(Store store, DeployableComponent component, Ref entityRef) { + private void tickDeployAnimationState(@Nonnull Store store, @Nonnull DeployableComponent component, @Nonnull Ref entityRef) { component.setFlag(DeployableComponent.DeployableFlag.STATE, 2); playAnimation(store, entityRef, this, "Deploy"); } @@ -102,34 +103,43 @@ public class DeployableTrapSpawnerConfig extends DeployableTrapConfig { @Nonnull Store store, @Nonnull DeployableComponent component, @Nonnull Ref entityRef, - CommandBuffer commandBuffer, + @Nonnull CommandBuffer commandBuffer, float dt ) { - Vector3d position = store.getComponent(entityRef, TransformComponent.getComponentType()).getPosition(); - float radius = this.getRadius(store, component.getSpawnInstant()); - component.setTimeSinceLastAttack(component.getTimeSinceLastAttack() + dt); - if (component.getTimeSinceLastAttack() > this.damageInterval && this.isLive(store, component)) { - component.setTimeSinceLastAttack(0.0F); - this.handleDetection(store, commandBuffer, entityRef, component, position, radius, DamageCause.PHYSICAL); + TransformComponent transformComponent = store.getComponent(entityRef, TransformComponent.getComponentType()); + if (transformComponent != null) { + Vector3d position = transformComponent.getPosition(); + float radius = this.getRadius(store, component.getSpawnInstant()); + component.setTimeSinceLastAttack(component.getTimeSinceLastAttack() + dt); + if (component.getTimeSinceLastAttack() > this.damageInterval && this.isLive(store, component)) { + component.setTimeSinceLastAttack(0.0F); + this.handleDetection(store, commandBuffer, entityRef, component, position, radius, DamageCause.PHYSICAL); + } } } private void tickTriggeredState( - CommandBuffer commandBuffer, @Nonnull Store store, @Nonnull DeployableComponent component, @Nonnull Ref entityRef + @Nonnull CommandBuffer commandBuffer, + @Nonnull Store store, + @Nonnull DeployableComponent component, + @Nonnull Ref entityRef ) { - component.setFlag(DeployableComponent.DeployableFlag.STATE, 5); - Vector3d parentPosition = store.getComponent(entityRef, TransformComponent.getComponentType()).getPosition(); - Ref parentOwner = store.getComponent(entityRef, DeployableComponent.getComponentType()).getOwner(); - World world = store.getExternalData().getWorld(); - if (this.deployableSpawners != null) { - for (DeployableSpawner spawner : this.deployableSpawners) { - if (spawner != null) { - DeployableConfig config = spawner.getConfig(); - Vector3d[] positionOffsets = spawner.getPositionOffsets(); + TransformComponent transformComponent = store.getComponent(entityRef, TransformComponent.getComponentType()); + if (transformComponent != null) { + component.setFlag(DeployableComponent.DeployableFlag.STATE, 5); + Vector3d parentPosition = transformComponent.getPosition(); + Ref parentOwner = component.getOwner(); + World world = store.getExternalData().getWorld(); + if (this.deployableSpawners != null) { + for (DeployableSpawner spawner : this.deployableSpawners) { + if (spawner != null) { + DeployableConfig config = spawner.getConfig(); + Vector3d[] positionOffsets = spawner.getPositionOffsets(); - for (Vector3d offset : positionOffsets) { - Vector3f childPosition = Vector3d.add(parentPosition, offset).toVector3f(); - world.execute(() -> DeployablesUtils.spawnDeployable(commandBuffer, store, config, parentOwner, childPosition, new Vector3f(), "UP")); + for (Vector3d offset : positionOffsets) { + Vector3f childPosition = Vector3d.add(parentPosition, offset).toVector3f(); + world.execute(() -> DeployablesUtils.spawnDeployable(commandBuffer, store, config, parentOwner, childPosition, new Vector3f(), "UP")); + } } } } @@ -143,6 +153,9 @@ public class DeployableTrapSpawnerConfig extends DeployableTrapConfig { @Override protected void onTriggered(@Nonnull Store store, @Nonnull Ref ref) { - store.getComponent(ref, DeployableComponent.getComponentType()).setFlag(DeployableComponent.DeployableFlag.STATE, 4); + DeployableComponent deployableComponent = store.getComponent(ref, DeployableComponent.getComponentType()); + if (deployableComponent != null) { + deployableComponent.setFlag(DeployableComponent.DeployableFlag.STATE, 4); + } } } diff --git a/src/com/hypixel/hytale/builtin/deployables/config/DeployableTurretConfig.java b/src/com/hypixel/hytale/builtin/deployables/config/DeployableTurretConfig.java index 66838cd5..11b5577b 100644 --- a/src/com/hypixel/hytale/builtin/deployables/config/DeployableTurretConfig.java +++ b/src/com/hypixel/hytale/builtin/deployables/config/DeployableTurretConfig.java @@ -264,7 +264,10 @@ public class DeployableTurretConfig extends DeployableConfig { DeployableProjectileShooterComponent shooterComponent = store.getComponent(ref, DeployableProjectileShooterComponent.getComponentType()); Vector3d spawnPos = Vector3d.ZERO.clone(); if (this.projectileSpawnOffsets != null) { - spawnPos.add(this.projectileSpawnOffsets.get(component.getSpawnFace())); + Vector3d spawnOffset = this.projectileSpawnOffsets.get(component.getSpawnFace()); + if (spawnOffset != null) { + spawnPos.add(spawnOffset); + } } if (shooterComponent == null) { @@ -359,19 +362,24 @@ public class DeployableTurretConfig extends DeployableConfig { Vector3d rootPos = transformComponent.getPosition(); Vector3d projectileSpawnPos = Vector3d.ZERO.clone(); if (this.projectileSpawnOffsets != null) { - projectileSpawnPos = this.projectileSpawnOffsets.get(component.getSpawnFace()).clone(); + projectileSpawnPos = this.projectileSpawnOffsets.getOrDefault(component.getSpawnFace(), Vector3d.ZERO).clone(); } projectileSpawnPos.add(fwdDirection.clone().normalize()); projectileSpawnPos.add(rootPos); - UUID uuid = store.getComponent(ref, UUIDComponent.getComponentType()).getUuid(); - shooterComponent.spawnProjectile(ref, commandBuffer, this.projectileConfig, uuid, projectileSpawnPos, fwdDirection.clone()); + UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType()); + if (uuidComponent != null) { + UUID uuid = uuidComponent.getUuid(); + shooterComponent.spawnProjectile(ref, commandBuffer, this.projectileConfig, uuid, projectileSpawnPos, fwdDirection.clone()); + } + playAnimation(store, ref, this, "Shoot"); component.setTimeSinceLastAttack(0.0F); } } } + @Nonnull private Vector3d calculatedTargetPosition(@Nonnull Vector3d original) { return Vector3d.add(original.clone(), this.targetOffset); } @@ -411,8 +419,12 @@ public class DeployableTurretConfig extends DeployableConfig { return false; } else { BlockType blockType = BlockType.getAssetMap().getAsset(id); - BlockMaterial material = blockType.getMaterial(); - return material == BlockMaterial.Empty ? false : blockType.getOpacity() != Opacity.Transparent; + if (blockType == null) { + return false; + } else { + BlockMaterial material = blockType.getMaterial(); + return material != null && material != BlockMaterial.Empty ? blockType.getOpacity() != Opacity.Transparent : false; + } } }, attackerPos.x, attackerPos.y, attackerPos.z, direction.x, direction.y, direction.z, distance); if (blockPosition == null) { @@ -457,44 +469,46 @@ public class DeployableTurretConfig extends DeployableConfig { shooterComponent.getProjectilesForRemoval().add(projectileRef); } else { TransformComponent projTransformComponent = store.getComponent(projectileRef, TransformComponent.getComponentType()); - - assert projTransformComponent != null; - - Vector3d projPos = projTransformComponent.getPosition(); - AtomicReference hit = new AtomicReference<>(Boolean.FALSE); - DeployableProjectileComponent dProjComponent = store.getComponent(projectileRef, DeployableProjectileComponent.getComponentType()); - - assert dProjComponent != null; - - Vector3d prevPos = dProjComponent.getPreviousTickPosition(); - Vector3d increment = new Vector3d((projPos.x - prevPos.x) * 0.1F, (projPos.y - prevPos.y) * 0.1F, (projPos.z - prevPos.z) * 0.1F); - - for (int j = 0; j < 10; j++) { - if (!hit.get()) { - Vector3d scanPos = dProjComponent.getPreviousTickPosition().clone(); - scanPos.x = scanPos.x + increment.x * j; - scanPos.y = scanPos.y + increment.y * j; - scanPos.z = scanPos.z + increment.z * j; - if (this.getDebugVisuals()) { - DebugUtils.addSphere(store.getExternalData().getWorld(), scanPos, new Vector3f(1.0F, 1.0F, 1.0F), 0.1F, 5.0F); - } - - for (Ref targetEntityRef : TargetUtil.getAllEntitiesInSphere(scanPos, 0.1, store)) { - if (hit.get()) { - return; - } - - this.projectileHit(targetEntityRef, projectileRef, shooterComponent, store, commandBuffer); - hit.set(Boolean.TRUE); - } - } - } - - dProjComponent.setPreviousTickPosition(projPos); - if (!hit.get()) { - StandardPhysicsProvider physics = store.getComponent(projectileRef, StandardPhysicsProvider.getComponentType()); - if (physics != null && physics.getState() != StandardPhysicsProvider.STATE.ACTIVE) { + if (projTransformComponent == null) { + shooterComponent.getProjectilesForRemoval().add(projectileRef); + } else { + Vector3d projPos = projTransformComponent.getPosition(); + AtomicReference hit = new AtomicReference<>(Boolean.FALSE); + DeployableProjectileComponent deployableProjectileComponent = store.getComponent(projectileRef, DeployableProjectileComponent.getComponentType()); + if (deployableProjectileComponent == null) { shooterComponent.getProjectilesForRemoval().add(projectileRef); + } else { + Vector3d prevPos = deployableProjectileComponent.getPreviousTickPosition(); + Vector3d increment = new Vector3d((projPos.x - prevPos.x) * 0.1F, (projPos.y - prevPos.y) * 0.1F, (projPos.z - prevPos.z) * 0.1F); + + for (int j = 0; j < 10; j++) { + if (!hit.get()) { + Vector3d scanPos = deployableProjectileComponent.getPreviousTickPosition().clone(); + scanPos.x = scanPos.x + increment.x * j; + scanPos.y = scanPos.y + increment.y * j; + scanPos.z = scanPos.z + increment.z * j; + if (this.getDebugVisuals()) { + DebugUtils.addSphere(store.getExternalData().getWorld(), scanPos, new Vector3f(1.0F, 1.0F, 1.0F), 0.1F, 5.0F); + } + + for (Ref targetEntityRef : TargetUtil.getAllEntitiesInSphere(scanPos, 0.1, store)) { + if (hit.get()) { + return; + } + + this.projectileHit(targetEntityRef, projectileRef, shooterComponent, store, commandBuffer); + hit.set(Boolean.TRUE); + } + } + } + + deployableProjectileComponent.setPreviousTickPosition(projPos); + if (!hit.get()) { + StandardPhysicsProvider physicsComponent = store.getComponent(projectileRef, StandardPhysicsProvider.getComponentType()); + if (physicsComponent != null && physicsComponent.getState() != StandardPhysicsProvider.STATE.ACTIVE) { + shooterComponent.getProjectilesForRemoval().add(projectileRef); + } + } } } } @@ -541,6 +555,7 @@ public class DeployableTurretConfig extends DeployableConfig { knockbackComponent.setDuration(this.projectileKnockback.getDuration()); } + @Nonnull @Override public String toString() { return "DeployableTurretConfig{}" + super.toString(); diff --git a/src/com/hypixel/hytale/builtin/deployables/interaction/SpawnDeployableFromRaycastInteraction.java b/src/com/hypixel/hytale/builtin/deployables/interaction/SpawnDeployableFromRaycastInteraction.java index a64af8a8..214c031c 100644 --- a/src/com/hypixel/hytale/builtin/deployables/interaction/SpawnDeployableFromRaycastInteraction.java +++ b/src/com/hypixel/hytale/builtin/deployables/interaction/SpawnDeployableFromRaycastInteraction.java @@ -34,6 +34,7 @@ import it.unimi.dsi.fastutil.ints.Int2FloatMap.Entry; import it.unimi.dsi.fastutil.objects.Object2FloatMap; import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class SpawnDeployableFromRaycastInteraction extends SimpleInstantInteraction { @Nonnull @@ -62,6 +63,7 @@ public class SpawnDeployableFromRaycastInteraction extends SimpleInstantInteract .afterDecode(SpawnDeployableFromRaycastInteraction::processConfig) .build(); protected Object2FloatMap unknownEntityStats; + @Nullable protected Int2FloatMap entityStats; protected float maxPlacementDistance; private DeployableConfig config; diff --git a/src/com/hypixel/hytale/builtin/deployables/system/DeployablesSystem.java b/src/com/hypixel/hytale/builtin/deployables/system/DeployablesSystem.java index 15f1670f..61928edf 100644 --- a/src/com/hypixel/hytale/builtin/deployables/system/DeployablesSystem.java +++ b/src/com/hypixel/hytale/builtin/deployables/system/DeployablesSystem.java @@ -29,7 +29,9 @@ import it.unimi.dsi.fastutil.objects.ObjectList; import javax.annotation.Nonnull; public class DeployablesSystem { - private static void spawnParticleEffect(Ref sourceRef, CommandBuffer commandBuffer, Vector3d position, ModelParticle particle) { + private static void spawnParticleEffect( + @Nonnull Ref sourceRef, @Nonnull CommandBuffer commandBuffer, @Nonnull Vector3d position, @Nonnull ModelParticle particle + ) { Vector3f particlePositionOffset = particle.getPositionOffset(); Direction particleRotationOffset = particle.getRotationOffset(); Vector3d particlePosition = new Vector3d(position.x, position.y, position.z); @@ -66,8 +68,13 @@ public class DeployablesSystem { } @Override - public void tick(float dt, int index, ArchetypeChunk archetypeChunk, Store store, CommandBuffer commandBuffer) { + public void tick( + float dt, int index, ArchetypeChunk archetypeChunk, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { DeployableOwnerComponent deployableOwnerComponent = archetypeChunk.getComponent(index, DeployableOwnerComponent.getComponentType()); + + assert deployableOwnerComponent != null; + deployableOwnerComponent.tick(commandBuffer); } } @@ -79,7 +86,9 @@ public class DeployablesSystem { Ref ownerRef = deployableComponent.getOwner(); if (ownerRef != null && ownerRef.isValid()) { DeployableOwnerComponent deployableOwnerComponent = ownerRef.getStore().getComponent(ownerRef, DeployableOwnerComponent.getComponentType()); - deployableOwnerComponent.deRegisterDeployable(deployableConfig.getId(), ref); + if (deployableOwnerComponent != null) { + deployableOwnerComponent.deRegisterDeployable(deployableConfig.getId(), ref); + } } } @@ -93,24 +102,30 @@ public class DeployablesSystem { @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { DeployableComponent deployableComponent = store.getComponent(ref, DeployableComponent.getComponentType()); - DeployableConfig deployableConfig = deployableComponent.getConfig(); - Vector3d position = store.getComponent(ref, TransformComponent.getComponentType()).getPosition(); - Ref ownerRef = deployableComponent.getOwner(); - int soundIndex = deployableConfig.getDeploySoundEventIndex(); - SoundUtil.playSoundEvent3d(null, soundIndex, position, commandBuffer); - ModelParticle[] particles = deployableConfig.getSpawnParticles(); - if (particles != null) { - for (ModelParticle particle : particles) { - DeployablesSystem.spawnParticleEffect(ref, commandBuffer, position, particle); + + assert deployableComponent != null; + + TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); + if (transformComponent != null) { + DeployableConfig deployableConfig = deployableComponent.getConfig(); + Vector3d position = transformComponent.getPosition(); + Ref ownerRef = deployableComponent.getOwner(); + int soundIndex = deployableConfig.getDeploySoundEventIndex(); + SoundUtil.playSoundEvent3d(null, soundIndex, position, commandBuffer); + ModelParticle[] particles = deployableConfig.getSpawnParticles(); + if (particles != null) { + for (ModelParticle particle : particles) { + DeployablesSystem.spawnParticleEffect(ref, commandBuffer, position, particle); + } } - } - if (ownerRef.isValid()) { - DeployableOwnerComponent deployableOwnerComponent = ownerRef.getStore().getComponent(ownerRef, DeployableOwnerComponent.getComponentType()); + if (ownerRef.isValid()) { + DeployableOwnerComponent deployableOwnerComponent = ownerRef.getStore().getComponent(ownerRef, DeployableOwnerComponent.getComponentType()); - assert deployableOwnerComponent != null; + assert deployableOwnerComponent != null; - deployableOwnerComponent.registerDeployable(ownerRef, deployableComponent, deployableConfig.getId(), ref, store); + deployableOwnerComponent.registerDeployable(ownerRef, deployableComponent, deployableConfig.getId(), ref, store); + } } } @@ -119,8 +134,15 @@ public class DeployablesSystem { @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { DeployableComponent deployableComponent = store.getComponent(ref, DeployableComponent.getComponentType()); + + assert deployableComponent != null; + + TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); + + assert transformComponent != null; + DeployableConfig deployableConfig = deployableComponent.getConfig(); - Vector3d position = store.getComponent(ref, TransformComponent.getComponentType()).getPosition(); + Vector3d position = transformComponent.getPosition(); int despawnSoundIndex = deployableConfig.getDespawnSoundEventIndex(); int dieSoundIndex = deployableConfig.getDieSoundEventIndex(); if (dieSoundIndex != 0) { @@ -152,9 +174,14 @@ public class DeployablesSystem { } @Override - public void tick(float dt, int index, ArchetypeChunk archetypeChunk, Store store, CommandBuffer commandBuffer) { - DeployableComponent comp = archetypeChunk.getComponent(index, DeployableComponent.getComponentType()); - comp.tick(dt, index, archetypeChunk, store, commandBuffer); + public void tick( + float dt, int index, ArchetypeChunk archetypeChunk, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { + DeployableComponent deployableComponent = archetypeChunk.getComponent(index, DeployableComponent.getComponentType()); + + assert deployableComponent != null; + + deployableComponent.tick(dt, index, archetypeChunk, store, commandBuffer); } } } diff --git a/src/com/hypixel/hytale/builtin/fluid/FluidCommand.java b/src/com/hypixel/hytale/builtin/fluid/FluidCommand.java index 0d00c3d1..04858212 100644 --- a/src/com/hypixel/hytale/builtin/fluid/FluidCommand.java +++ b/src/com/hypixel/hytale/builtin/fluid/FluidCommand.java @@ -27,10 +27,11 @@ import com.hypixel.hytale.server.core.util.TargetUtil; import javax.annotation.Nonnull; public class FluidCommand extends AbstractCommandCollection { - private static final SingleArgumentType FLUID_ARG = new AssetArgumentType("Fluid", Fluid.class, ""); + @Nonnull + private static final SingleArgumentType FLUID_ARG = new AssetArgumentType("Fluid", Fluid.class, "server.commands.fluid.fluidArgType.desc"); 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()); @@ -42,10 +43,12 @@ public class FluidCommand extends AbstractCommandCollection { @Nonnull private static final Message MESSAGE_COMMANDS_NO_SECTION_COMPONENT = Message.translation("server.commands.noSectionComponent"); @Nonnull - private final OptionalArg targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION); + private final OptionalArg targetOffset = this.withOptionalArg( + "offset", "server.commands.fluid.get.offset.desc", ArgTypes.RELATIVE_BLOCK_POSITION + ); public GetCommand() { - super("get", "Gets the fluid at the target position"); + super("get", "server.commands.fluid.get.desc"); } @Override @@ -94,14 +97,16 @@ public class FluidCommand extends AbstractCommandCollection { @Nonnull private static final Message MESSAGE_COMMANDS_NO_SECTION_COMPONENT = Message.translation("server.commands.noSectionComponent"); @Nonnull - private final RequiredArg fluid = this.withRequiredArg("fluid", "", FluidCommand.FLUID_ARG); + private final RequiredArg fluid = this.withRequiredArg("fluid", "server.commands.fluid.set.fluid.desc", FluidCommand.FLUID_ARG); @Nonnull - private final RequiredArg level = this.withRequiredArg("level", "", ArgTypes.INTEGER); + private final RequiredArg level = this.withRequiredArg("level", "server.commands.fluid.set.level.desc", ArgTypes.INTEGER); @Nonnull - private final OptionalArg targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION); + private final OptionalArg targetOffset = this.withOptionalArg( + "offset", "server.commands.fluid.set.offset.desc", ArgTypes.RELATIVE_BLOCK_POSITION + ); public SetCommand() { - super("set", "Changes the fluid at the target position"); + super("set", "server.commands.fluid.set.desc"); } @Override @@ -163,16 +168,18 @@ public class FluidCommand extends AbstractCommandCollection { @Nonnull private static final Message MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_LOOKING_AT_BLOCK = Message.translation("server.commands.errors.playerNotLookingAtBlock"); @Nonnull - private final RequiredArg radius = this.withRequiredArg("radius", "", ArgTypes.INTEGER); + private final RequiredArg radius = this.withRequiredArg("radius", "server.commands.fluid.setradius.radius.desc", ArgTypes.INTEGER); @Nonnull - private final RequiredArg fluid = this.withRequiredArg("fluid", "", FluidCommand.FLUID_ARG); + private final RequiredArg fluid = this.withRequiredArg("fluid", "server.commands.fluid.setradius.fluid.desc", FluidCommand.FLUID_ARG); @Nonnull - private final RequiredArg level = this.withRequiredArg("level", "", ArgTypes.INTEGER); + private final RequiredArg level = this.withRequiredArg("level", "server.commands.fluid.setradius.level.desc", ArgTypes.INTEGER); @Nonnull - private final OptionalArg targetOffset = this.withOptionalArg("offset", "", ArgTypes.RELATIVE_BLOCK_POSITION); + private final OptionalArg targetOffset = this.withOptionalArg( + "offset", "server.commands.fluid.setradius.offset.desc", 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 @@ -209,38 +216,50 @@ public class FluidCommand extends AbstractCommandCollection { int maxCY = ChunkUtil.chunkCoordinate(maxY); int minCZ = ChunkUtil.chunkCoordinate(minZ); int maxCZ = ChunkUtil.chunkCoordinate(maxZ); - Integer finalLevel = level; + byte levelByteValue = level.byteValue(); for (int cx = minCX; cx <= maxCX; cx++) { for (int cz = minCZ; cz <= maxCZ; cz++) { - int relMinX = MathUtil.clamp(minX - ChunkUtil.minBlock(cx), 0, 32); - int relMaxX = MathUtil.clamp(maxX - ChunkUtil.minBlock(cx), 0, 32); - int relMinZ = MathUtil.clamp(minZ - ChunkUtil.minBlock(cz), 0, 32); - int relMaxZ = MathUtil.clamp(maxZ - ChunkUtil.minBlock(cz), 0, 32); + int minBlockX = ChunkUtil.minBlock(cx); + int minBlockZ = ChunkUtil.minBlock(cz); + int relMinX = MathUtil.clamp(minX - minBlockX, 0, 32); + int relMaxX = MathUtil.clamp(maxX - minBlockX, 0, 32); + int relMinZ = MathUtil.clamp(minZ - minBlockZ, 0, 32); + int relMaxZ = MathUtil.clamp(maxZ - minBlockZ, 0, 32); for (int cy = minCY; cy <= maxCY; cy++) { - chunkStore.getChunkSectionReferenceAsync(cx, cy, cz).thenAcceptAsync(section -> { - Store sectionStore = section.getStore(); - FluidSection fluidSection = sectionStore.getComponent((Ref)section, FluidSection.getComponentType()); - if (fluidSection != null) { - int relMinY = MathUtil.clamp(minY - ChunkUtil.minBlock(fluidSection.getY()), 0, 32); - int relMaxY = MathUtil.clamp(maxY - ChunkUtil.minBlock(fluidSection.getY()), 0, 32); - ChunkSection sectionComp = sectionStore.getComponent((Ref)section, ChunkSection.getComponentType()); - WorldChunk worldChunk = sectionStore.getComponent(sectionComp.getChunkColumnReference(), WorldChunk.getComponentType()); + chunkStore.getChunkSectionReferenceAsync(cx, cy, cz) + .thenAcceptAsync( + section -> { + Store sectionStore = section.getStore(); + FluidSection fluidSectionComponent = sectionStore.getComponent((Ref)section, FluidSection.getComponentType()); + if (fluidSectionComponent != null) { + ChunkSection chunkSectionComponent = sectionStore.getComponent((Ref)section, ChunkSection.getComponentType()); + if (chunkSectionComponent != null) { + WorldChunk worldChunkComponent = sectionStore.getComponent( + chunkSectionComponent.getChunkColumnReference(), WorldChunk.getComponentType() + ); + if (worldChunkComponent != null) { + int relMinY = MathUtil.clamp(minY - ChunkUtil.minBlock(fluidSectionComponent.getY()), 0, 32); + int relMaxY = MathUtil.clamp(maxY - ChunkUtil.minBlock(fluidSectionComponent.getY()), 0, 32); - for (int y = relMinY; y < relMaxY; y++) { - for (int z = relMinZ; z < relMaxZ; z++) { - for (int x = relMinX; x < relMaxX; x++) { - int index = ChunkUtil.indexBlock(x, y, z); - fluidSection.setFluid(index, fluid, finalLevel.byteValue()); - worldChunk.setTicking(pos.x, pos.y, pos.z, true); + for (int y = relMinY; y < relMaxY; y++) { + for (int z = relMinZ; z < relMaxZ; z++) { + for (int x = relMinX; x < relMaxX; x++) { + int blockIndex = ChunkUtil.indexBlock(x, y, z); + fluidSectionComponent.setFluid(blockIndex, fluid, levelByteValue); + worldChunkComponent.setTicking(pos.x, pos.y, pos.z, true); + } + } + } + + worldChunkComponent.markNeedsSaving(); + } } } - } - - worldChunk.markNeedsSaving(); - } - }, world); + }, + world + ); } } } diff --git a/src/com/hypixel/hytale/builtin/fluid/FluidPlugin.java b/src/com/hypixel/hytale/builtin/fluid/FluidPlugin.java index b1040165..693c9328 100644 --- a/src/com/hypixel/hytale/builtin/fluid/FluidPlugin.java +++ b/src/com/hypixel/hytale/builtin/fluid/FluidPlugin.java @@ -3,6 +3,8 @@ package com.hypixel.hytale.builtin.fluid; import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; import com.hypixel.hytale.codec.lookup.Priority; +import com.hypixel.hytale.component.ComponentRegistryProxy; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.event.EventPriority; import com.hypixel.hytale.logger.HytaleLogger; @@ -11,6 +13,7 @@ import com.hypixel.hytale.server.core.asset.type.blocktick.BlockTickStrategy; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.fluid.DefaultFluidTicker; import com.hypixel.hytale.server.core.asset.type.fluid.FiniteFluidTicker; +import com.hypixel.hytale.server.core.asset.type.fluid.FireFluidTicker; import com.hypixel.hytale.server.core.asset.type.fluid.Fluid; import com.hypixel.hytale.server.core.asset.type.fluid.FluidTicker; import com.hypixel.hytale.server.core.plugin.JavaPlugin; @@ -19,6 +22,7 @@ import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk; import com.hypixel.hytale.server.core.universe.world.chunk.ChunkColumn; import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection; +import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection; import com.hypixel.hytale.server.core.universe.world.chunk.section.FluidSection; import com.hypixel.hytale.server.core.universe.world.events.ChunkPreLoadProcessEvent; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; @@ -28,6 +32,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class FluidPlugin extends JavaPlugin { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); private static FluidPlugin instance; @@ -42,76 +47,93 @@ public class FluidPlugin extends JavaPlugin { @Override protected void setup() { + ComponentRegistryProxy chunkStoreRegistry = this.getChunkStoreRegistry(); FluidTicker.CODEC.register(Priority.DEFAULT, "Default", DefaultFluidTicker.class, DefaultFluidTicker.CODEC); + FluidTicker.CODEC.register("Fire", FireFluidTicker.class, FireFluidTicker.CODEC); FluidTicker.CODEC.register("Finite", FiniteFluidTicker.class, FiniteFluidTicker.CODEC); - this.getChunkStoreRegistry().registerSystem(new FluidSystems.EnsureFluidSection()); - this.getChunkStoreRegistry().registerSystem(new FluidSystems.MigrateFromColumn()); - this.getChunkStoreRegistry().registerSystem(new FluidSystems.SetupSection()); - this.getChunkStoreRegistry().registerSystem(new FluidSystems.LoadPacketGenerator()); - this.getChunkStoreRegistry().registerSystem(new FluidSystems.ReplicateChanges()); - this.getChunkStoreRegistry().registerSystem(new FluidSystems.Ticking()); + ComponentType chunkSectionComponentType = ChunkSection.getComponentType(); + ComponentType fluidSectionComponentType = FluidSection.getComponentType(); + ComponentType chunkColumnComponentType = ChunkColumn.getComponentType(); + ComponentType blockChunkComponentType = BlockChunk.getComponentType(); + ComponentType worldChunkComponentType = WorldChunk.getComponentType(); + chunkStoreRegistry.registerSystem(new FluidSystems.EnsureFluidSection(chunkSectionComponentType, fluidSectionComponentType)); + chunkStoreRegistry.registerSystem(new FluidSystems.MigrateFromColumn(chunkColumnComponentType, blockChunkComponentType, fluidSectionComponentType)); + chunkStoreRegistry.registerSystem(new FluidSystems.SetupSection(chunkSectionComponentType, fluidSectionComponentType)); + chunkStoreRegistry.registerSystem(new FluidSystems.LoadPacketGenerator(chunkColumnComponentType, fluidSectionComponentType)); + chunkStoreRegistry.registerSystem(new FluidSystems.ReplicateChanges(chunkSectionComponentType, fluidSectionComponentType, worldChunkComponentType)); + chunkStoreRegistry.registerSystem(new FluidSystems.Ticking(chunkSectionComponentType, fluidSectionComponentType, blockChunkComponentType)); this.getEventRegistry().registerGlobal(EventPriority.FIRST, ChunkPreLoadProcessEvent.class, FluidPlugin::onChunkPreProcess); this.getCommandRegistry().registerCommand(new FluidCommand()); } private static void onChunkPreProcess(@Nonnull ChunkPreLoadProcessEvent event) { if (event.isNewlyGenerated()) { - WorldChunk wc = event.getChunk(); + WorldChunk worldChunk = event.getChunk(); Holder holder = event.getHolder(); - ChunkColumn column = holder.getComponent(ChunkColumn.getComponentType()); - if (column != null) { - BlockChunk blockChunk = holder.getComponent(BlockChunk.getComponentType()); - if (blockChunk != null) { + ChunkColumn chunkColumnComponent = holder.getComponent(ChunkColumn.getComponentType()); + if (chunkColumnComponent != null) { + BlockChunk blockChunkComponent = holder.getComponent(BlockChunk.getComponentType()); + if (blockChunkComponent != null) { IndexedLookupTableAssetMap fluidMap = Fluid.getAssetMap(); BlockTypeAssetMap blockMap = BlockType.getAssetMap(); - Holder[] sections = column.getSectionHolders(); + Holder[] sections = chunkColumnComponent.getSectionHolders(); if (sections != null) { for (int i = 0; i < sections.length && i < 10; i++) { Holder section = sections[i]; - FluidSection fluid = section.getComponent(FluidSection.getComponentType()); - if (fluid != null && !fluid.isEmpty()) { - BlockSection blockSection = section.ensureAndGetComponent(BlockSection.getComponentType()); + FluidSection fluidSectionComponent = section.getComponent(FluidSection.getComponentType()); + if (fluidSectionComponent != null && !fluidSectionComponent.isEmpty()) { + BlockSection blockSectionComponent = section.ensureAndGetComponent(BlockSection.getComponentType()); for (int idx = 0; idx < 32768; idx++) { - int fluidId = fluid.getFluidId(idx); + int fluidId = fluidSectionComponent.getFluidId(idx); if (fluidId != 0) { Fluid fluidType = fluidMap.getAsset(fluidId); if (fluidType == null) { LOGGER.at(Level.WARNING) - .log("Invalid fluid found in chunk section: %d, %d %d with id %d", fluid.getX(), fluid.getY(), fluid.getZ(), fluid); - fluid.setFluid(idx, 0, (byte)0); + .log( + "Invalid fluid found in chunk section: %d, %d %d with id %d", + fluidSectionComponent.getX(), + fluidSectionComponent.getY(), + fluidSectionComponent.getZ(), + fluidSectionComponent + ); + fluidSectionComponent.setFluid(idx, 0, (byte)0); } else { FluidTicker ticker = fluidType.getTicker(); - if (FluidTicker.isSolid(blockMap.getAsset(blockSection.get(idx)))) { - fluid.setFluid(idx, 0, (byte)0); + if (FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(idx)))) { + fluidSectionComponent.setFluid(idx, 0, (byte)0); } else { if (!ticker.canDemote()) { - int x = ChunkUtil.minBlock(fluid.getX()) + ChunkUtil.xFromIndex(idx); - int y = ChunkUtil.minBlock(fluid.getY()) + ChunkUtil.yFromIndex(idx); - int z = ChunkUtil.minBlock(fluid.getZ()) + ChunkUtil.zFromIndex(idx); + int x = ChunkUtil.minBlock(fluidSectionComponent.getX()) + ChunkUtil.xFromIndex(idx); + int y = ChunkUtil.minBlock(fluidSectionComponent.getY()) + ChunkUtil.yFromIndex(idx); + int z = ChunkUtil.minBlock(fluidSectionComponent.getZ()) + ChunkUtil.zFromIndex(idx); boolean canSpread = ChunkUtil.isBorderBlock(x, z) - || fluid.getFluidId(x - 1, y, z) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x - 1, y, z))) - || fluid.getFluidId(x + 1, y, z) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x + 1, y, z))) - || fluid.getFluidId(x, y, z - 1) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x, y, z - 1))) - || fluid.getFluidId(x, y, z + 1) == 0 && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x, y, z + 1))); + || fluidSectionComponent.getFluidId(x - 1, y, z) != fluidId + && !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x - 1, y, z))) + || fluidSectionComponent.getFluidId(x + 1, y, z) != fluidId + && !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x + 1, y, z))) + || fluidSectionComponent.getFluidId(x, y, z - 1) != fluidId + && !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x, y, z - 1))) + || fluidSectionComponent.getFluidId(x, y, z + 1) != fluidId + && !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x, y, z + 1))); if (y > 0) { if (ChunkUtil.chunkCoordinate(y) == ChunkUtil.chunkCoordinate(y - 1)) { - canSpread |= fluid.getFluidId(x, y - 1, z) == 0 - && !FluidTicker.isSolid(blockMap.getAsset(blockSection.get(x, y - 1, z))); + canSpread |= fluidSectionComponent.getFluidId(x, y - 1, z) != fluidId + && !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x, y - 1, z))); } else { FluidSection fluidSection2 = sections[i - 1].getComponent(FluidSection.getComponentType()); - canSpread |= fluidSection2.getFluidId(x, y - 1, z) == 0 - && !FluidTicker.isSolid(blockMap.getAsset(blockChunk.getBlock(x, y - 1, z))); + canSpread |= fluidSection2.getFluidId(x, y - 1, z) != fluidId + && !FluidTicker.isSolid(blockMap.getAsset(blockChunkComponent.getBlock(x, y - 1, z))); } } if (!canSpread) { - blockSection.setTicking(idx, false); + blockSectionComponent.setTicking(idx, false); continue; } } - blockSection.setTicking(idx, true); + blockSectionComponent.setTicking(idx, true); } } } @@ -119,32 +141,32 @@ public class FluidPlugin extends JavaPlugin { } } - int tickingBlocks = blockChunk.getTickingBlocksCount(); + int tickingBlocks = blockChunkComponent.getTickingBlocksCount(); if (tickingBlocks != 0) { - FluidPlugin.PreprocesorAccessor accessor = new FluidPlugin.PreprocesorAccessor(wc, blockChunk, sections); + FluidPlugin.PreprocesorAccessor accessor = new FluidPlugin.PreprocesorAccessor(worldChunk, blockChunkComponent, sections); do { - blockChunk.preTick(Instant.MIN); + blockChunkComponent.preTick(Instant.MIN); for (int ix = 0; ix < sections.length; ix++) { Holder section = sections[ix]; - FluidSection fluidSection = section.getComponent(FluidSection.getComponentType()); - if (fluidSection != null && !fluidSection.isEmpty()) { - BlockSection blockSection = section.ensureAndGetComponent(BlockSection.getComponentType()); - fluidSection.preload(wc.getX(), ix, wc.getZ()); - accessor.blockSection = blockSection; - blockSection.forEachTicking( + FluidSection fluidSectionComponent = section.getComponent(FluidSection.getComponentType()); + if (fluidSectionComponent != null && !fluidSectionComponent.isEmpty()) { + BlockSection blockSectionComponent = section.ensureAndGetComponent(BlockSection.getComponentType()); + fluidSectionComponent.preload(worldChunk.getX(), ix, worldChunk.getZ()); + accessor.blockSection = blockSectionComponent; + blockSectionComponent.forEachTicking( accessor, - fluidSection, + fluidSectionComponent, ix, (preprocesorAccessor, fluidSection1, xx, yx, zx, block) -> { int fluidId = fluidSection1.getFluidId(xx, yx, zx); if (fluidId == 0) { return BlockTickStrategy.IGNORED; } else { - Fluid fluid = Fluid.getAssetMap().getAsset(fluidId); int blockX = fluidSection1.getX() << 5 | xx; int blockZ = fluidSection1.getZ() << 5 | zx; + Fluid fluid = Fluid.getAssetMap().getAsset(fluidId); return fluid.getTicker() .process( preprocesorAccessor.worldChunk.getWorld(), @@ -164,11 +186,11 @@ public class FluidPlugin extends JavaPlugin { } } - tickingBlocks = blockChunk.getTickingBlocksCount(); + tickingBlocks = blockChunkComponent.getTickingBlocksCount(); accessor.tick++; } while (tickingBlocks != 0 && accessor.tick <= 100L); - blockChunk.mergeTickingBlocks(); + blockChunkComponent.mergeTickingBlocks(); } } } @@ -177,13 +199,16 @@ public class FluidPlugin extends JavaPlugin { } public static class PreprocesorAccessor implements FluidTicker.Accessor { + @Nonnull private final WorldChunk worldChunk; + @Nonnull private final BlockChunk blockChunk; + @Nonnull private final Holder[] sections; public long tick; public BlockSection blockSection; - public PreprocesorAccessor(WorldChunk worldChunk, BlockChunk blockChunk, Holder[] sections) { + public PreprocesorAccessor(@Nonnull WorldChunk worldChunk, @Nonnull BlockChunk blockChunk, @Nonnull Holder[] sections) { this.worldChunk = worldChunk; this.blockChunk = blockChunk; this.sections = sections; diff --git a/src/com/hypixel/hytale/builtin/fluid/FluidState.java b/src/com/hypixel/hytale/builtin/fluid/FluidState.java index 8bc2fb6c..1b104862 100644 --- a/src/com/hypixel/hytale/builtin/fluid/FluidState.java +++ b/src/com/hypixel/hytale/builtin/fluid/FluidState.java @@ -7,6 +7,7 @@ import javax.annotation.Nonnull; public record FluidState(int fluidLevel, byte verticalFill) { public static int SOURCE_LEVEL = 0; public static final int FULL_LEVEL = 8; + @Nonnull public static final FluidState[] FLUID_STATES = generateFluidStates(8); public FluidState(int fluidLevel, int verticalFill) { diff --git a/src/com/hypixel/hytale/builtin/fluid/FluidSystems.java b/src/com/hypixel/hytale/builtin/fluid/FluidSystems.java index 58f91fd7..ab45517c 100644 --- a/src/com/hypixel/hytale/builtin/fluid/FluidSystems.java +++ b/src/com/hypixel/hytale/builtin/fluid/FluidSystems.java @@ -4,6 +4,7 @@ import com.hypixel.hytale.builtin.blocktick.system.ChunkBlockTickSystem; import com.hypixel.hytale.component.AddReason; import com.hypixel.hytale.component.ArchetypeChunk; import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.RemoveReason; @@ -18,7 +19,7 @@ import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.component.system.tick.RunWhenPausedSystem; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.util.ChunkUtil; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.world.ServerSetFluid; import com.hypixel.hytale.protocol.packets.world.ServerSetFluids; import com.hypixel.hytale.protocol.packets.world.SetFluidCmd; @@ -56,11 +57,20 @@ public class FluidSystems { public static class EnsureFluidSection extends HolderSystem { @Nonnull - private static final Query QUERY = Query.and(ChunkSection.getComponentType(), Query.not(FluidSection.getComponentType())); + private final ComponentType fluidSectionComponentType; + @Nonnull + private final Query query; + + public EnsureFluidSection( + @Nonnull ComponentType chunkSectionComponentType, @Nonnull ComponentType fluidSectionComponentType + ) { + this.fluidSectionComponentType = fluidSectionComponentType; + this.query = Query.and(chunkSectionComponentType, Query.not(fluidSectionComponentType)); + } @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - holder.addComponent(FluidSection.getComponentType(), new FluidSection()); + holder.addComponent(this.fluidSectionComponentType, new FluidSection()); } @Override @@ -70,7 +80,7 @@ public class FluidSystems { @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } @Nonnull @@ -81,20 +91,32 @@ public class FluidSystems { } public static class LoadPacketGenerator extends ChunkStore.LoadFuturePacketDataQuerySystem { + @Nonnull + private final ComponentType chunkColumnComponentType; + @Nonnull + private final ComponentType fluidSectionComponentType; + + public LoadPacketGenerator( + @Nonnull ComponentType chunkColumnComponentType, @Nonnull ComponentType fluidSectionComponentType + ) { + this.chunkColumnComponentType = chunkColumnComponentType; + this.fluidSectionComponentType = fluidSectionComponentType; + } + public void fetch( int index, @Nonnull ArchetypeChunk archetypeChunk, Store store, @Nonnull CommandBuffer commandBuffer, PlayerRef query, - @Nonnull List> results + @Nonnull List> results ) { - ChunkColumn chunkColumnComponent = archetypeChunk.getComponent(index, ChunkColumn.getComponentType()); + ChunkColumn chunkColumnComponent = archetypeChunk.getComponent(index, this.chunkColumnComponentType); assert chunkColumnComponent != null; for (Ref sectionRef : chunkColumnComponent.getSections()) { - FluidSection fluidSectionComponent = commandBuffer.getComponent(sectionRef, FluidSection.getComponentType()); + FluidSection fluidSectionComponent = commandBuffer.getComponent(sectionRef, this.fluidSectionComponentType); if (fluidSectionComponent != null) { results.add(fluidSectionComponent.getCachedPacket().exceptionally(throwable -> { if (throwable != null) { @@ -107,39 +129,59 @@ public class FluidSystems { } } + @Nonnull @Override public Query getQuery() { - return ChunkColumn.getComponentType(); + return this.chunkColumnComponentType; } } public static class MigrateFromColumn extends ChunkColumnMigrationSystem { @Nonnull - private final Query QUERY = Query.and(ChunkColumn.getComponentType(), BlockChunk.getComponentType()); + private final ComponentType chunkColumnComponentType; @Nonnull - private final Set> DEPENDENCIES = Set.of(new SystemDependency<>(Order.BEFORE, LegacyModule.MigrateLegacySections.class)); + private final ComponentType blockChunkComponentType; + @Nonnull + private final ComponentType fluidSectionComponentType; + @Nonnull + private final Query query; + @Nonnull + private final Set> dependencies = Set.of(new SystemDependency<>(Order.BEFORE, LegacyModule.MigrateLegacySections.class)); + + public MigrateFromColumn( + @Nonnull ComponentType chunkColumnComponentType, + @Nonnull ComponentType blockChunkComponentType, + @Nonnull ComponentType fluidSectionComponentType + ) { + this.chunkColumnComponentType = chunkColumnComponentType; + this.blockChunkComponentType = blockChunkComponentType; + this.fluidSectionComponentType = fluidSectionComponentType; + this.query = Query.and(chunkColumnComponentType, blockChunkComponentType); + } @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - ChunkColumn chunkColumnComponent = holder.getComponent(ChunkColumn.getComponentType()); + ChunkColumn chunkColumnComponent = holder.getComponent(this.chunkColumnComponentType); assert chunkColumnComponent != null; - BlockChunk blockChunkComponent = holder.getComponent(BlockChunk.getComponentType()); + BlockChunk blockChunkComponent = holder.getComponent(this.blockChunkComponentType); assert blockChunkComponent != null; Holder[] sections = chunkColumnComponent.getSectionHolders(); - BlockSection[] legacySections = blockChunkComponent.getMigratedSections(); - if (legacySections != null) { - for (int i = 0; i < sections.length; i++) { - Holder section = sections[i]; - BlockSection paletteSection = legacySections[i]; - if (section != null && paletteSection != null) { - FluidSection fluid = paletteSection.takeMigratedFluid(); - if (fluid != null) { - section.putComponent(FluidSection.getComponentType(), fluid); - blockChunkComponent.markNeedsSaving(); + if (sections != null) { + BlockSection[] legacySections = blockChunkComponent.getMigratedSections(); + if (legacySections != null) { + for (int i = 0; i < sections.length; i++) { + Holder section = sections[i]; + BlockSection paletteSection = legacySections[i]; + if (section != null && paletteSection != null) { + FluidSection fluid = paletteSection.takeMigratedFluid(); + if (fluid != null) { + section.putComponent(this.fluidSectionComponentType, fluid); + blockChunkComponent.markNeedsSaving(); + } } } } @@ -153,19 +195,36 @@ public class FluidSystems { @Nonnull @Override public Query getQuery() { - return this.QUERY; + return this.query; } @Nonnull @Override public Set> getDependencies() { - return this.DEPENDENCIES; + return this.dependencies; } } public static class ReplicateChanges extends EntityTickingSystem implements RunWhenPausedSystem { @Nonnull - private static final Query QUERY = Query.and(ChunkSection.getComponentType(), FluidSection.getComponentType()); + private final ComponentType chunkSectionComponentType; + @Nonnull + private final ComponentType fluidSectionComponentType; + @Nonnull + private final ComponentType worldChunkComponentType; + @Nonnull + private final Query query; + + public ReplicateChanges( + @Nonnull ComponentType chunkSectionComponentType, + @Nonnull ComponentType fluidSectionComponentType, + @Nonnull ComponentType worldChunkComponentType + ) { + this.chunkSectionComponentType = chunkSectionComponentType; + this.fluidSectionComponentType = fluidSectionComponentType; + this.worldChunkComponentType = worldChunkComponentType; + this.query = Query.and(chunkSectionComponentType, fluidSectionComponentType); + } @Override public boolean isParallel(int archetypeChunkSize, int taskCount) { @@ -180,18 +239,18 @@ public class FluidSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - FluidSection fluidSectionComponent = archetypeChunk.getComponent(index, FluidSection.getComponentType()); + FluidSection fluidSectionComponent = archetypeChunk.getComponent(index, this.fluidSectionComponentType); assert fluidSectionComponent != null; IntOpenHashSet changes = fluidSectionComponent.getAndClearChangedPositions(); if (!changes.isEmpty()) { - ChunkSection chunkSectionComponent = archetypeChunk.getComponent(index, ChunkSection.getComponentType()); + ChunkSection chunkSectionComponent = archetypeChunk.getComponent(index, this.chunkSectionComponentType); assert chunkSectionComponent != null; World world = commandBuffer.getExternalData().getWorld(); - WorldChunk worldChunkComponent = commandBuffer.getComponent(chunkSectionComponent.getChunkColumnReference(), WorldChunk.getComponentType()); + WorldChunk worldChunkComponent = commandBuffer.getComponent(chunkSectionComponent.getChunkColumnReference(), this.worldChunkComponentType); int sectionY = chunkSectionComponent.getY(); world.execute(() -> { if (worldChunkComponent != null && worldChunkComponent.getWorld() != null) { @@ -276,7 +335,7 @@ public class FluidSystems { @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } @Nonnull @@ -288,17 +347,29 @@ public class FluidSystems { public static class SetupSection extends HolderSystem { @Nonnull - private static final Query QUERY = Query.and(ChunkSection.getComponentType(), FluidSection.getComponentType()); + private final ComponentType chunkSectionComponentType; @Nonnull - private static final Set> DEPENDENCIES = Set.of(new SystemDependency<>(Order.AFTER, FluidSystems.MigrateFromColumn.class)); + private final ComponentType fluidSectionComponentType; + @Nonnull + private final Query query; + @Nonnull + private final Set> dependencies = Set.of(new SystemDependency<>(Order.AFTER, FluidSystems.MigrateFromColumn.class)); + + public SetupSection( + @Nonnull ComponentType chunkSectionComponentType, @Nonnull ComponentType fluidSectionComponentType + ) { + this.chunkSectionComponentType = chunkSectionComponentType; + this.fluidSectionComponentType = fluidSectionComponentType; + this.query = Query.and(chunkSectionComponentType, fluidSectionComponentType); + } @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - ChunkSection chunkSectionComponent = holder.getComponent(ChunkSection.getComponentType()); + ChunkSection chunkSectionComponent = holder.getComponent(this.chunkSectionComponentType); assert chunkSectionComponent != null; - FluidSection fluidSectionComponent = holder.getComponent(FluidSection.getComponentType()); + FluidSection fluidSectionComponent = holder.getComponent(this.fluidSectionComponentType); assert fluidSectionComponent != null; @@ -312,24 +383,41 @@ public class FluidSystems { @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } @Nonnull @Override public Set> getDependencies() { - return DEPENDENCIES; + return this.dependencies; } } public static class Ticking extends EntityTickingSystem { @Nonnull - private static final Query QUERY = Query.and(FluidSection.getComponentType(), ChunkSection.getComponentType()); + private final ComponentType chunkSectionComponentType; @Nonnull - private static final Set> DEPENDENCIES = Set.of( + private final ComponentType fluidSectionComponentType; + @Nonnull + private final ComponentType blockChunkComponentType; + @Nonnull + private final Query query; + @Nonnull + private final Set> dependencies = Set.of( new SystemDependency<>(Order.AFTER, ChunkBlockTickSystem.PreTick.class), new SystemDependency<>(Order.BEFORE, ChunkBlockTickSystem.Ticking.class) ); + public Ticking( + @Nonnull ComponentType chunkSectionComponentType, + @Nonnull ComponentType fluidSectionComponentType, + @Nonnull ComponentType blockChunkComponentType + ) { + this.chunkSectionComponentType = chunkSectionComponentType; + this.fluidSectionComponentType = fluidSectionComponentType; + this.blockChunkComponentType = blockChunkComponentType; + this.query = Query.and(fluidSectionComponentType, chunkSectionComponentType); + } + @Override public boolean isParallel(int archetypeChunkSize, int taskCount) { return EntityTickingSystem.useParallel(archetypeChunkSize, taskCount); @@ -343,36 +431,35 @@ public class FluidSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - ChunkSection chunkSectionComponent = archetypeChunk.getComponent(index, ChunkSection.getComponentType()); + ChunkSection chunkSectionComponent = archetypeChunk.getComponent(index, this.chunkSectionComponentType); assert chunkSectionComponent != null; - FluidSection fluidSectionComponent = archetypeChunk.getComponent(index, FluidSection.getComponentType()); + FluidSection fluidSectionComponent = archetypeChunk.getComponent(index, this.fluidSectionComponentType); assert fluidSectionComponent != null; Ref chunkRef = chunkSectionComponent.getChunkColumnReference(); - BlockChunk blockChunkComponent = commandBuffer.getComponent(chunkRef, BlockChunk.getComponentType()); - - assert blockChunkComponent != null; - - BlockSection blockSection = blockChunkComponent.getSectionAtIndex(fluidSectionComponent.getY()); - if (blockSection != null) { - if (blockSection.getTickingBlocksCountCopy() != 0) { - FluidTicker.CachedAccessor accessor = FluidTicker.CachedAccessor.of(commandBuffer, fluidSectionComponent, blockSection, 5); - blockSection.forEachTicking(accessor, commandBuffer, fluidSectionComponent.getY(), (accessor1, commandBuffer1, x, y, z, block) -> { - FluidSection fluidSection1 = accessor1.selfFluidSection; - BlockSection blockSection1 = accessor1.selfBlockSection; - int fluidId = fluidSection1.getFluidId(x, y, z); - if (fluidId == 0) { - return BlockTickStrategy.IGNORED; - } else { - Fluid fluid = Fluid.getAssetMap().getAsset(fluidId); - int blockX = fluidSection1.getX() << 5 | x; - int blockZ = fluidSection1.getZ() << 5 | z; - return fluid.getTicker().tick(commandBuffer1, accessor1, fluidSection1, blockSection1, fluid, fluidId, blockX, y, blockZ); - } - }); + BlockChunk blockChunkComponent = commandBuffer.getComponent(chunkRef, this.blockChunkComponentType); + if (blockChunkComponent != null) { + BlockSection blockSection = blockChunkComponent.getSectionAtIndex(fluidSectionComponent.getY()); + if (blockSection != null) { + if (blockSection.getTickingBlocksCountCopy() != 0) { + FluidTicker.CachedAccessor accessor = FluidTicker.CachedAccessor.of(commandBuffer, fluidSectionComponent, blockSection, 5); + blockSection.forEachTicking(accessor, commandBuffer, fluidSectionComponent.getY(), (accessor1, commandBuffer1, x, y, z, block) -> { + FluidSection fluidSection1 = accessor1.selfFluidSection; + BlockSection blockSection1 = accessor1.selfBlockSection; + int fluidId = fluidSection1.getFluidId(x, y, z); + if (fluidId == 0) { + return BlockTickStrategy.IGNORED; + } else { + int blockX = fluidSection1.getX() << 5 | x; + int blockZ = fluidSection1.getZ() << 5 | z; + Fluid fluid = Fluid.getAssetMap().getAsset(fluidId); + return fluid.getTicker().tick(commandBuffer1, accessor1, fluidSection1, blockSection1, fluid, fluidId, blockX, y, blockZ); + } + }); + } } } } @@ -380,13 +467,13 @@ public class FluidSystems { @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } @Nonnull @Override public Set> getDependencies() { - return DEPENDENCIES; + return this.dependencies; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/BlockMask.java b/src/com/hypixel/hytale/builtin/hytalegenerator/BlockMask.java index ba125386..e360558a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/BlockMask.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/BlockMask.java @@ -8,7 +8,9 @@ import javax.annotation.Nonnull; public class BlockMask { private MaterialSet skippedBlocks = new MaterialSet(); private MaterialSet defaultMask = new MaterialSet(); + @Nonnull private final List sourceBlocks = new ArrayList<>(0); + @Nonnull private final List destinationBlocks = new ArrayList<>(0); public boolean canPlace(@Nonnull Material material) { @@ -19,7 +21,7 @@ public class BlockMask { return !this.skippedBlocks.test(materialHash); } - public boolean canReplace(Material source, Material destination) { + public boolean canReplace(@Nonnull Material source, @Nonnull Material destination) { return this.canReplace(source.hashMaterialIds(), destination.hashMaterialIds()); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/FutureUtils.java b/src/com/hypixel/hytale/builtin/hytalegenerator/FutureUtils.java index 91be0d02..767cdb2b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/FutureUtils.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/FutureUtils.java @@ -5,6 +5,7 @@ import java.util.concurrent.CompletableFuture; import javax.annotation.Nonnull; public class FutureUtils { + @Nonnull public static CompletableFuture allOf(@Nonnull List> tasks) { return CompletableFuture.allOf(tasks.toArray(new CompletableFuture[tasks.size()])); } 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/LoggerUtil.java b/src/com/hypixel/hytale/builtin/hytalegenerator/LoggerUtil.java index f9be9a82..1774ab0b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/LoggerUtil.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/LoggerUtil.java @@ -5,6 +5,7 @@ import java.util.logging.Logger; import javax.annotation.Nonnull; public class LoggerUtil { + @Nonnull public static final String HYTALE_GENERATOR_NAME = "HytaleGenerator"; public static Logger getLogger() { @@ -22,4 +23,11 @@ public class LoggerUtil { msg = msg + ExceptionUtil.toStringWithStack(e); logger.severe(msg); } + + @Nonnull + public static String nsToMsDecimal(long ns) { + long ms = ns / 1000000L; + long decimal = (ns - ms * 1000000L) / 1000L; + return ms + "." + decimal; + } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/MaterialSet.java b/src/com/hypixel/hytale/builtin/hytalegenerator/MaterialSet.java index e820d53e..5bee90f2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/MaterialSet.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/MaterialSet.java @@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.ints.IntSets; import java.util.List; import java.util.function.Predicate; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class MaterialSet implements Predicate { private final boolean isInclusive; @@ -46,7 +47,7 @@ public class MaterialSet implements Predicate { } } - public boolean test(Material value) { + public boolean test(@Nullable Material value) { if (value == null) { return false; } else { 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..3a1c8346 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/ReusableList.java @@ -0,0 +1,59 @@ +package com.hypixel.hytale.builtin.hytalegenerator; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ReusableList { + @Nonnull + 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/AssetManager.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/AssetManager.java index 1c957445..290e091b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/AssetManager.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/AssetManager.java @@ -88,6 +88,7 @@ import com.hypixel.hytale.builtin.hytalegenerator.assets.density.VectorWarpDensi import com.hypixel.hytale.builtin.hytalegenerator.assets.density.XOverrideDensityAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.density.XValueDensityAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.density.YOverrideDensityAsset; +import com.hypixel.hytale.builtin.hytalegenerator.assets.density.YSampledDensityAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.density.YValueDensityAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.density.ZOverrideDensityAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.density.ZValueDensityAsset; @@ -110,6 +111,9 @@ import com.hypixel.hytale.builtin.hytalegenerator.assets.density.positions.retur import com.hypixel.hytale.builtin.hytalegenerator.assets.environmentproviders.ConstantEnvironmentProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.environmentproviders.DensityDelimitedEnvironmentProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.environmentproviders.EnvironmentProviderAsset; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.DecimalConstantsFrameworkAsset; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.FrameworkAsset; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.PositionsFrameworkAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.materialproviders.ConstantMaterialProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.materialproviders.DownwardDepthMaterialProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.materialproviders.DownwardSpaceMaterialProviderAsset; @@ -161,9 +165,11 @@ import com.hypixel.hytale.builtin.hytalegenerator.assets.pointgenerators.MeshPoi import com.hypixel.hytale.builtin.hytalegenerator.assets.pointgenerators.PointGeneratorAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.AnchorPositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.BaseHeightPositionProviderAsset; +import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.BoundPositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.CachedPositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.FieldFunctionOccurrencePositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.FieldFunctionPositionProviderAsset; +import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.FrameworkPositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.ImportedPositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.ListPositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.Mesh2DPositionProviderAsset; @@ -171,7 +177,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.Mesh3 import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.OffsetPositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.PositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.SimpleHorizontalPositionProviderAsset; -import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.SpherePositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.UnionPositionProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.propassignments.AssignmentsAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.propassignments.ConstantAssignmentsAsset; @@ -215,8 +220,6 @@ import com.hypixel.hytale.builtin.hytalegenerator.assets.vectorproviders.Importe import com.hypixel.hytale.builtin.hytalegenerator.assets.vectorproviders.VectorProviderAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.WorldStructureAsset; import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.basic.BasicWorldStructureAsset; -import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.mapcontentfield.BaseHeightContentFieldAsset; -import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.mapcontentfield.ContentFieldAsset; import com.hypixel.hytale.common.util.ExceptionUtil; import com.hypixel.hytale.event.EventRegistry; import com.hypixel.hytale.logger.HytaleLogger; @@ -264,7 +267,7 @@ public class AssetManager { for (BlockMaskAsset value : event.getLoadedAssets().values()) { this.blockMaskAssets.put(value.getId(), value); - this.logger.at(Level.FINE).log("Loaded BlockMask asset " + value.toString()); + this.logger.at(Level.FINE).log("Loaded BlockMask asset " + value); } this.triggerReloadListeners(); @@ -275,7 +278,7 @@ public class AssetManager { for (DensityAsset value : event.getLoadedAssets().values()) { this.densityAssets.put(value.getId(), value); - this.logger.at(Level.FINE).log("Loaded Density asset " + value.toString()); + this.logger.at(Level.FINE).log("Loaded Density asset " + value); } this.triggerReloadListeners(); @@ -462,7 +465,9 @@ public class AssetManager { DensityAsset.CODEC.register("Exported", ExportedDensityAsset.class, ExportedDensityAsset.CODEC); DensityAsset.CODEC.register("Terrain", TerrainDensityAsset.class, TerrainDensityAsset.CODEC); DensityAsset.CODEC.register("DistanceToBiomeEdge", DistanceToBiomeEdgeDensityAsset.class, DistanceToBiomeEdgeDensityAsset.CODEC); - ContentFieldAsset.CODEC.register("BaseHeight", BaseHeightContentFieldAsset.class, BaseHeightContentFieldAsset.CODEC); + DensityAsset.CODEC.register("YSampled", YSampledDensityAsset.class, YSampledDensityAsset.CODEC); + FrameworkAsset.CODEC.register("DecimalConstants", DecimalConstantsFrameworkAsset.class, DecimalConstantsFrameworkAsset.CODEC); + FrameworkAsset.CODEC.register("Positions", PositionsFrameworkAsset.class, PositionsFrameworkAsset.CODEC); TerrainAsset.CODEC.register("DAOTerrain", DensityTerrainAsset.class, DensityTerrainAsset.CODEC); NoiseAsset.CODEC.register("Simplex", SimplexNoiseAsset.class, SimplexNoiseAsset.CODEC); NoiseAsset.CODEC.register("Cell", CellNoiseAsset.class, CellNoiseAsset.CODEC); @@ -505,7 +510,8 @@ public class AssetManager { PositionProviderAsset.CODEC.register("BaseHeight", BaseHeightPositionProviderAsset.class, BaseHeightPositionProviderAsset.CODEC); PositionProviderAsset.CODEC.register("Imported", ImportedPositionProviderAsset.class, ImportedPositionProviderAsset.CODEC); PositionProviderAsset.CODEC.register("Anchor", AnchorPositionProviderAsset.class, AnchorPositionProviderAsset.CODEC); - PositionProviderAsset.CODEC.register("Sphere", SpherePositionProviderAsset.class, SpherePositionProviderAsset.CODEC); + PositionProviderAsset.CODEC.register("Bound", BoundPositionProviderAsset.class, BoundPositionProviderAsset.CODEC); + PositionProviderAsset.CODEC.register("Framework", FrameworkPositionProviderAsset.class, FrameworkPositionProviderAsset.CODEC); PointGeneratorAsset.CODEC.register("Mesh", MeshPointGeneratorAsset.class, MeshPointGeneratorAsset.CODEC); AssignmentsAsset.CODEC.register("FieldFunction", FieldFunctionAssignmentsAsset.class, FieldFunctionAssignmentsAsset.CODEC); AssignmentsAsset.CODEC.register("Sandwich", SandwichAssignmentsAsset.class, SandwichAssignmentsAsset.CODEC); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/SettingsAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/SettingsAsset.java index 637118f5..7d2c46a6 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/SettingsAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/SettingsAsset.java @@ -12,6 +12,7 @@ import java.util.List; import javax.annotation.Nonnull; public class SettingsAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( SettingsAsset.class, SettingsAsset::new, 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..50ababd0 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; @@ -39,8 +39,10 @@ import com.hypixel.hytale.codec.validation.ValidatorCache; import javax.annotation.Nonnull; public class BiomeAsset implements JsonAssetWithMap>, Cleanable { + @Nonnull public static final ValidatorCache VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(BiomeAsset::getAssetStore)); private static AssetStore> STORE; + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( BiomeAsset.class, BiomeAsset::new, @@ -95,6 +97,7 @@ public class BiomeAsset implements JsonAssetWithMap> getAssetStore() { if (STORE == null) { STORE = AssetRegistry.getAssetStore(BiomeAsset.class); @@ -123,28 +126,29 @@ public class BiomeAsset implements JsonAssetWithMap materialProvider = this.materialProviderAsset - .build(new MaterialProviderAsset.Argument(parentSeed, materialCache, referenceBundle, workerIndexer)); - Density density = this.terrainAsset.buildDensity(parentSeed, referenceBundle, workerIndexer); - EnvironmentProvider environments = EnvironmentProvider.noEnvironmentProvider(); + .build(new MaterialProviderAsset.Argument(parentSeed, materialCache, referenceBundle, workerId)); + Density density = this.terrainAsset.buildDensity(parentSeed, referenceBundle, workerId); + EnvironmentProvider provider = EnvironmentProvider.noEnvironmentProvider(); if (this.environmentProviderAsset != null) { - environments = this.environmentProviderAsset.build(new EnvironmentProviderAsset.Argument(parentSeed, materialCache, referenceBundle, workerIndexer)); + provider = this.environmentProviderAsset.build(new EnvironmentProviderAsset.Argument(parentSeed, materialCache, referenceBundle, workerId)); } 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, workerId)); } - SimpleBiomeType biome = new SimpleBiomeType(this.biomeName, density, materialProvider, environments, tints); + SimpleBiome biome = new SimpleBiome(this.biomeName, density, materialProvider, provider, 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, workerId); + Assignments distribution = fieldAsset.buildPropDistribution(parentSeed, materialCache, fieldAsset.getRuntime(), referenceBundle, workerId); PropField field = new PropField(fieldAsset.getRuntime(), distribution, positionProvider); biome.addPropFieldTo(field); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/blockmask/BlockMaskAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/blockmask/BlockMaskAsset.java index 084830ee..3a783ce0 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/blockmask/BlockMaskAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/blockmask/BlockMaskAsset.java @@ -18,7 +18,9 @@ import java.util.Map; import javax.annotation.Nonnull; public class BlockMaskAsset implements JsonAssetWithMap>, Cleanable { + @Nonnull private static final Map exportedNodes = new HashMap<>(); + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( BlockMaskAsset.class, BlockMaskAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/blockmask/BlockMaskEntryAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/blockmask/BlockMaskEntryAsset.java index f8f4bc04..d9cbef94 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/blockmask/BlockMaskEntryAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/blockmask/BlockMaskEntryAsset.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.codec.KeyedCodec; import javax.annotation.Nonnull; public class BlockMaskEntryAsset implements JsonAssetWithMap>, Cleanable { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( BlockMaskEntryAsset.class, BlockMaskEntryAsset::new, @@ -35,10 +36,12 @@ public class BlockMaskEntryAsset implements JsonAssetWithMap>, Cleanable { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( MaterialSetAsset.class, MaterialSetAsset::new, @@ -39,8 +41,9 @@ public class MaterialSetAsset implements JsonAssetWithMap materials = new ArrayList<>(this.materialAssets.length); + List materials = new ObjectArrayList<>(this.materialAssets.length); for (MaterialAsset materialAsset : this.materialAssets) { if (materialAsset != null) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/bounds/DecimalBounds3dAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/bounds/DecimalBounds3dAsset.java new file mode 100644 index 00000000..ff121b6e --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/bounds/DecimalBounds3dAsset.java @@ -0,0 +1,44 @@ +package com.hypixel.hytale.builtin.hytalegenerator.assets.bounds; + +import com.hypixel.hytale.assetstore.AssetExtraInfo; +import com.hypixel.hytale.assetstore.codec.AssetBuilderCodec; +import com.hypixel.hytale.assetstore.map.DefaultAssetMap; +import com.hypixel.hytale.assetstore.map.JsonAssetWithMap; +import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3d; +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.math.vector.Vector3d; +import javax.annotation.Nonnull; + +public class DecimalBounds3dAsset implements JsonAssetWithMap> { + @Nonnull + public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( + DecimalBounds3dAsset.class, + DecimalBounds3dAsset::new, + Codec.STRING, + (asset, id) -> asset.id = id, + config -> config.id, + (config, data) -> config.data = data, + config -> config.data + ) + .append(new KeyedCodec<>("PointA", Vector3d.CODEC, true), (t, value) -> t.pointA = value, t -> t.pointA) + .add() + .append(new KeyedCodec<>("PointB", Vector3d.CODEC, true), (t, value) -> t.pointB = value, t -> t.pointB) + .add() + .build(); + private String id; + private AssetExtraInfo.Data data; + private Vector3d pointA = new Vector3d(); + private Vector3d pointB = new Vector3d(); + + @Nonnull + public Bounds3d build() { + Bounds3d bounds = new Bounds3d(this.pointA, this.pointB); + bounds.correct(); + return bounds; + } + + public String getId() { + return this.id; + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/bounds/IntegerBounds3dAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/bounds/IntegerBounds3dAsset.java new file mode 100644 index 00000000..a18251ee --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/bounds/IntegerBounds3dAsset.java @@ -0,0 +1,44 @@ +package com.hypixel.hytale.builtin.hytalegenerator.assets.bounds; + +import com.hypixel.hytale.assetstore.AssetExtraInfo; +import com.hypixel.hytale.assetstore.codec.AssetBuilderCodec; +import com.hypixel.hytale.assetstore.map.DefaultAssetMap; +import com.hypixel.hytale.assetstore.map.JsonAssetWithMap; +import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i; +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.math.vector.Vector3i; +import javax.annotation.Nonnull; + +public class IntegerBounds3dAsset implements JsonAssetWithMap> { + @Nonnull + public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( + IntegerBounds3dAsset.class, + IntegerBounds3dAsset::new, + Codec.STRING, + (asset, id) -> asset.id = id, + config -> config.id, + (config, data) -> config.data = data, + config -> config.data + ) + .append(new KeyedCodec<>("PointA", Vector3i.CODEC, true), (t, value) -> t.pointA = value, t -> t.pointA) + .add() + .append(new KeyedCodec<>("PointB", Vector3i.CODEC, true), (t, value) -> t.pointB = value, t -> t.pointB) + .add() + .build(); + private String id; + private AssetExtraInfo.Data data; + private Vector3i pointA = new Vector3i(); + private Vector3i pointB = new Vector3i(); + + @Nonnull + public Bounds3i build() { + Bounds3i bounds = new Bounds3i(this.pointA, this.pointB); + bounds.correct(); + return bounds; + } + + public String getId() { + return this.id; + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/CeilingCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/CeilingCurveAsset.java index e37d9215..1a6337f1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/CeilingCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/CeilingCurveAsset.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class CeilingCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CeilingCurveAsset.class, CeilingCurveAsset::new, CurveAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curve", CurveAsset.CODEC, true), (t, k) -> t.curveAsset = k, k -> k.curveAsset) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ClampCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ClampCurveAsset.java index 516b5e58..d2ef9c67 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ClampCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ClampCurveAsset.java @@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class ClampCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ClampCurveAsset.class, ClampCurveAsset::new, CurveAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curve", CurveAsset.CODEC, false), (t, k) -> t.curveAsset = k, k -> k.curveAsset) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ConstantCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ConstantCurveAsset.java index fafeb95b..6e5f08c3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ConstantCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ConstantCurveAsset.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class ConstantCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ConstantCurveAsset.class, ConstantCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/CurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/CurveAsset.java index c287d03f..5ad424ba 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/CurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/CurveAsset.java @@ -17,13 +17,19 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class CurveAsset implements JsonAssetWithMap>, Cleanable { + @Nonnull private static final CurveAsset[] EMPTY_INPUTS = new CurveAsset[0]; + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(CurveAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(CurveAsset.class) .append(new KeyedCodec<>("ExportAs", Codec.STRING, false), (t, k) -> t.exportName = k, t -> t.exportName) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/DistanceExponentialCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/DistanceExponentialCurveAsset.java index d2bf961d..a5787a8d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/DistanceExponentialCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/DistanceExponentialCurveAsset.java @@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class DistanceExponentialCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DistanceExponentialCurveAsset.class, DistanceExponentialCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/DistanceSCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/DistanceSCurveAsset.java index 030563c6..db831709 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/DistanceSCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/DistanceSCurveAsset.java @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class DistanceSCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DistanceSCurveAsset.class, DistanceSCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/FloorCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/FloorCurveAsset.java index a5e22c77..2992fa63 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/FloorCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/FloorCurveAsset.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class FloorCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(FloorCurveAsset.class, FloorCurveAsset::new, CurveAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curve", CurveAsset.CODEC, true), (t, k) -> t.curveAsset = k, k -> k.curveAsset) .add() @@ -14,7 +15,7 @@ public class FloorCurveAsset extends CurveAsset { .add() .build(); private CurveAsset curveAsset = new ConstantCurveAsset(); - private double limit = 0.0; + private double limit; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ImportedCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ImportedCurveAsset.java index 2e37c435..ea19f99a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ImportedCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/ImportedCurveAsset.java @@ -5,8 +5,10 @@ import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.logger.HytaleLogger; import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; +import javax.annotation.Nonnull; public class ImportedCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedCurveAsset.class, ImportedCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/InverterCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/InverterCurveAsset.java index 0853e163..4317c476 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/InverterCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/InverterCurveAsset.java @@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class InverterCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( InverterCurveAsset.class, InverterCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MaxCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MaxCurveAsset.java index 0771e4ee..0f272a4b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MaxCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MaxCurveAsset.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class MaxCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(MaxCurveAsset.class, MaxCurveAsset::new, CurveAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curves", new ArrayCodec<>(CurveAsset.CODEC, CurveAsset[]::new), true), (t, k) -> t.curveAssets = k, k -> k.curveAssets) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MinCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MinCurveAsset.java index fb0f1618..15089aa5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MinCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MinCurveAsset.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class MinCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(MinCurveAsset.class, MinCurveAsset::new, CurveAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curves", new ArrayCodec<>(CurveAsset.CODEC, CurveAsset[]::new), true), (t, k) -> t.curveAssets = k, k -> k.curveAssets) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MultiplierCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MultiplierCurveAsset.java index c691c0dd..22c3b2c5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MultiplierCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/MultiplierCurveAsset.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class MultiplierCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MultiplierCurveAsset.class, MultiplierCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/NotCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/NotCurveAsset.java index 87c94758..4af29b8c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/NotCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/NotCurveAsset.java @@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class NotCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(NotCurveAsset.class, NotCurveAsset::new, CurveAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curve", CurveAsset.CODEC, true), (t, k) -> t.curveAsset = k, k -> k.curveAsset) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothCeilingCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothCeilingCurveAsset.java index 0a2db0b2..81dfe0a3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothCeilingCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothCeilingCurveAsset.java @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class SmoothCeilingCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothCeilingCurveAsset.class, SmoothCeilingCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothClampCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothClampCurveAsset.java index 8681225c..960e03b9 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothClampCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothClampCurveAsset.java @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class SmoothClampCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothClampCurveAsset.class, SmoothClampCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothFloorCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothFloorCurveAsset.java index f550c72b..58df3e9d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothFloorCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothFloorCurveAsset.java @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class SmoothFloorCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothFloorCurveAsset.class, SmoothFloorCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothMaxCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothMaxCurveAsset.java index adc71a68..d6970f63 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothMaxCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothMaxCurveAsset.java @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class SmoothMaxCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothMaxCurveAsset.class, SmoothMaxCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothMinCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothMinCurveAsset.java index 8e7245c0..8f34fd38 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothMinCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SmoothMinCurveAsset.java @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class SmoothMinCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothMinCurveAsset.class, SmoothMinCurveAsset::new, CurveAsset.ABSTRACT_CODEC ) @@ -22,7 +23,7 @@ public class SmoothMinCurveAsset extends CurveAsset { .build(); private CurveAsset curveAAsset = new ConstantCurveAsset(); private CurveAsset curveBAsset = new ConstantCurveAsset(); - private double range = 0.0; + private double range; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SumCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SumCurveAsset.java index c3fd5b1b..c3f47f06 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SumCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/SumCurveAsset.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class SumCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(SumCurveAsset.class, SumCurveAsset::new, CurveAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curves", new ArrayCodec<>(CurveAsset.CODEC, CurveAsset[]::new), true), (t, k) -> t.curveAssets = k, k -> k.curveAssets) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/legacy/NodeFunctionYOutAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/legacy/NodeFunctionYOutAsset.java index 6855ca23..5f793f87 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/legacy/NodeFunctionYOutAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/legacy/NodeFunctionYOutAsset.java @@ -15,6 +15,7 @@ import java.util.HashSet; import javax.annotation.Nonnull; public class NodeFunctionYOutAsset implements JsonAssetWithMap>, Cleanable { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( NodeFunctionYOutAsset.class, NodeFunctionYOutAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/legacy/PointYOutAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/legacy/PointYOutAsset.java index ad53d432..598376b8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/legacy/PointYOutAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/legacy/PointYOutAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.math.vector.Vector2d; import javax.annotation.Nonnull; public class PointYOutAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( PointYOutAsset.class, PointYOutAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/manual/ManualCurveAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/manual/ManualCurveAsset.java index 80c003ca..1746e803 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/manual/ManualCurveAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/manual/ManualCurveAsset.java @@ -12,6 +12,7 @@ import java.util.HashSet; import javax.annotation.Nonnull; public class ManualCurveAsset extends CurveAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ManualCurveAsset.class, ManualCurveAsset::new, CurveAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Points", new ArrayCodec<>(PointInOutAsset.CODEC, PointInOutAsset[]::new), true), (t, k) -> t.nodes = k, t -> t.nodes) .addValidator((LegacyValidator)((v, r) -> { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/manual/PointInOutAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/manual/PointInOutAsset.java index 590c7653..6c8f710b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/manual/PointInOutAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/curves/manual/PointInOutAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.math.vector.Vector2d; import javax.annotation.Nonnull; public class PointInOutAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( PointInOutAsset.class, PointInOutAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/delimiters/RangeDoubleAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/delimiters/RangeDoubleAsset.java index 94068493..44306c9a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/delimiters/RangeDoubleAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/delimiters/RangeDoubleAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.KeyedCodec; import javax.annotation.Nonnull; public class RangeDoubleAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( RangeDoubleAsset.class, RangeDoubleAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/delimiters/RangeIntAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/delimiters/RangeIntAsset.java index 0c84417e..b22c6b08 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/delimiters/RangeIntAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/delimiters/RangeIntAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.KeyedCodec; import javax.annotation.Nonnull; public class RangeIntAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( RangeIntAsset.class, RangeIntAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AbsDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AbsDensityAsset.java index 7c2e4856..f5845234 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AbsDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AbsDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class AbsDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(AbsDensityAsset.class, AbsDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .build(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AmplitudeConstantAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AmplitudeConstantAsset.java index 478878dc..329bc2f9 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AmplitudeConstantAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AmplitudeConstantAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class AmplitudeConstantAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( AmplitudeConstantAsset.class, AmplitudeConstantAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AmplitudeDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AmplitudeDensityAsset.java index 4c488134..b5ef4d11 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AmplitudeDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AmplitudeDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class AmplitudeDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( AmplitudeDensityAsset.class, AmplitudeDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AnchorDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AnchorDensityAsset.java index cdd51a33..78fb9592 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AnchorDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AnchorDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class AnchorDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( AnchorDensityAsset.class, AnchorDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AngleDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AngleDensityAsset.java index 4346a227..a57ad559 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AngleDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AngleDensityAsset.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class AngleDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( AngleDensityAsset.class, AngleDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -29,7 +30,7 @@ public class AngleDensityAsset extends DensityAsset { .build(); private VectorProviderAsset vectorProviderAsset = new ConstantVectorProviderAsset(); private Vector3d vector = new Vector3d(); - private boolean isAxis = false; + private boolean isAxis; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AxisDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AxisDensityAsset.java index 64badebe..2783ca2f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AxisDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/AxisDensityAsset.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class AxisDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(AxisDensityAsset.class, AxisDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curve", CurveAsset.CODEC, true), (t, k) -> t.distanceCurveAsset = k, k -> k.distanceCurveAsset) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/BaseHeightDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/BaseHeightDensityAsset.java index 43fe0076..3e9770fe 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/BaseHeightDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/BaseHeightDensityAsset.java @@ -1,17 +1,16 @@ package com.hypixel.hytale.builtin.hytalegenerator.assets.density; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.DecimalConstantsFrameworkAsset; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.BaseHeightDensity; import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.ConstantValueDensity; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; -import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.BaseHeightReference; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; -import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class BaseHeightDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( BaseHeightDensityAsset.class, BaseHeightDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -29,16 +28,12 @@ public class BaseHeightDensityAsset extends DensityAsset { if (this.isSkipped()) { return new ConstantValueDensity(0.0); } else { - BaseHeightReference heightDataLayer = argument.referenceBundle.getLayerWithName(this.baseHeightName, BaseHeightReference.class); - if (heightDataLayer == null) { - HytaleLogger.getLogger() - .atConfig() - .log("Couldn't find height data layer with name \"" + this.baseHeightName + "\", using a zero-constant Density node."); - return new ConstantValueDensity(0.0); - } else { - BiDouble2DoubleFunction yFunction = heightDataLayer.getHeightFunction(); - return new BaseHeightDensity(yFunction, this.isDistance); + Double baseHeight = DecimalConstantsFrameworkAsset.Entries.get(this.baseHeightName, argument.referenceBundle); + if (baseHeight == null) { + baseHeight = 0.0; } + + return new BaseHeightDensity(baseHeight, this.isDistance); } } 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..c239853f 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 @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class Cache2dDensityAsset_Deprecated extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Cache2dDensityAsset_Deprecated.class, Cache2dDensityAsset_Deprecated::new, DensityAsset.ABSTRACT_CODEC ) @@ -27,7 +28,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..5cda38b3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CacheDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CacheDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class CacheDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CacheDensityAsset.class, CacheDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -27,8 +28,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/CeilingDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CeilingDensityAsset.java index 38a19189..0edce5e3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CeilingDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CeilingDensityAsset.java @@ -9,13 +9,14 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class CeilingDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CeilingDensityAsset.class, CeilingDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) .append(new KeyedCodec<>("Limit", Codec.DOUBLE, true), (t, k) -> t.limit = k, k -> k.limit) .add() .build(); - private double limit = 0.0; + private double limit; @Nonnull @Override 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..d464de50 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise2DDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise2DDensityAsset.java @@ -18,6 +18,7 @@ import javax.annotation.Nonnull; public class CellNoise2DDensityAsset extends DensityAsset { private static Set validCellTypes = new HashSet<>(); + @Nonnull public static final BuilderCodec CODEC; private double scaleX = 1.0; private double scaleZ = 1.0; @@ -35,7 +36,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/CellNoise3DDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise3DDensityAsset.java index 76c84793..e04d0825 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise3DDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellNoise3DDensityAsset.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class CellNoise3DDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CellNoise3DDensityAsset.class, CellNoise3DDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -43,6 +44,7 @@ public class CellNoise3DDensityAsset extends DensityAsset { private double jitter = 0.5; private int octaves = 1; private String seedKey = "A"; + @Nonnull private FastNoiseLite.CellularReturnType cellType = FastNoiseLite.CellularReturnType.CellValue; @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellWallDistanceDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellWallDistanceDensityAsset.java index 952ed0c2..0ae24f13 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellWallDistanceDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CellWallDistanceDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class CellWallDistanceDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CellWallDistanceDensityAsset.class, CellWallDistanceDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ClampDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ClampDensityAsset.java index 059fa0f8..e199d12f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ClampDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ClampDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ClampDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ClampDensityAsset.class, ClampDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -17,8 +18,8 @@ public class ClampDensityAsset extends DensityAsset { .append(new KeyedCodec<>("WallB", Codec.DOUBLE, true), (t, k) -> t.wallB = k, k -> k.wallB) .add() .build(); - private double wallA = 0.0; - private double wallB = 0.0; + private double wallA; + private double wallB; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ConstantDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ConstantDensityAsset.java index a17ef09a..9a3022f5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ConstantDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ConstantDensityAsset.java @@ -8,13 +8,14 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ConstantDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ConstantDensityAsset.class, ConstantDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) .append(new KeyedCodec<>("Value", Codec.DOUBLE, true), (t, k) -> t.value = k, k -> k.value) .add() .build(); - private double value = 0.0; + private double value; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CubeDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CubeDensityAsset.java index 04b9ee17..1b952b48 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CubeDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CubeDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class CubeDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CubeDensityAsset.class, CubeDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Curve", CurveAsset.CODEC, false), (t, k) -> t.densityCurveAsset = k, k -> k.densityCurveAsset) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CuboidDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CuboidDensityAsset.java index bdd54f89..d190a8ea 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CuboidDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CuboidDensityAsset.java @@ -15,6 +15,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class CuboidDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CuboidDensityAsset.class, CuboidDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -40,7 +41,7 @@ public class CuboidDensityAsset extends DensityAsset { private Vector3d scaleVector = new Vector3d(1.0, 1.0, 1.0); @Nonnull private Vector3d newYAxis = new Vector3d(0.0, 1.0, 0.0); - private double spinAngle = 0.0; + private double spinAngle; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CurveMapperDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CurveMapperDensityAsset.java index e07e33a9..c36cb548 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CurveMapperDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CurveMapperDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class CurveMapperDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CurveMapperDensityAsset.class, CurveMapperDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CylinderDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CylinderDensityAsset.java index 0efa8142..c1f6c731 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CylinderDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/CylinderDensityAsset.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class CylinderDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CylinderDensityAsset.class, CylinderDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -33,7 +34,7 @@ public class CylinderDensityAsset extends DensityAsset { private CurveAsset axialCurveAsset = new ConstantCurveAsset(); @Nonnull private Vector3d newYAxis = new Vector3d(0.0, 1.0, 0.0); - private double spinAngle = 0.0; + private double spinAngle; @Nonnull @Override 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..c1f611d4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DensityAsset.java @@ -32,13 +32,19 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class DensityAsset implements JsonAssetWithMap>, Cleanable { + @Nonnull private static final DensityAsset[] EMPTY_INPUTS = new DensityAsset[0]; + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(DensityAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(DensityAsset.class) .append(new KeyedCodec<>("Inputs", new ArrayCodec<>(CODEC, DensityAsset[]::new), true), (t, k) -> t.inputs = k, t -> t.inputs) .add() @@ -52,14 +58,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/DistanceDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DistanceDensityAsset.java index 2c020856..cbe9efa4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DistanceDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DistanceDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class DistanceDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DistanceDensityAsset.class, DistanceDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DistanceToBiomeEdgeDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DistanceToBiomeEdgeDensityAsset.java index 5a457aef..6be5ab58 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DistanceToBiomeEdgeDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/DistanceToBiomeEdgeDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class DistanceToBiomeEdgeDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DistanceToBiomeEdgeDensityAsset.class, DistanceToBiomeEdgeDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/EllipsoidDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/EllipsoidDensityAsset.java index 5a801edc..6afeb005 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/EllipsoidDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/EllipsoidDensityAsset.java @@ -15,6 +15,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class EllipsoidDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( EllipsoidDensityAsset.class, EllipsoidDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) 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..dea6b8e0 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ExportedDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ExportedDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ExportedDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ExportedDensityAsset.class, ExportedDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -26,12 +27,14 @@ 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) { + Density builtInstance = exported.threadInstances.get(argument.workerId); + if (builtInstance == null) { + builtInstance = this.firstInput().build(argument); + exported.threadInstances.put(argument.workerId, 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/FastGradientWarpDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/FastGradientWarpDensityAsset.java index c3099701..52c3fa19 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/FastGradientWarpDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/FastGradientWarpDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class FastGradientWarpDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( FastGradientWarpDensityAsset.class, FastGradientWarpDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/FloorDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/FloorDensityAsset.java index 26b6b43f..3bc0b12a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/FloorDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/FloorDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class FloorDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( FloorDensityAsset.class, FloorDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/GradientDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/GradientDensityAsset.java index 60241359..b5c2b666 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/GradientDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/GradientDensityAsset.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class GradientDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( GradientDensityAsset.class, GradientDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/GradientWarpDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/GradientWarpDensityAsset.java index b4710d76..52ae89a9 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/GradientWarpDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/GradientWarpDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class GradientWarpDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( GradientWarpDensityAsset.class, GradientWarpDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -25,8 +26,8 @@ public class GradientWarpDensityAsset extends DensityAsset { .build(); private double sampleRange = 1.0; private double warpFactor = 1.0; - private boolean is2d = false; - private double y2d = 0.0; + private boolean is2d; + private double y2d; @Nonnull @Override 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..f14a62b1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ImportedDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ImportedDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ImportedDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedDensityAsset.class, ImportedDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -23,18 +24,20 @@ 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) { + Density builtInstance = exported.threadInstances.get(argument.workerId); + if (builtInstance == null) { + builtInstance = exported.asset.build(argument); + exported.threadInstances.put(argument.workerId, 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/InverterDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/InverterDensityAsset.java index da48a5ff..7eef05b2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/InverterDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/InverterDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class InverterDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( InverterDensityAsset.class, InverterDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MaxDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MaxDensityAsset.java index ef39eefb..c47a30a9 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MaxDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MaxDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class MaxDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(MaxDensityAsset.class, MaxDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .build(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MinDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MinDensityAsset.java index 63d07145..33109b1b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MinDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MinDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class MinDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(MinDensityAsset.class, MinDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .build(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MixDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MixDensityAsset.java index 24505679..58918c58 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MixDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MixDensityAsset.java @@ -8,6 +8,7 @@ import java.util.List; import javax.annotation.Nonnull; public class MixDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(MixDensityAsset.class, MixDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .build(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MultiMixDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MultiMixDensityAsset.java index 9ed96159..ac09d7dc 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MultiMixDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MultiMixDensityAsset.java @@ -17,6 +17,7 @@ import java.util.List; import javax.annotation.Nonnull; public class MultiMixDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MultiMixDensityAsset.class, MultiMixDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -42,7 +43,7 @@ public class MultiMixDensityAsset extends DensityAsset { ArrayList keys = new ArrayList<>(this.keyAssets.length); for (MultiMixDensityAsset.KeyAsset keyAsset : this.keyAssets) { - if (keyAsset.densityIndex <= 0) { + if (keyAsset.densityIndex < 0) { keys.add(new MultiMixDensity.Key(keyAsset.value, null)); } else if (keyAsset.densityIndex >= densityInputs.size() - 1) { LoggerUtil.getLogger() @@ -108,6 +109,7 @@ public class MultiMixDensityAsset extends DensityAsset { public static class KeyAsset implements JsonAssetWithMap> { public static final int NO_DENSITY_INDEX = 0; + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( MultiMixDensityAsset.KeyAsset.class, MultiMixDensityAsset.KeyAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MultiplierDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MultiplierDensityAsset.java index 543b7c5c..7c8a09a4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MultiplierDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/MultiplierDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class MultiplierDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MultiplierDensityAsset.class, MultiplierDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/NormalizerDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/NormalizerDensityAsset.java index 86692c81..bfc1bc33 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/NormalizerDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/NormalizerDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class NormalizerDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( NormalizerDensityAsset.class, NormalizerDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -21,9 +22,9 @@ public class NormalizerDensityAsset extends DensityAsset { .append(new KeyedCodec<>("ToMax", Codec.DOUBLE, true), (t, k) -> t.toMax = k, k -> k.toMax) .add() .build(); - private double fromMin = 0.0; + private double fromMin; private double fromMax = 1.0; - private double toMin = 0.0; + private double toMin; private double toMax = 1.0; @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/OffsetConstantAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/OffsetConstantAsset.java index ba708991..5763e4aa 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/OffsetConstantAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/OffsetConstantAsset.java @@ -9,13 +9,14 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class OffsetConstantAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( OffsetConstantAsset.class, OffsetConstantAsset::new, DensityAsset.ABSTRACT_CODEC ) .append(new KeyedCodec<>("Value", Codec.DOUBLE, true), (t, k) -> t.value = k, t -> t.value) .add() .build(); - private double value = 0.0; + private double value; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/OffsetDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/OffsetDensityAsset.java index df72d7b7..41b497a4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/OffsetDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/OffsetDensityAsset.java @@ -9,12 +9,14 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class OffsetDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( OffsetDensityAsset.class, OffsetDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) .append(new KeyedCodec<>("FunctionForY", NodeFunctionYOutAsset.CODEC, true), (t, k) -> t.nodeFunctionYOutAsset = k, k -> k.nodeFunctionYOutAsset) .add() .build(); + @Nonnull private NodeFunctionYOutAsset nodeFunctionYOutAsset = new NodeFunctionYOutAsset(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PipelineDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PipelineDensityAsset.java index 854894cd..19e010ad 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PipelineDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PipelineDensityAsset.java @@ -8,7 +8,9 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import javax.annotation.Nonnull; public class PipelineDensityAsset extends DensityAsset { + @Nonnull private static final DensityAsset[] EMPTY_INPUTS = new DensityAsset[0]; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( PipelineDensityAsset.class, PipelineDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PlaneDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PlaneDensityAsset.java index 82f4336d..4b969f15 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PlaneDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PlaneDensityAsset.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class PlaneDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( PlaneDensityAsset.class, PlaneDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -30,7 +31,7 @@ public class PlaneDensityAsset extends DensityAsset { .build(); private CurveAsset distanceCurveAsset = new ConstantCurveAsset(); private Vector3d planeNormal = new Vector3d(0.0, 1.0, 0.0); - private boolean isAnchored = false; + private boolean isAnchored; @Nonnull @Override 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..affc699f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsPinchDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsPinchDensityAsset.java @@ -15,6 +15,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class PositionsPinchDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( PositionsPinchDensityAsset.class, PositionsPinchDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -38,10 +39,10 @@ public class PositionsPinchDensityAsset extends DensityAsset { .build(); private PositionProviderAsset positionProviderAsset = new ListPositionProviderAsset(); private CurveAsset pinchCurveAsset = new ConstantCurveAsset(); - private double maxDistance = 0.0; - private boolean normalizeDistance = false; - private boolean isHorizontal = false; - private double positionsMinY = 0.0; + private double maxDistance; + private boolean normalizeDistance; + private boolean isHorizontal; + private double positionsMinY; private double positionsMaxY = 1.0E-6; @Nonnull @@ -53,17 +54,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, argument.workerId)), 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, argument.workerId)), 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..55930075 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsTwistDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PositionsTwistDensityAsset.java @@ -15,6 +15,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class PositionsTwistDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( PositionsTwistDensityAsset.class, PositionsTwistDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -37,9 +38,9 @@ public class PositionsTwistDensityAsset extends DensityAsset { private PositionProviderAsset positionProviderAsset = new ListPositionProviderAsset(); private CurveAsset pinchCurveAsset = new ConstantCurveAsset(); private Vector3d twistAxis = new Vector3d(); - private double maxDistance = 0.0; - private boolean normalizeDistance = false; - private boolean zeroPositionsY = false; + private double maxDistance; + private boolean normalizeDistance; + private boolean zeroPositionsY; @Nonnull @Override @@ -48,7 +49,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, argument.workerId)), this.pinchCurveAsset.build(), this.twistAxis, this.maxDistance, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PowDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PowDensityAsset.java index d15a6aa4..94dddf63 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PowDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/PowDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class PowDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PowDensityAsset.class, PowDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Exponent", Codec.DOUBLE, true), (t, k) -> t.exponent = k, t -> t.exponent) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/RotatorDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/RotatorDensityAsset.java index 62f0cb68..64e6c303 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/RotatorDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/RotatorDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class RotatorDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( RotatorDensityAsset.class, RotatorDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -19,7 +20,7 @@ public class RotatorDensityAsset extends DensityAsset { .add() .build(); private Vector3d newYAxis = new Vector3d(); - private double spinAngle = 0.0; + private double spinAngle; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ScaleDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ScaleDensityAsset.java index 0aa2be63..25e976cb 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ScaleDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ScaleDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ScaleDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ScaleDensityAsset.class, ScaleDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SelectorDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SelectorDensityAsset.java index f22e282b..78a6cd9f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SelectorDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SelectorDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SelectorDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SelectorDensityAsset.class, SelectorDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ShellDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ShellDensityAsset.java index b95bb98e..21ca23d8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ShellDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ShellDensityAsset.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class ShellDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ShellDensityAsset.class, ShellDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -25,7 +26,7 @@ public class ShellDensityAsset extends DensityAsset { .add() .build(); private Vector3d axis = new Vector3d(0.0, 0.0, 0.0); - private boolean isMirrored = false; + private boolean isMirrored; private CurveAsset angleCurveAsset = new ConstantCurveAsset(); private CurveAsset distanceCurveAsset = new ConstantCurveAsset(); 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..51a2b8c3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise2dDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise2dDensityAsset.java @@ -14,6 +14,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SimplexNoise2dDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SimplexNoise2dDensityAsset.class, SimplexNoise2dDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -53,7 +54,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/SimplexNoise3DDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise3DDensityAsset.java index 6bd42354..1b43251b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise3DDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SimplexNoise3DDensityAsset.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SimplexNoise3DDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SimplexNoise3DDensityAsset.class, SimplexNoise3DDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SliderDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SliderDensityAsset.java index 0af5a8f2..2f93617d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SliderDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SliderDensityAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class SliderDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SliderDensityAsset.class, SliderDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothCeilingDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothCeilingDensityAsset.java index df625a6b..a34a62a4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothCeilingDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothCeilingDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SmoothCeilingDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothCeilingDensityAsset.class, SmoothCeilingDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -20,7 +21,7 @@ public class SmoothCeilingDensityAsset extends DensityAsset { .add() .build(); private double smoothRange = 1.0; - private double limit = 0.0; + private double limit; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothClampDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothClampDensityAsset.java index 29cfec0b..1b04d6dd 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothClampDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothClampDensityAsset.java @@ -11,6 +11,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SmoothClampDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothClampDensityAsset.class, SmoothClampDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothFloorDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothFloorDensityAsset.java index 0e5a82e4..3d15459a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothFloorDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothFloorDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SmoothFloorDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothFloorDensityAsset.class, SmoothFloorDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -20,7 +21,7 @@ public class SmoothFloorDensityAsset extends DensityAsset { .add() .build(); private double smoothRange = 1.0; - private double limit = 0.0; + private double limit; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothMaxDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothMaxDensityAsset.java index 3e9d78a7..0170e7db 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothMaxDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothMaxDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SmoothMaxDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothMaxDensityAsset.class, SmoothMaxDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothMinDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothMinDensityAsset.java index 4e27fcff..28f69833 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothMinDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SmoothMinDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SmoothMinDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmoothMinDensityAsset.class, SmoothMinDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SqrtDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SqrtDensityAsset.java index 97b4c950..9227565b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SqrtDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SqrtDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class SqrtDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(SqrtDensityAsset.class, SqrtDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .build(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SumDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SumDensityAsset.java index 1051b8fb..4371df54 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SumDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SumDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class SumDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(SumDensityAsset.class, SumDensityAsset::new, DensityAsset.ABSTRACT_CODEC) .build(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SwitchDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SwitchDensityAsset.java index 9eebbfb0..a12803f9 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SwitchDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SwitchDensityAsset.java @@ -17,6 +17,7 @@ import java.util.Objects; import javax.annotation.Nonnull; public class SwitchDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SwitchDensityAsset.class, SwitchDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -27,7 +28,9 @@ public class SwitchDensityAsset extends DensityAsset { ) .add() .build(); + @Nonnull public static final String DEFAULT_STATE = "Default"; + @Nonnull public static final int DEFAULT_STATE_HASH = 0; private SwitchDensityAsset.SwitchCaseAsset[] switchCaseAssets = new SwitchDensityAsset.SwitchCaseAsset[0]; @@ -68,6 +71,7 @@ public class SwitchDensityAsset extends DensityAsset { } public static class SwitchCaseAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( SwitchDensityAsset.SwitchCaseAsset.class, SwitchDensityAsset.SwitchCaseAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SwitchStateDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SwitchStateDensityAsset.java index 2c2d3ccd..c31c479c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SwitchStateDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/SwitchStateDensityAsset.java @@ -10,6 +10,7 @@ import java.util.Objects; import javax.annotation.Nonnull; public class SwitchStateDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SwitchStateDensityAsset.class, SwitchStateDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/TerrainDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/TerrainDensityAsset.java index 5dc50ec9..18fdfca5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/TerrainDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/TerrainDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class TerrainDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TerrainDensityAsset.class, TerrainDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/VectorWarpDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/VectorWarpDensityAsset.java index 7b23d639..9d01d1e7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/VectorWarpDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/VectorWarpDensityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class VectorWarpDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( VectorWarpDensityAsset.class, VectorWarpDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/XOverrideDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/XOverrideDensityAsset.java index add1fdd4..962dacf6 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/XOverrideDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/XOverrideDensityAsset.java @@ -9,13 +9,14 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class XOverrideDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( XOverrideDensityAsset.class, XOverrideDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) .append(new KeyedCodec<>("Value", Codec.DOUBLE, true), (t, k) -> t.value = k, t -> t.value) .add() .build(); - private double value = 0.0; + private double value; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/XValueDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/XValueDensityAsset.java index c1cb50a5..e2eabdda 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/XValueDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/XValueDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class XValueDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( XValueDensityAsset.class, XValueDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YOverrideDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YOverrideDensityAsset.java index e7085a6d..c728ac8a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YOverrideDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YOverrideDensityAsset.java @@ -9,13 +9,14 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class YOverrideDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( YOverrideDensityAsset.class, YOverrideDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) .append(new KeyedCodec<>("Value", Codec.DOUBLE, true), (t, k) -> t.value = k, t -> t.value) .add() .build(); - private double value = 0.0; + private double value; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YSampledDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YSampledDensityAsset.java new file mode 100644 index 00000000..90a3ac08 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YSampledDensityAsset.java @@ -0,0 +1,38 @@ +package com.hypixel.hytale.builtin.hytalegenerator.assets.density; + +import com.hypixel.hytale.builtin.hytalegenerator.density.Density; +import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.ConstantValueDensity; +import com.hypixel.hytale.builtin.hytalegenerator.density.nodes.YSampledDensity; +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.codec.validation.Validators; +import javax.annotation.Nonnull; + +public class YSampledDensityAsset extends DensityAsset { + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder( + YSampledDensityAsset.class, YSampledDensityAsset::new, DensityAsset.ABSTRACT_CODEC + ) + .append(new KeyedCodec<>("SampleDistance", Codec.DOUBLE, true), (asset, value) -> asset.sampleDistance = value, asset -> asset.sampleDistance) + .addValidator(Validators.greaterThan(0.0)) + .add() + .append(new KeyedCodec<>("SampleOffset", Codec.DOUBLE, true), (asset, value) -> asset.sampleOffset = value, asset -> asset.sampleOffset) + .add() + .build(); + private double sampleDistance = 4.0; + private double sampleOffset = 0.0; + + @Nonnull + @Override + public Density build(@Nonnull DensityAsset.Argument argument) { + return (Density)(this.sampleDistance <= 0.0 + ? new ConstantValueDensity(0.0) + : new YSampledDensity(this.buildFirstInput(argument), this.sampleDistance, this.sampleOffset)); + } + + @Override + public void cleanUp() { + this.cleanUpInputs(); + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YValueDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YValueDensityAsset.java index 323bbd33..7f02309e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YValueDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/YValueDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class YValueDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( YValueDensityAsset.class, YValueDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ZOverrideDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ZOverrideDensityAsset.java index dfb93d02..fb41b64e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ZOverrideDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ZOverrideDensityAsset.java @@ -9,13 +9,14 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ZOverrideDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ZOverrideDensityAsset.class, ZOverrideDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) .append(new KeyedCodec<>("Value", Codec.DOUBLE, true), (t, k) -> t.value = k, t -> t.value) .add() .build(); - private double value = 0.0; + private double value; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ZValueDensityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ZValueDensityAsset.java index 8eafd57b..e301218f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ZValueDensityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/ZValueDensityAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ZValueDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ZValueDensityAsset.class, ZValueDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) 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..77d995dc 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 @@ -19,6 +19,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class Positions3DDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Positions3DDensityAsset.class, Positions3DDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -43,7 +44,7 @@ public class Positions3DDensityAsset extends DensityAsset { return new ConstantValueDensity(0.0); } else { PositionProvider positionsField = this.positionProviderAsset - .build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle, argument.workerIndexer)); + .build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle, argument.workerId)); 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..27a657c1 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 @@ -20,6 +20,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class PositionsCellNoiseDensityAsset extends DensityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( PositionsCellNoiseDensityAsset.class, PositionsCellNoiseDensityAsset::new, DensityAsset.ABSTRACT_CODEC ) @@ -51,8 +52,8 @@ public class PositionsCellNoiseDensityAsset extends DensityAsset { 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); + .build(new PositionProviderAsset.Argument(argument.parentSeed, argument.referenceBundle, argument.workerId)); + ReturnType returnType = this.returnTypeAsset.build(argument.parentSeed, argument.referenceBundle, argument.workerId); 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/distancefunctions/DistanceFunctionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/DistanceFunctionAsset.java index cc073608..f17d8cc1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/DistanceFunctionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/DistanceFunctionAsset.java @@ -13,11 +13,15 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import javax.annotation.Nonnull; public abstract class DistanceFunctionAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(DistanceFunctionAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(DistanceFunctionAsset.class).build(); private String id; private AssetExtraInfo.Data data; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/EuclideanDistanceFunctionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/EuclideanDistanceFunctionAsset.java index 739f287d..e41e59de 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/EuclideanDistanceFunctionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/EuclideanDistanceFunctionAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class EuclideanDistanceFunctionAsset extends DistanceFunctionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( EuclideanDistanceFunctionAsset.class, EuclideanDistanceFunctionAsset::new, DistanceFunctionAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/ManhattanDistanceFunctionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/ManhattanDistanceFunctionAsset.java index 05e44722..81d77357 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/ManhattanDistanceFunctionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/density/positions/distancefunctions/ManhattanDistanceFunctionAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ManhattanDistanceFunctionAsset extends DistanceFunctionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ManhattanDistanceFunctionAsset.class, ManhattanDistanceFunctionAsset::new, DistanceFunctionAsset.ABSTRACT_CODEC ) 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..4b5318df 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 @@ -16,6 +16,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class CellValueReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CellValueReturnTypeAsset.class, CellValueReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -25,14 +26,14 @@ public class CellValueReturnTypeAsset extends ReturnTypeAsset { .add() .build(); private DensityAsset densityAsset = new ConstantDensityAsset(); - private double defaultValue = 0.0; + private double defaultValue; @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, @Nonnull WorkerIndexer.Id workerId) { + Density densityNode = this.densityAsset.build(new DensityAsset.Argument(parentSeed, referenceBundle, workerId)); + 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..36e13631 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 @@ -13,6 +13,7 @@ import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; import javax.annotation.Nonnull; public class CurveReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CurveReturnTypeAsset.class, CurveReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -23,7 +24,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, @Nonnull WorkerIndexer.Id workerId) { 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..528c4569 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 @@ -24,6 +24,7 @@ import java.util.HashMap; import javax.annotation.Nonnull; public class DensityReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DensityReturnTypeAsset.class, DensityReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -44,8 +45,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, @Nonnull WorkerIndexer.Id workerId) { + DensityAsset.Argument densityArgument = new DensityAsset.Argument(parentSeed, referenceBundle, workerId); Density choiceDensity = this.choiceDensityAsset.build(densityArgument); HashMap delimiterMap = new HashMap<>(this.delimiterAssets.length); @@ -53,11 +54,12 @@ 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> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( DensityReturnTypeAsset.DelimiterAsset.class, DensityReturnTypeAsset.DelimiterAsset::new, 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..857d568a 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 @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class Distance2AddReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Distance2AddReturnTypeAsset.class, Distance2AddReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -16,7 +17,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, @Nonnull WorkerIndexer.Id workerId) { 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..1dfcc740 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 @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class Distance2DivReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Distance2DivReturnTypeAsset.class, Distance2DivReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -16,7 +17,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, @Nonnull WorkerIndexer.Id workerId) { 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..57521d0b 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 @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class Distance2MulReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Distance2MulReturnTypeAsset.class, Distance2MulReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -16,7 +17,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, @Nonnull WorkerIndexer.Id workerId) { 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..7c150f35 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 @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class Distance2ReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Distance2ReturnTypeAsset.class, Distance2ReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -16,7 +17,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, @Nonnull WorkerIndexer.Id workerId) { 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..aae8a51c 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 @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class Distance2SubReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Distance2SubReturnTypeAsset.class, Distance2SubReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -16,7 +17,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, @Nonnull WorkerIndexer.Id workerId) { 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..c0131633 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 @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class DistanceReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DistanceReturnTypeAsset.class, DistanceReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -16,7 +17,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, @Nonnull WorkerIndexer.Id workerId) { 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..078baf7d 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 @@ -14,6 +14,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ImportedReturnTypeAsset extends ReturnTypeAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedReturnTypeAsset.class, ImportedReturnTypeAsset::new, ReturnTypeAsset.ABSTRACT_CODEC ) @@ -23,7 +24,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, @Nonnull WorkerIndexer.Id workerId) { ReturnTypeAsset asset = getExportedAsset(this.importedAssetName); if (asset == null) { Logger.getLogger("Density") @@ -42,7 +43,7 @@ public class ImportedReturnTypeAsset extends ReturnTypeAsset { } }; } else { - return asset.build(parentSeed, referenceBundle, workerIndexer); + return asset.build(parentSeed, referenceBundle, workerId); } } } 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..ea56b30d 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 @@ -19,13 +19,19 @@ import java.util.Map; import javax.annotation.Nonnull; public abstract class ReturnTypeAsset implements JsonAssetWithMap> { + @Nonnull private static final ReturnTypeAsset[] EMPTY_INPUTS = new ReturnTypeAsset[0]; + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new HashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(ReturnTypeAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(ReturnTypeAsset.class) .append(new KeyedCodec<>("ExportAs", Codec.STRING, false), (t, k) -> t.exportName = k, t -> t.exportName) .add() @@ -43,7 +49,7 @@ public abstract class ReturnTypeAsset implements JsonAssetWithMap CODEC = BuilderCodec.builder( ConstantEnvironmentProviderAsset.class, ConstantEnvironmentProviderAsset::new, EnvironmentProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/environmentproviders/DensityDelimitedEnvironmentProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/environmentproviders/DensityDelimitedEnvironmentProviderAsset.java index f8cf2065..273b450d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/environmentproviders/DensityDelimitedEnvironmentProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/environmentproviders/DensityDelimitedEnvironmentProviderAsset.java @@ -21,6 +21,7 @@ import java.util.List; import javax.annotation.Nonnull; public class DensityDelimitedEnvironmentProviderAsset extends EnvironmentProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DensityDelimitedEnvironmentProviderAsset.class, DensityDelimitedEnvironmentProviderAsset::new, EnvironmentProviderAsset.ABSTRACT_CODEC ) @@ -69,6 +70,7 @@ public class DensityDelimitedEnvironmentProviderAsset extends EnvironmentProvide public static class DelimiterAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( DensityDelimitedEnvironmentProviderAsset.DelimiterAsset.class, DensityDelimitedEnvironmentProviderAsset.DelimiterAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/environmentproviders/EnvironmentProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/environmentproviders/EnvironmentProviderAsset.java index 1953967a..d303c2fd 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/environmentproviders/EnvironmentProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/environmentproviders/EnvironmentProviderAsset.java @@ -21,12 +21,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class EnvironmentProviderAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(EnvironmentProviderAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(EnvironmentProviderAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -78,22 +83,22 @@ public abstract class EnvironmentProviderAsset implements Cleanable, JsonAssetWi public SeedBox parentSeed; public MaterialCache materialCache; public ReferenceBundle referenceBundle; - public WorkerIndexer workerIndexer; + public WorkerIndexer.Id workerId; public Argument( - @Nonnull SeedBox parentSeed, @Nonnull MaterialCache materialCache, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer + @Nonnull SeedBox parentSeed, @Nonnull MaterialCache materialCache, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer.Id workerId ) { this.parentSeed = parentSeed; this.materialCache = materialCache; this.referenceBundle = referenceBundle; - this.workerIndexer = workerIndexer; + this.workerId = workerId; } public Argument(@Nonnull EnvironmentProviderAsset.Argument argument) { this.parentSeed = argument.parentSeed; this.materialCache = argument.materialCache; this.referenceBundle = argument.referenceBundle; - this.workerIndexer = argument.workerIndexer; + this.workerId = argument.workerId; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/framework/DecimalConstantsFrameworkAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/framework/DecimalConstantsFrameworkAsset.java new file mode 100644 index 00000000..e4fd84c8 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/framework/DecimalConstantsFrameworkAsset.java @@ -0,0 +1,94 @@ +package com.hypixel.hytale.builtin.hytalegenerator.assets.framework; + +import com.hypixel.hytale.assetstore.AssetExtraInfo; +import com.hypixel.hytale.assetstore.codec.AssetBuilderCodec; +import com.hypixel.hytale.assetstore.map.DefaultAssetMap; +import com.hypixel.hytale.assetstore.map.JsonAssetWithMap; +import com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.WorldStructureAsset; +import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; +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 java.util.HashMap; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class DecimalConstantsFrameworkAsset extends FrameworkAsset { + @Nonnull + public static final String NAME = "DecimalConstants"; + @Nonnull + public static final Class CLASS = DecimalConstantsFrameworkAsset.Entries.class; + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder( + DecimalConstantsFrameworkAsset.class, DecimalConstantsFrameworkAsset::new, FrameworkAsset.ABSTRACT_CODEC + ) + .append( + new KeyedCodec<>("Entries", new ArrayCodec<>(DecimalConstantsFrameworkAsset.EntryAsset.CODEC, DecimalConstantsFrameworkAsset.EntryAsset[]::new), true), + (asset, value) -> asset.entryAssets = value, + asset -> asset.entryAssets + ) + .add() + .build(); + private String id; + private AssetExtraInfo.Data data; + private DecimalConstantsFrameworkAsset.EntryAsset[] entryAssets = new DecimalConstantsFrameworkAsset.EntryAsset[0]; + + private DecimalConstantsFrameworkAsset() { + } + + @Override + public String getId() { + return this.id; + } + + @Override + public void build(@Nonnull WorldStructureAsset.Argument argument, @Nonnull ReferenceBundle referenceBundle) { + DecimalConstantsFrameworkAsset.Entries entries = new DecimalConstantsFrameworkAsset.Entries(); + + for (DecimalConstantsFrameworkAsset.EntryAsset entryAsset : this.entryAssets) { + entries.put(entryAsset.name, entryAsset.value); + } + + referenceBundle.put("DecimalConstants", entries, CLASS); + } + + public static class Entries extends HashMap { + @Nullable + public static DecimalConstantsFrameworkAsset.Entries get(@Nonnull ReferenceBundle referenceBundle) { + return referenceBundle.get("DecimalConstants", DecimalConstantsFrameworkAsset.CLASS); + } + + @Nullable + public static Double get(@Nonnull String name, @Nonnull ReferenceBundle referenceBundle) { + DecimalConstantsFrameworkAsset.Entries entries = get(referenceBundle); + return entries == null ? null : entries.get(name); + } + } + + public static class EntryAsset implements JsonAssetWithMap> { + @Nonnull + public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( + DecimalConstantsFrameworkAsset.EntryAsset.class, + DecimalConstantsFrameworkAsset.EntryAsset::new, + Codec.STRING, + (asset, id) -> asset.id = id, + config -> config.id, + (config, data) -> config.data = data, + config -> config.data + ) + .append(new KeyedCodec<>("Name", Codec.STRING, true), (asset, value) -> asset.name = value, asset -> asset.name) + .add() + .append(new KeyedCodec<>("Value", Codec.DOUBLE, true), (asset, value) -> asset.value = value, asset -> asset.value) + .add() + .build(); + private String id; + private AssetExtraInfo.Data data; + private String name = ""; + private double value = 0.0; + + public String getId() { + return this.id; + } + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/mapcontentfield/ContentFieldAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/framework/FrameworkAsset.java similarity index 52% rename from src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/mapcontentfield/ContentFieldAsset.java rename to src/com/hypixel/hytale/builtin/hytalegenerator/assets/framework/FrameworkAsset.java index 587b5f05..78127887 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/mapcontentfield/ContentFieldAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/framework/FrameworkAsset.java @@ -1,4 +1,4 @@ -package com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.mapcontentfield; +package com.hypixel.hytale.builtin.hytalegenerator.assets.framework; import com.hypixel.hytale.assetstore.AssetExtraInfo; import com.hypixel.hytale.assetstore.codec.AssetCodecMapCodec; @@ -6,21 +6,28 @@ 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.assets.worldstructures.WorldStructureAsset; +import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.ReferenceBundle; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.codecs.array.ArrayCodec; +import javax.annotation.Nonnull; -public abstract class ContentFieldAsset implements Cleanable, JsonAssetWithMap> { - public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( +public abstract class FrameworkAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull + public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); - public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(ContentFieldAsset.class, CODEC); + @Nonnull + public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(FrameworkAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); - public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(ContentFieldAsset.class).build(); + @Nonnull + public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(FrameworkAsset.class).build(); private String id; private AssetExtraInfo.Data data; - protected ContentFieldAsset() { + protected FrameworkAsset() { } public String getId() { @@ -30,4 +37,6 @@ public abstract class ContentFieldAsset implements Cleanable, JsonAssetWithMap CLASS = PositionsFrameworkAsset.Entries.class; + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder( + PositionsFrameworkAsset.class, PositionsFrameworkAsset::new, FrameworkAsset.ABSTRACT_CODEC + ) + .append( + new KeyedCodec<>("Entries", new ArrayCodec<>(PositionsFrameworkAsset.EntryAsset.CODEC, PositionsFrameworkAsset.EntryAsset[]::new), true), + (asset, value) -> asset.entryAssets = value, + asset -> asset.entryAssets + ) + .add() + .build(); + private String id; + private AssetExtraInfo.Data data; + private PositionsFrameworkAsset.EntryAsset[] entryAssets = new PositionsFrameworkAsset.EntryAsset[0]; + + private PositionsFrameworkAsset() { + } + + @Override + public String getId() { + return this.id; + } + + @Override + public void build(@NonNullDecl WorldStructureAsset.Argument argument, @NonNullDecl ReferenceBundle referenceBundle) { + PositionsFrameworkAsset.Entries entries = new PositionsFrameworkAsset.Entries(); + + for (PositionsFrameworkAsset.EntryAsset entryAsset : this.entryAssets) { + entries.put(entryAsset.name, entryAsset.positionProviderAsset); + } + + referenceBundle.put("Positions", entries, CLASS); + } + + public static class Entries extends HashMap { + @Nullable + public static PositionsFrameworkAsset.Entries get(@Nonnull ReferenceBundle referenceBundle) { + return referenceBundle.get("Positions", PositionsFrameworkAsset.CLASS); + } + + @Nullable + public static PositionProviderAsset get(@Nonnull String name, @Nonnull ReferenceBundle referenceBundle) { + PositionsFrameworkAsset.Entries entries = get(referenceBundle); + return entries == null ? null : entries.get(name); + } + } + + public static class EntryAsset implements JsonAssetWithMap> { + @Nonnull + public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( + PositionsFrameworkAsset.EntryAsset.class, + PositionsFrameworkAsset.EntryAsset::new, + Codec.STRING, + (asset, id) -> asset.id = id, + config -> config.id, + (config, data) -> config.data = data, + config -> config.data + ) + .append(new KeyedCodec<>("Name", Codec.STRING, true), (asset, value) -> asset.name = value, asset -> asset.name) + .add() + .append( + new KeyedCodec<>("Positions", PositionProviderAsset.CODEC, true), + (asset, value) -> asset.positionProviderAsset = value, + asset -> asset.positionProviderAsset + ) + .add() + .build(); + private String id; + private AssetExtraInfo.Data data; + private String name = ""; + private PositionProviderAsset positionProviderAsset = new ListPositionProviderAsset(); + + public String getId() { + return this.id; + } + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/interpolationasset/BiomeFrontierAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/interpolationasset/BiomeFrontierAsset.java index 4ecaf55c..4b38f77d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/interpolationasset/BiomeFrontierAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/interpolationasset/BiomeFrontierAsset.java @@ -6,8 +6,10 @@ import com.hypixel.hytale.assetstore.map.DefaultAssetMap; import com.hypixel.hytale.assetstore.map.JsonAssetWithMap; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; +import javax.annotation.Nonnull; public class BiomeFrontierAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( BiomeFrontierAsset.class, BiomeFrontierAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/material/MaterialAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/material/MaterialAsset.java index aeb5154f..3524f322 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/material/MaterialAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/material/MaterialAsset.java @@ -11,9 +11,12 @@ import com.hypixel.hytale.builtin.hytalegenerator.material.MaterialCache; import com.hypixel.hytale.builtin.hytalegenerator.material.SolidMaterial; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.Rotation; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple; import javax.annotation.Nonnull; public class MaterialAsset implements JsonAssetWithMap>, Cleanable { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( MaterialAsset.class, MaterialAsset::new, @@ -27,6 +30,10 @@ public class MaterialAsset implements JsonAssetWithMap("Fluid", Codec.STRING, true), (t, value) -> t.fluidName = value, t -> t.fluidName) .add() + .append(new KeyedCodec<>("SolidBottomUp", Codec.BOOLEAN, false), (t, value) -> t.isSolidBottomUp = value, t -> t.isSolidBottomUp) + .add() + .append(new KeyedCodec<>("SolidRotation", OrthogonalRotationAsset.CODEC, false), (t, value) -> t.solidRotationAsset = value, t -> t.solidRotationAsset) + .add() .build(); private String id; private AssetExtraInfo.Data data; @@ -34,19 +41,37 @@ public class MaterialAsset implements JsonAssetWithMap> { + @Nonnull + public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( + OrthogonalRotationAsset.class, + OrthogonalRotationAsset::new, + Codec.STRING, + (asset, id) -> asset.id = id, + config -> config.id, + (config, data) -> config.data = data, + config -> config.data + ) + .append(new KeyedCodec<>("Yaw", Rotation.CODEC, false), (asset, value) -> asset.yaw = value, asset -> asset.yaw) + .add() + .append(new KeyedCodec<>("Pitch", Rotation.CODEC, false), (asset, value) -> asset.pitch = value, asset -> asset.pitch) + .add() + .append(new KeyedCodec<>("Roll", Rotation.CODEC, false), (asset, value) -> asset.roll = value, asset -> asset.roll) + .add() + .build(); + private String id; + private AssetExtraInfo.Data data; + @Nonnull + private Rotation yaw = Rotation.None; + @Nonnull + private Rotation pitch = Rotation.None; + @Nonnull + private Rotation roll = Rotation.None; + + @Nonnull + public RotationTuple build() { + return RotationTuple.of(this.yaw, this.pitch, this.roll); + } + + public boolean isNone() { + return this.yaw == Rotation.None && this.pitch == Rotation.None && this.roll == Rotation.None; + } + + public String getId() { + return this.id; + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/ConstantMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/ConstantMaterialProviderAsset.java index 7050a5c0..9ce6ab72 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/ConstantMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/ConstantMaterialProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ConstantMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ConstantMaterialProviderAsset.class, ConstantMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/DownwardDepthMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/DownwardDepthMaterialProviderAsset.java index 23fd5165..9e253e1a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/DownwardDepthMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/DownwardDepthMaterialProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class DownwardDepthMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DownwardDepthMaterialProviderAsset.class, DownwardDepthMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) @@ -17,7 +18,7 @@ public class DownwardDepthMaterialProviderAsset extends MaterialProviderAsset { .append(new KeyedCodec<>("Material", MaterialProviderAsset.CODEC, true), (t, k) -> t.materialProviderAsset = k, k -> k.materialProviderAsset) .add() .build(); - private int depth = 0; + private int depth; private MaterialProviderAsset materialProviderAsset = new ConstantMaterialProviderAsset(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/DownwardSpaceMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/DownwardSpaceMaterialProviderAsset.java index 19bdc30f..5eff7676 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/DownwardSpaceMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/DownwardSpaceMaterialProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class DownwardSpaceMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DownwardSpaceMaterialProviderAsset.class, DownwardSpaceMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/FieldFunctionMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/FieldFunctionMaterialProviderAsset.java index 683d0625..d662c6e4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/FieldFunctionMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/FieldFunctionMaterialProviderAsset.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class FieldFunctionMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( FieldFunctionMaterialProviderAsset.class, FieldFunctionMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) @@ -71,6 +72,7 @@ public class FieldFunctionMaterialProviderAsset extends MaterialProviderAsset { public static class DelimiterAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( FieldFunctionMaterialProviderAsset.DelimiterAsset.class, FieldFunctionMaterialProviderAsset.DelimiterAsset::new, @@ -89,8 +91,8 @@ public class FieldFunctionMaterialProviderAsset extends MaterialProviderAsset { .build(); private String id; private AssetExtraInfo.Data data; - private double from = 0.0; - private double to = 0.0; + private double from; + private double to; private MaterialProviderAsset materialProviderAsset = new ConstantMaterialProviderAsset(); public String getId() { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/ImportedMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/ImportedMaterialProviderAsset.java index 475c8cbe..50a1e200 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/ImportedMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/ImportedMaterialProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class ImportedMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedMaterialProviderAsset.class, ImportedMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/MaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/MaterialProviderAsset.java index 5942f52b..8fa24e21 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/MaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/MaterialProviderAsset.java @@ -24,13 +24,19 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class MaterialProviderAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull private static final MaterialProviderAsset[] EMPTY_INPUTS = new MaterialProviderAsset[0]; + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(MaterialProviderAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(MaterialProviderAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -49,7 +55,7 @@ public abstract class MaterialProviderAsset implements Cleanable, JsonAssetWithM .build(); private String id; private AssetExtraInfo.Data data; - private boolean skip = false; + private boolean skip; private String exportName = ""; protected MaterialProviderAsset() { @@ -69,12 +75,14 @@ public abstract class MaterialProviderAsset implements Cleanable, JsonAssetWithM return this.id; } + @Nonnull public static MaterialProviderAsset.Argument argumentFrom(@Nonnull DensityAsset.Argument argument, @Nonnull MaterialCache materialCache) { - return new MaterialProviderAsset.Argument(argument.parentSeed, materialCache, argument.referenceBundle, argument.workerIndexer); + return new MaterialProviderAsset.Argument(argument.parentSeed, materialCache, argument.referenceBundle, argument.workerId); } + @Nonnull public static MaterialProviderAsset.Argument argumentFrom(@Nonnull PropAsset.Argument argument) { - return new MaterialProviderAsset.Argument(argument.parentSeed, argument.materialCache, argument.referenceBundle, argument.workerIndexer); + return new MaterialProviderAsset.Argument(argument.parentSeed, argument.materialCache, argument.referenceBundle, argument.workerId); } @Override @@ -85,22 +93,21 @@ public abstract class MaterialProviderAsset implements Cleanable, JsonAssetWithM public SeedBox parentSeed; public MaterialCache materialCache; public ReferenceBundle referenceBundle; - public WorkerIndexer workerIndexer; + public WorkerIndexer.Id workerId; public Argument( - @Nonnull SeedBox parentSeed, @Nonnull MaterialCache materialCache, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer + @Nonnull SeedBox parentSeed, @Nonnull MaterialCache materialCache, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer.Id workerId ) { this.parentSeed = parentSeed; this.materialCache = materialCache; this.referenceBundle = referenceBundle; - this.workerIndexer = workerIndexer; + this.workerId = workerId; } public Argument(@Nonnull MaterialProviderAsset.Argument argument) { this.parentSeed = argument.parentSeed; this.materialCache = argument.materialCache; - this.referenceBundle = argument.referenceBundle; - this.workerIndexer = argument.workerIndexer; + this.workerId = argument.workerId; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/QueueMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/QueueMaterialProviderAsset.java index 1b3b5aa7..715ae5fb 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/QueueMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/QueueMaterialProviderAsset.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class QueueMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( QueueMaterialProviderAsset.class, QueueMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/SimpleHorizontalMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/SimpleHorizontalMaterialProviderAsset.java index a438a2cd..f33d9932 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/SimpleHorizontalMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/SimpleHorizontalMaterialProviderAsset.java @@ -1,17 +1,16 @@ package com.hypixel.hytale.builtin.hytalegenerator.assets.materialproviders; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.DecimalConstantsFrameworkAsset; import com.hypixel.hytale.builtin.hytalegenerator.material.Material; import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.HorizontalMaterialProvider; import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.MaterialProvider; -import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.BaseHeightReference; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; -import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class SimpleHorizontalMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SimpleHorizontalMaterialProviderAsset.class, SimpleHorizontalMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) @@ -26,8 +25,8 @@ public class SimpleHorizontalMaterialProviderAsset extends MaterialProviderAsset .append(new KeyedCodec<>("BottomBaseHeight", Codec.STRING, false), (t, k) -> t.bottomBaseHeightName = k, t -> t.bottomBaseHeightName) .add() .build(); - private int topY = 0; - private int bottomY = 0; + private int topY; + private int bottomY; private MaterialProviderAsset materialProviderAsset = new ConstantMaterialProviderAsset(); private String topBaseHeightName = ""; private String bottomBaseHeightName = ""; @@ -38,33 +37,21 @@ public class SimpleHorizontalMaterialProviderAsset extends MaterialProviderAsset if (super.skip()) { return MaterialProvider.noMaterialProvider(); } else { - BiDouble2DoubleFunction topFunction = (x, z) -> this.topY; - BiDouble2DoubleFunction bottomFunction = (x, z) -> this.bottomY; + double topBaseHeight = 0.0; + double bottomBaseHeight = 0.0; if (!this.topBaseHeightName.isEmpty()) { - BaseHeightReference topHeightDataLayer = argument.referenceBundle.getLayerWithName(this.topBaseHeightName, BaseHeightReference.class); - if (topHeightDataLayer != null) { - BiDouble2DoubleFunction baseHeight = topHeightDataLayer.getHeightFunction(); - topFunction = (x, z) -> baseHeight.apply(x, z) + this.topY; - } else { - HytaleLogger.getLogger() - .atConfig() - .log("Couldn't find height data layer with name \"" + this.topBaseHeightName + "\", using a zero-constant Density node."); + Double topValue = DecimalConstantsFrameworkAsset.Entries.get(this.topBaseHeightName, argument.referenceBundle); + if (topValue != null) { + topBaseHeight = topValue; + } + + Double bottomValue = DecimalConstantsFrameworkAsset.Entries.get(this.bottomBaseHeightName, argument.referenceBundle); + if (topValue != null) { + bottomBaseHeight = bottomValue; } } - if (!this.bottomBaseHeightName.isEmpty()) { - BaseHeightReference bottomHeightDataLayer = argument.referenceBundle.getLayerWithName(this.bottomBaseHeightName, BaseHeightReference.class); - if (bottomHeightDataLayer != null) { - BiDouble2DoubleFunction baseHeight = bottomHeightDataLayer.getHeightFunction(); - bottomFunction = (x, z) -> baseHeight.apply(x, z) + this.bottomY; - } else { - HytaleLogger.getLogger() - .atConfig() - .log("Couldn't find height data layer with name \"" + this.bottomBaseHeightName + "\", using a zero-constant Density node."); - } - } - - return new HorizontalMaterialProvider<>(this.materialProviderAsset.build(argument), topFunction::apply, bottomFunction::apply); + return new HorizontalMaterialProvider<>(this.materialProviderAsset.build(argument), this.topY + topBaseHeight, this.bottomY + bottomBaseHeight); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/SolidityMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/SolidityMaterialProviderAsset.java index a1c775cd..fecbd291 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/SolidityMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/SolidityMaterialProviderAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class SolidityMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SolidityMaterialProviderAsset.class, SolidityMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/StripedMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/StripedMaterialProviderAsset.java index 15841b5b..0bfd2e25 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/StripedMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/StripedMaterialProviderAsset.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class StripedMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( StripedMaterialProviderAsset.class, StripedMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) @@ -59,6 +60,7 @@ public class StripedMaterialProviderAsset extends MaterialProviderAsset { } public static class StripeAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( StripedMaterialProviderAsset.StripeAsset.class, StripedMaterialProviderAsset.StripeAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/TerrainDensityMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/TerrainDensityMaterialProviderAsset.java index e5edae7c..83002fa6 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/TerrainDensityMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/TerrainDensityMaterialProviderAsset.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class TerrainDensityMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TerrainDensityMaterialProviderAsset.class, TerrainDensityMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) @@ -62,6 +63,7 @@ public class TerrainDensityMaterialProviderAsset extends MaterialProviderAsset { public static class DelimiterAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( TerrainDensityMaterialProviderAsset.DelimiterAsset.class, TerrainDensityMaterialProviderAsset.DelimiterAsset::new, @@ -80,8 +82,8 @@ public class TerrainDensityMaterialProviderAsset extends MaterialProviderAsset { .build(); private String id; private AssetExtraInfo.Data data; - private double from = 0.0; - private double to = 0.0; + private double from; + private double to; private MaterialProviderAsset materialProviderAsset = new ConstantMaterialProviderAsset(); public String getId() { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/UpwardDepthMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/UpwardDepthMaterialProviderAsset.java index 41995bc1..f018304d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/UpwardDepthMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/UpwardDepthMaterialProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class UpwardDepthMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UpwardDepthMaterialProviderAsset.class, UpwardDepthMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) @@ -17,7 +18,7 @@ public class UpwardDepthMaterialProviderAsset extends MaterialProviderAsset { .append(new KeyedCodec<>("Material", MaterialProviderAsset.CODEC, true), (t, k) -> t.materialProviderAsset = k, k -> k.materialProviderAsset) .add() .build(); - private int depth = 0; + private int depth; private MaterialProviderAsset materialProviderAsset = new ConstantMaterialProviderAsset(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/UpwardSpaceMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/UpwardSpaceMaterialProviderAsset.java index baf1fc21..b0ddcd8d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/UpwardSpaceMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/UpwardSpaceMaterialProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class UpwardSpaceMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UpwardSpaceMaterialProviderAsset.class, UpwardSpaceMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) @@ -17,7 +18,7 @@ public class UpwardSpaceMaterialProviderAsset extends MaterialProviderAsset { .append(new KeyedCodec<>("Material", MaterialProviderAsset.CODEC, true), (t, k) -> t.materialProviderAsset = k, k -> k.materialProviderAsset) .add() .build(); - private int space = 0; + private int space; private MaterialProviderAsset materialProviderAsset = new ConstantMaterialProviderAsset(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/WeightedMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/WeightedMaterialProviderAsset.java index 6b0cf8bb..b0447c6a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/WeightedMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/WeightedMaterialProviderAsset.java @@ -17,6 +17,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class WeightedMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( WeightedMaterialProviderAsset.class, WeightedMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) @@ -36,7 +37,7 @@ public class WeightedMaterialProviderAsset extends MaterialProviderAsset { .add() .build(); private WeightedMaterialProviderAsset.WeightedMaterialAsset[] weighedMapEntries = new WeightedMaterialProviderAsset.WeightedMaterialAsset[0]; - private double skipChance = 0.0; + private double skipChance; private String seed = ""; @Nonnull @@ -65,6 +66,7 @@ public class WeightedMaterialProviderAsset extends MaterialProviderAsset { public static class WeightedMaterialAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( WeightedMaterialProviderAsset.WeightedMaterialAsset.class, WeightedMaterialProviderAsset.WeightedMaterialAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/SpaceAndDepthMaterialProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/SpaceAndDepthMaterialProviderAsset.java index e907547f..58f74505 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/SpaceAndDepthMaterialProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/SpaceAndDepthMaterialProviderAsset.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class SpaceAndDepthMaterialProviderAsset extends MaterialProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SpaceAndDepthMaterialProviderAsset.class, SpaceAndDepthMaterialProviderAsset::new, MaterialProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/AlwaysTrueConditionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/AlwaysTrueConditionAsset.java index bb3d6b71..2af392b4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/AlwaysTrueConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/AlwaysTrueConditionAsset.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class AlwaysTrueConditionAsset extends ConditionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( AlwaysTrueConditionAsset.class, AlwaysTrueConditionAsset::new, ConditionAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/AndConditionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/AndConditionAsset.java index 35b16195..63895d33 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/AndConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/AndConditionAsset.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class AndConditionAsset extends ConditionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( AndConditionAsset.class, AndConditionAsset::new, ConditionAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/ConditionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/ConditionAsset.java index 4f0209b8..28660a28 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/ConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/ConditionAsset.java @@ -9,14 +9,20 @@ import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.spaceanddept import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.codecs.array.ArrayCodec; +import javax.annotation.Nonnull; public abstract class ConditionAsset implements JsonAssetWithMap> { + @Nonnull private static final ConditionAsset[] EMPTY_INPUTS = new ConditionAsset[0]; + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(ConditionAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(ConditionAsset.class).build(); private String id; private AssetExtraInfo.Data data; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/EqualsConditionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/EqualsConditionAsset.java index e337b533..fc201de3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/EqualsConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/EqualsConditionAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class EqualsConditionAsset extends ConditionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( EqualsConditionAsset.class, EqualsConditionAsset::new, ConditionAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/GreaterThanConditionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/GreaterThanConditionAsset.java index 0749e241..283a7117 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/GreaterThanConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/GreaterThanConditionAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class GreaterThanConditionAsset extends ConditionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( GreaterThanConditionAsset.class, GreaterThanConditionAsset::new, ConditionAsset.ABSTRACT_CODEC ) @@ -18,7 +19,7 @@ public class GreaterThanConditionAsset extends ConditionAsset { .add() .build(); private ConditionParameter parameter = ConditionParameter.SPACE_ABOVE_FLOOR; - private int threshold = 0; + private int threshold; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/NotConditionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/NotConditionAsset.java index fd3db553..894a032b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/NotConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/NotConditionAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class NotConditionAsset extends ConditionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( NotConditionAsset.class, NotConditionAsset::new, ConditionAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/OrConditionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/OrConditionAsset.java index cd0f3f4e..c606b61c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/OrConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/OrConditionAsset.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class OrConditionAsset extends ConditionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(OrConditionAsset.class, OrConditionAsset::new, ConditionAsset.ABSTRACT_CODEC) .append( new KeyedCodec<>("Conditions", new ArrayCodec<>(ConditionAsset.CODEC, ConditionAsset[]::new), true), diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/SmallerThanConditionAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/SmallerThanConditionAsset.java index b784a5b9..316ed3e8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/SmallerThanConditionAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/conditionassets/SmallerThanConditionAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class SmallerThanConditionAsset extends ConditionAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SmallerThanConditionAsset.class, SmallerThanConditionAsset::new, ConditionAsset.ABSTRACT_CODEC ) @@ -18,7 +19,7 @@ public class SmallerThanConditionAsset extends ConditionAsset { .add() .build(); private ConditionParameter parameter = ConditionParameter.SPACE_ABOVE_FLOOR; - private int threshold = 0; + private int threshold; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/ConstantThicknessLayerAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/ConstantThicknessLayerAsset.java index c3e24424..5bb91f0e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/ConstantThicknessLayerAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/ConstantThicknessLayerAsset.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class ConstantThicknessLayerAsset extends LayerAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ConstantThicknessLayerAsset.class, ConstantThicknessLayerAsset::new, LayerAsset.ABSTRACT_CODEC ) @@ -21,7 +22,7 @@ public class ConstantThicknessLayerAsset extends LayerAsset { .append(new KeyedCodec<>("Material", MaterialProviderAsset.CODEC, true), (t, k) -> t.materialProviderAsset = k, k -> k.materialProviderAsset) .add() .build(); - private int thickness = 0; + private int thickness; private MaterialProviderAsset materialProviderAsset = new ConstantMaterialProviderAsset(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/LayerAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/LayerAsset.java index 77f662aa..8b0de02a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/LayerAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/LayerAsset.java @@ -15,12 +15,17 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import javax.annotation.Nonnull; public abstract class LayerAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull private static final LayerAsset[] EMPTY_INPUTS = new LayerAsset[0]; + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(LayerAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(LayerAsset.class).build(); private String id; private AssetExtraInfo.Data data; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/NoiseThicknessAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/NoiseThicknessAsset.java index 7209eca4..14320e6f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/NoiseThicknessAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/NoiseThicknessAsset.java @@ -14,6 +14,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class NoiseThicknessAsset extends LayerAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( NoiseThicknessAsset.class, NoiseThicknessAsset::new, LayerAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/RangeThicknessAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/RangeThicknessAsset.java index 061e2626..c7823d9a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/RangeThicknessAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/RangeThicknessAsset.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class RangeThicknessAsset extends LayerAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( RangeThicknessAsset.class, RangeThicknessAsset::new, LayerAsset.ABSTRACT_CODEC ) @@ -27,8 +28,8 @@ public class RangeThicknessAsset extends LayerAsset { .build(); private MaterialProviderAsset materialProviderAsset = new ConstantMaterialProviderAsset(); private String seed = ""; - private int rangeMin = 0; - private int rangeMax = 0; + private int rangeMin; + private int rangeMax; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/WeightedThicknessLayerAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/WeightedThicknessLayerAsset.java index 73e14955..c2be500b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/WeightedThicknessLayerAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/materialproviders/spaceanddepth/layerassets/WeightedThicknessLayerAsset.java @@ -18,6 +18,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class WeightedThicknessLayerAsset extends LayerAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( WeightedThicknessLayerAsset.class, WeightedThicknessLayerAsset::new, LayerAsset.ABSTRACT_CODEC ) @@ -59,6 +60,7 @@ public class WeightedThicknessLayerAsset extends LayerAsset { } public static class WeightedThicknessAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( WeightedThicknessLayerAsset.WeightedThicknessAsset.class, WeightedThicknessLayerAsset.WeightedThicknessAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/CellNoiseAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/CellNoiseAsset.java index 5293d495..b805fc29 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/CellNoiseAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/CellNoiseAsset.java @@ -13,7 +13,9 @@ import java.util.Set; import javax.annotation.Nonnull; public class CellNoiseAsset extends NoiseAsset { + @Nonnull private static Set validCellTypes = new HashSet<>(); + @Nonnull public static final BuilderCodec CODEC; private double warpScale = 1.0; private double warpAmount = 1.0; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/NoiseAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/NoiseAsset.java index 36df09bd..81245460 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/NoiseAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/NoiseAsset.java @@ -13,11 +13,15 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import javax.annotation.Nonnull; public abstract class NoiseAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(NoiseAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(NoiseAsset.class).build(); private String id; private AssetExtraInfo.Data data; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/SimplexNoiseAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/SimplexNoiseAsset.java index 39f77f01..2fe1b7bd 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/SimplexNoiseAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/noisegenerators/SimplexNoiseAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class SimplexNoiseAsset extends NoiseAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(SimplexNoiseAsset.class, SimplexNoiseAsset::new, NoiseAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Lacunarity", Codec.DOUBLE, true), (asset, lacunarity) -> asset.lacunarity = lacunarity, asset -> asset.lacunarity) .addValidator(Validators.greaterThan(0.0)) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/AndPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/AndPatternAsset.java index bde6fcbe..17bdc375 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/AndPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/AndPatternAsset.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class AndPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(AndPatternAsset.class, AndPatternAsset::new, PatternAsset.ABSTRACT_CODEC) .append( new KeyedCodec<>("Patterns", new ArrayCodec<>(PatternAsset.CODEC, PatternAsset[]::new), true), (t, k) -> t.patternAssets = k, k -> k.patternAssets diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/BlockSetPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/BlockSetPatternAsset.java index bf3ffda0..b0e74201 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/BlockSetPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/BlockSetPatternAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class BlockSetPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( BlockSetPatternAsset.class, BlockSetPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/CeilingPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/CeilingPatternAsset.java index e99150b0..44d2cc87 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/CeilingPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/CeilingPatternAsset.java @@ -1,12 +1,13 @@ package com.hypixel.hytale.builtin.hytalegenerator.assets.patterns; -import com.hypixel.hytale.builtin.hytalegenerator.patterns.CeilingPattern; import com.hypixel.hytale.builtin.hytalegenerator.patterns.Pattern; +import com.hypixel.hytale.builtin.hytalegenerator.patterns.SurfacePattern; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class CeilingPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CeilingPatternAsset.class, CeilingPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) @@ -26,7 +27,7 @@ public class CeilingPatternAsset extends PatternAsset { } else { Pattern ceilingPattern = this.ceiling.build(argument); Pattern originPattern = this.origin.build(argument); - return new CeilingPattern(ceilingPattern, originPattern); + return new SurfacePattern(ceilingPattern, originPattern, 0.0, 0.0, SurfacePattern.Facing.D, 0, 0); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/ConstantPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/ConstantPatternAsset.java index 274ef305..841382ed 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/ConstantPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/ConstantPatternAsset.java @@ -8,14 +8,16 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ConstantPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ConstantPatternAsset.class, ConstantPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) .append(new KeyedCodec<>("Value", Codec.BOOLEAN, true), (asset, value) -> asset.value = value, value -> value.value) .add() .build(); - private boolean value = false; + private boolean value; + @Nonnull @Override public Pattern build(@Nonnull PatternAsset.Argument argument) { return super.isSkipped() ? Pattern.noPattern() : new Pattern() { @@ -24,6 +26,7 @@ public class ConstantPatternAsset extends PatternAsset { return ConstantPatternAsset.this.value; } + @Nonnull @Override public SpaceSize readSpace() { return SpaceSize.empty(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/CuboidPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/CuboidPatternAsset.java index ac92b7c7..e89c5530 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/CuboidPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/CuboidPatternAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class CuboidPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CuboidPatternAsset.class, CuboidPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/DensityPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/DensityPatternAsset.java index 84256acf..9c4a6bab 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/DensityPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/DensityPatternAsset.java @@ -16,6 +16,7 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import javax.annotation.Nonnull; public class DensityPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DensityPatternAsset.class, DensityPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) @@ -54,6 +55,7 @@ public class DensityPatternAsset extends PatternAsset { } public static class DelimiterAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( DensityPatternAsset.DelimiterAsset.class, DensityPatternAsset.DelimiterAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/FloorPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/FloorPatternAsset.java index 853f7d49..d7493063 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/FloorPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/FloorPatternAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class FloorPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( FloorPatternAsset.class, FloorPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/GapPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/GapPatternAsset.java index dc0143c1..d5869238 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/GapPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/GapPatternAsset.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class GapPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(GapPatternAsset.class, GapPatternAsset::new, PatternAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("GapPattern", PatternAsset.CODEC, true), (t, k) -> t.gapPatternAsset = k, k -> k.gapPatternAsset) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/ImportedPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/ImportedPatternAsset.java index e98d0efa..2badbd1c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/ImportedPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/ImportedPatternAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class ImportedPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedPatternAsset.class, ImportedPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/MaterialPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/MaterialPatternAsset.java index 27a880d4..8913676a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/MaterialPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/MaterialPatternAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class MaterialPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MaterialPatternAsset.class, MaterialPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) @@ -17,6 +18,7 @@ public class MaterialPatternAsset extends PatternAsset { .build(); private MaterialAsset materialAsset = new MaterialAsset(); + @Nonnull @Override public Pattern build(@Nonnull PatternAsset.Argument argument) { if (super.isSkipped()) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/NotPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/NotPatternAsset.java index f6b634c5..309554e7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/NotPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/NotPatternAsset.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class NotPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(NotPatternAsset.class, NotPatternAsset::new, PatternAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Pattern", PatternAsset.CODEC, true), (t, k) -> t.patternAsset = k, k -> k.patternAsset) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/OffsetPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/OffsetPatternAsset.java index 8c439602..4ea5bd07 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/OffsetPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/OffsetPatternAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class OffsetPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( OffsetPatternAsset.class, OffsetPatternAsset::new, PatternAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/OrPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/OrPatternAsset.java index 2b33028a..fc2279ee 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/OrPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/OrPatternAsset.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class OrPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(OrPatternAsset.class, OrPatternAsset::new, PatternAsset.ABSTRACT_CODEC) .append( new KeyedCodec<>("Patterns", new ArrayCodec<>(PatternAsset.CODEC, PatternAsset[]::new), true), (t, k) -> t.patternAssets = k, k -> k.patternAssets diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/PatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/PatternAsset.java index d0ba19bb..62cfc4bb 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/PatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/PatternAsset.java @@ -23,12 +23,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class PatternAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(PatternAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(PatternAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -47,7 +52,7 @@ public abstract class PatternAsset implements Cleanable, JsonAssetWithMap CODEC = BuilderCodec.builder( SurfacePatternAsset.class, SurfacePatternAsset::new, PatternAsset.ABSTRACT_CODEC ) @@ -43,12 +44,12 @@ public class SurfacePatternAsset extends PatternAsset { .build(); private PatternAsset surface = new ConstantPatternAsset(); private PatternAsset origin = new ConstantPatternAsset(); - private double surfaceRadius = 0.0; - private double originRadius = 0.0; - private int surfaceGap = 0; - private int originGap = 0; + private double surfaceRadius; + private double originRadius; + private int surfaceGap; + private int originGap; private SurfacePattern.Facing[] facings = new SurfacePattern.Facing[0]; - private boolean requireAllFacings = false; + private boolean requireAllFacings; @Nonnull @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/WallPatternAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/WallPatternAsset.java index 98d3c2fe..57bbb4e2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/WallPatternAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/patterns/WallPatternAsset.java @@ -10,6 +10,7 @@ import java.util.List; import javax.annotation.Nonnull; public class WallPatternAsset extends PatternAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(WallPatternAsset.class, WallPatternAsset::new, PatternAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Wall", PatternAsset.CODEC, true), (t, k) -> t.wall = k, k -> k.wall) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/MeshPointGeneratorAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/MeshPointGeneratorAsset.java index a952b5d3..7925ec40 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/MeshPointGeneratorAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/MeshPointGeneratorAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class MeshPointGeneratorAsset extends PointGeneratorAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( MeshPointGeneratorAsset.class, MeshPointGeneratorAsset::new, PointGeneratorAsset.ABSTRACT_CODEC ) @@ -29,9 +30,9 @@ public class MeshPointGeneratorAsset extends PointGeneratorAsset { .add() .build(); private double jitter = 0.35; - private double scaleX = 1.0; - private double scaleY = 1.0; - private double scaleZ = 1.0; + private double scaleX = 40.0; + private double scaleY = 40.0; + private double scaleZ = 40.0; private String seedKey = "A"; @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/NoPointGeneratorAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/NoPointGeneratorAsset.java index e05291c8..b6cbce71 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/NoPointGeneratorAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/NoPointGeneratorAsset.java @@ -12,24 +12,29 @@ import java.util.function.Consumer; import javax.annotation.Nonnull; public class NoPointGeneratorAsset extends PointGeneratorAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( NoPointGeneratorAsset.class, NoPointGeneratorAsset::new, PointGeneratorAsset.ABSTRACT_CODEC ) .build(); + @Nonnull @Override public PointProvider build(@Nonnull SeedBox parentSeed) { return new PointProvider() { + @Nonnull @Override public List points3i(@Nonnull Vector3i min, @Nonnull Vector3i max) { return List.of(); } + @Nonnull @Override public List points2i(@Nonnull Vector2i min, @Nonnull Vector2i max) { return List.of(); } + @Nonnull @Override public List points1i(int min, int max) { return List.of(); @@ -47,16 +52,19 @@ public class NoPointGeneratorAsset extends PointGeneratorAsset { public void points1i(int min, int max, @Nonnull Consumer pointsOut) { } + @Nonnull @Override public List points3d(@Nonnull Vector3d min, @Nonnull Vector3d max) { return List.of(); } + @Nonnull @Override public List points2d(@Nonnull Vector2d min, @Nonnull Vector2d max) { return List.of(); } + @Nonnull @Override public List points1d(double min, double max) { return List.of(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/PointGeneratorAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/PointGeneratorAsset.java index e2f7aad1..13913a4c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/PointGeneratorAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/pointgenerators/PointGeneratorAsset.java @@ -17,13 +17,19 @@ import java.util.Map; import javax.annotation.Nonnull; public abstract class PointGeneratorAsset implements JsonAssetWithMap> { + @Nonnull private static final PointGeneratorAsset[] EMPTY_INPUTS = new PointGeneratorAsset[0]; + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new HashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(PointGeneratorAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(PointGeneratorAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -38,8 +44,9 @@ public abstract class PointGeneratorAsset implements JsonAssetWithMap CODEC = BuilderCodec.builder( AnchorPositionProviderAsset.class, AnchorPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/BaseHeightPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/BaseHeightPositionProviderAsset.java index d2723e4f..8a3c6e56 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/BaseHeightPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/BaseHeightPositionProviderAsset.java @@ -1,16 +1,15 @@ package com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.DecimalConstantsFrameworkAsset; import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.BaseHeightPositionProvider; import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; -import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.BaseHeightReference; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; -import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class BaseHeightPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( BaseHeightPositionProviderAsset.class, BaseHeightPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) @@ -18,7 +17,7 @@ public class BaseHeightPositionProviderAsset extends PositionProviderAsset { .add() .append(new KeyedCodec<>("MaxYRead", Codec.DOUBLE, false), (asset, v) -> asset.maxYRead = v, asset -> asset.maxYRead) .add() - .append(new KeyedCodec<>("BedName", Codec.STRING, false), (asset, v) -> asset.bedName = v, asset -> asset.bedName) + .append(new KeyedCodec<>("BedName", Codec.STRING, false), (asset, v) -> asset.baseHeightName = v, asset -> asset.baseHeightName) .add() .append( new KeyedCodec<>("Positions", PositionProviderAsset.CODEC, true), (asset, v) -> asset.positionProviderAsset = v, asset -> asset.positionProviderAsset @@ -27,7 +26,7 @@ public class BaseHeightPositionProviderAsset extends PositionProviderAsset { .build(); private double minYRead = -1.0; private double maxYRead = 1.0; - private String bedName = ""; + private String baseHeightName = ""; private PositionProviderAsset positionProviderAsset = new ListPositionProviderAsset(); @Nonnull @@ -37,16 +36,12 @@ public class BaseHeightPositionProviderAsset extends PositionProviderAsset { return PositionProvider.noPositionProvider(); } else { PositionProvider positionProvider = this.positionProviderAsset.build(argument); - BaseHeightReference heightDataLayer = argument.referenceBundle.getLayerWithName(this.bedName, BaseHeightReference.class); - if (heightDataLayer == null) { - HytaleLogger.getLogger() - .atConfig() - .log("Couldn't height data layer with name \"" + this.bedName + "\", the positions will not be offset by the bed."); - return new BaseHeightPositionProvider((x, z) -> 0.0, positionProvider, this.minYRead, this.maxYRead); - } else { - BiDouble2DoubleFunction heightFunction = heightDataLayer.getHeightFunction(); - return new BaseHeightPositionProvider(heightFunction, positionProvider, this.minYRead, this.maxYRead); + Double baseHeight = DecimalConstantsFrameworkAsset.Entries.get(this.baseHeightName, argument.referenceBundle); + if (baseHeight == null) { + baseHeight = 0.0; } + + return new BaseHeightPositionProvider(baseHeight, positionProvider, this.minYRead, this.maxYRead); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/BoundPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/BoundPositionProviderAsset.java new file mode 100644 index 00000000..cca4f3db --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/BoundPositionProviderAsset.java @@ -0,0 +1,39 @@ +package com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders; + +import com.hypixel.hytale.builtin.hytalegenerator.assets.bounds.DecimalBounds3dAsset; +import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.BoundPositionProvider; +import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; +import javax.annotation.Nonnull; + +public class BoundPositionProviderAsset extends PositionProviderAsset { + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder( + BoundPositionProviderAsset.class, BoundPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC + ) + .append(new KeyedCodec<>("Bounds", DecimalBounds3dAsset.CODEC, true), (asset, value) -> asset.bounds = value, asset -> asset.bounds) + .add() + .append( + new KeyedCodec<>("Positions", PositionProviderAsset.CODEC, true), + (asset, value) -> asset.positionProviderAsset = value, + asset -> asset.positionProviderAsset + ) + .add() + .build(); + private DecimalBounds3dAsset bounds = new DecimalBounds3dAsset(); + private PositionProviderAsset positionProviderAsset = new ListPositionProviderAsset(); + + @Nonnull + @Override + public PositionProvider build(@Nonnull PositionProviderAsset.Argument argument) { + return (PositionProvider)(super.skip() + ? PositionProvider.noPositionProvider() + : new BoundPositionProvider(this.positionProviderAsset.build(argument), this.bounds.build())); + } + + @Override + public void cleanUp() { + this.positionProviderAsset.cleanUp(); + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/CachedPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/CachedPositionProviderAsset.java index eefef21b..afd99f0e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/CachedPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/CachedPositionProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class CachedPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CachedPositionProviderAsset.class, CachedPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) @@ -32,7 +33,7 @@ public class CachedPositionProviderAsset extends PositionProviderAsset { return PositionProvider.noPositionProvider(); } else { PositionProvider childPositions = this.childAsset.build(argument); - return new CachedPositionProvider(childPositions, this.sectionSize, this.cacheSize, false, argument.workerIndexer.getWorkerCount()); + return new CachedPositionProvider(childPositions, this.sectionSize, this.cacheSize, false); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FieldFunctionOccurrencePositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FieldFunctionOccurrencePositionProviderAsset.java index 60c0ab89..013e70a4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FieldFunctionOccurrencePositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FieldFunctionOccurrencePositionProviderAsset.java @@ -11,6 +11,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class FieldFunctionOccurrencePositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( FieldFunctionOccurrencePositionProviderAsset.class, FieldFunctionOccurrencePositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FieldFunctionPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FieldFunctionPositionProviderAsset.java index 2866afe2..f0636e66 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FieldFunctionPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FieldFunctionPositionProviderAsset.java @@ -16,7 +16,9 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import javax.annotation.Nonnull; public class FieldFunctionPositionProviderAsset extends PositionProviderAsset { + @Nonnull private static final FieldFunctionPositionProviderAsset.DelimiterAsset[] EMPTY_DELIMITER_ASSETS = new FieldFunctionPositionProviderAsset.DelimiterAsset[0]; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( FieldFunctionPositionProviderAsset.class, FieldFunctionPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) @@ -47,9 +49,9 @@ public class FieldFunctionPositionProviderAsset extends PositionProviderAsset { if (super.skip()) { return PositionProvider.noPositionProvider(); } else { - Density functionTree = this.densityAsset.build(DensityAsset.from(argument)); + Density density = this.densityAsset.build(DensityAsset.from(argument)); PositionProvider positionProvider = this.positionProviderAsset.build(argument); - FieldFunctionPositionProvider out = new FieldFunctionPositionProvider(functionTree, positionProvider); + FieldFunctionPositionProvider out = new FieldFunctionPositionProvider(density, positionProvider); for (FieldFunctionPositionProviderAsset.DelimiterAsset asset : this.delimiterAssets) { out.addDelimiter(asset.min, asset.max); @@ -66,6 +68,7 @@ public class FieldFunctionPositionProviderAsset extends PositionProviderAsset { } public static class DelimiterAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( FieldFunctionPositionProviderAsset.DelimiterAsset.class, FieldFunctionPositionProviderAsset.DelimiterAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FrameworkPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FrameworkPositionProviderAsset.java new file mode 100644 index 00000000..c1549ed4 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/FrameworkPositionProviderAsset.java @@ -0,0 +1,36 @@ +package com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders; + +import com.hypixel.hytale.builtin.hytalegenerator.LoggerUtil; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.PositionsFrameworkAsset; +import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; +import java.util.logging.Level; +import javax.annotation.Nonnull; + +public class FrameworkPositionProviderAsset extends PositionProviderAsset { + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder( + FrameworkPositionProviderAsset.class, FrameworkPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC + ) + .append(new KeyedCodec<>("Name", Codec.STRING, true), (asset, v) -> asset.name = v, asset -> asset.name) + .add() + .build(); + private String name = ""; + + @Override + public PositionProvider build(@Nonnull PositionProviderAsset.Argument argument) { + if (super.skip()) { + return PositionProvider.noPositionProvider(); + } else { + PositionProviderAsset baseAsset = PositionsFrameworkAsset.Entries.get(this.name, argument.referenceBundle); + if (baseAsset == null) { + LoggerUtil.getLogger().log(Level.WARNING, "Couldn't find WorldFramework Positions with name " + this.name); + return PositionProvider.noPositionProvider(); + } else { + return baseAsset.build(argument); + } + } + } +} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/ImportedPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/ImportedPositionProviderAsset.java index f4652829..8fcc12fd 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/ImportedPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/ImportedPositionProviderAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ImportedPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedPositionProviderAsset.class, ImportedPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/ListPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/ListPositionProviderAsset.java index 4c04dd12..611a9081 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/ListPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/ListPositionProviderAsset.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class ListPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ListPositionProviderAsset.class, ListPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) @@ -45,6 +46,7 @@ public class ListPositionProviderAsset extends PositionProviderAsset { } public static class PositionAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( ListPositionProviderAsset.PositionAsset.class, ListPositionProviderAsset.PositionAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/Mesh2DPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/Mesh2DPositionProviderAsset.java index 7909f935..18cea4e5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/Mesh2DPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/Mesh2DPositionProviderAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class Mesh2DPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Mesh2DPositionProviderAsset.class, Mesh2DPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/Mesh3DPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/Mesh3DPositionProviderAsset.java index 2fa191d9..e8c5f30f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/Mesh3DPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/Mesh3DPositionProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class Mesh3DPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( Mesh3DPositionProviderAsset.class, Mesh3DPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/OffsetPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/OffsetPositionProviderAsset.java index 7ce681e3..0c75cc78 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/OffsetPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/OffsetPositionProviderAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class OffsetPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( OffsetPositionProviderAsset.class, OffsetPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) @@ -23,9 +24,9 @@ public class OffsetPositionProviderAsset extends PositionProviderAsset { ) .add() .build(); - private int offsetX = 0; - private int offsetY = 0; - private int offsetZ = 0; + private int offsetX; + private int offsetY; + private int offsetZ; private PositionProviderAsset positionProviderAsset = new ListPositionProviderAsset(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/PositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/PositionProviderAsset.java index 16687a88..248d1a88 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/PositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/PositionProviderAsset.java @@ -20,12 +20,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class PositionProviderAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(PositionProviderAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(PositionProviderAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -71,18 +76,18 @@ public abstract class PositionProviderAsset implements Cleanable, JsonAssetWithM public static class Argument { public SeedBox parentSeed; public ReferenceBundle referenceBundle; - public WorkerIndexer workerIndexer; + public WorkerIndexer.Id workerId; - public Argument(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public Argument(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer.Id workerId) { this.parentSeed = parentSeed; this.referenceBundle = referenceBundle; - this.workerIndexer = workerIndexer; + this.workerId = workerId; } public Argument(@Nonnull PositionProviderAsset.Argument argument) { this.parentSeed = argument.parentSeed; this.referenceBundle = argument.referenceBundle; - this.workerIndexer = argument.workerIndexer; + this.workerId = argument.workerId; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/SimpleHorizontalPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/SimpleHorizontalPositionProviderAsset.java index 98b92b3e..70fee1b2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/SimpleHorizontalPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/SimpleHorizontalPositionProviderAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class SimpleHorizontalPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SimpleHorizontalPositionProviderAsset.class, SimpleHorizontalPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/SpherePositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/SpherePositionProviderAsset.java deleted file mode 100644 index e37892c9..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/SpherePositionProviderAsset.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders; - -import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; -import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.SpherePositionProvider; -import com.hypixel.hytale.codec.Codec; -import com.hypixel.hytale.codec.KeyedCodec; -import com.hypixel.hytale.codec.builder.BuilderCodec; -import javax.annotation.Nonnull; - -public class SpherePositionProviderAsset extends PositionProviderAsset { - public static final BuilderCodec CODEC = BuilderCodec.builder( - SpherePositionProviderAsset.class, SpherePositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC - ) - .append(new KeyedCodec<>("Range", Codec.DOUBLE, false), (t, k) -> t.range = k, k -> k.range) - .add() - .append(new KeyedCodec<>("Positions", PositionProviderAsset.CODEC, true), (t, k) -> t.positionProviderAsset = k, k -> k.positionProviderAsset) - .add() - .build(); - private double range = 0.0; - private PositionProviderAsset positionProviderAsset = new ListPositionProviderAsset(); - - @Nonnull - @Override - public PositionProvider build(@Nonnull PositionProviderAsset.Argument argument) { - if (super.skip()) { - return PositionProvider.noPositionProvider(); - } else { - PositionProvider positionProvider = this.positionProviderAsset == null - ? PositionProvider.noPositionProvider() - : this.positionProviderAsset.build(argument); - return new SpherePositionProvider(positionProvider, this.range); - } - } - - @Override - public void cleanUp() { - this.positionProviderAsset.cleanUp(); - } -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/UnionPositionProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/UnionPositionProviderAsset.java index 57c405f6..24c4d820 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/UnionPositionProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/positionproviders/UnionPositionProviderAsset.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class UnionPositionProviderAsset extends PositionProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( UnionPositionProviderAsset.class, UnionPositionProviderAsset::new, PositionProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/AssignmentsAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/AssignmentsAsset.java index 011adbfa..d21485da 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/AssignmentsAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/AssignmentsAsset.java @@ -21,12 +21,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class AssignmentsAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(AssignmentsAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(AssignmentsAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -45,7 +50,7 @@ public abstract class AssignmentsAsset implements Cleanable, JsonAssetWithMap CODEC = BuilderCodec.builder( ConstantAssignmentsAsset.class, ConstantAssignmentsAsset::new, AssignmentsAsset.ABSTRACT_CODEC ) @@ -24,8 +25,7 @@ public class ConstantAssignmentsAsset extends AssignmentsAsset { if (super.skip()) { return Assignments.noPropDistribution(argument.runtime); } else { - Prop prop = this.propAsset - .build(new PropAsset.Argument(argument.parentSeed, argument.materialCache, argument.referenceBundle, argument.workerIndexer)); + Prop prop = this.propAsset.build(new PropAsset.Argument(argument.parentSeed, argument.materialCache, argument.referenceBundle, argument.workerId)); return new ConstantAssignments(prop, argument.runtime); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/FieldFunctionAssignmentsAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/FieldFunctionAssignmentsAsset.java index 6791e573..2beebb65 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/FieldFunctionAssignmentsAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/FieldFunctionAssignmentsAsset.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class FieldFunctionAssignmentsAsset extends AssignmentsAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( FieldFunctionAssignmentsAsset.class, FieldFunctionAssignmentsAsset::new, AssignmentsAsset.ABSTRACT_CODEC ) @@ -60,6 +61,7 @@ public class FieldFunctionAssignmentsAsset extends AssignmentsAsset { } public static class DelimiterAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( FieldFunctionAssignmentsAsset.DelimiterAsset.class, FieldFunctionAssignmentsAsset.DelimiterAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/ImportedAssignmentsAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/ImportedAssignmentsAsset.java index ae8f3f91..22434359 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/ImportedAssignmentsAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/ImportedAssignmentsAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class ImportedAssignmentsAsset extends AssignmentsAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedAssignmentsAsset.class, ImportedAssignmentsAsset::new, AssignmentsAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/SandwichAssignmentsAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/SandwichAssignmentsAsset.java index bf538969..160788f3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/SandwichAssignmentsAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/SandwichAssignmentsAsset.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class SandwichAssignmentsAsset extends AssignmentsAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( SandwichAssignmentsAsset.class, SandwichAssignmentsAsset::new, AssignmentsAsset.ABSTRACT_CODEC ) @@ -53,6 +54,7 @@ public class SandwichAssignmentsAsset extends AssignmentsAsset { } public static class DelimiterAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( SandwichAssignmentsAsset.DelimiterAsset.class, SandwichAssignmentsAsset.DelimiterAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/WeightedAssignmentsAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/WeightedAssignmentsAsset.java index 91a58472..b2a9a244 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/WeightedAssignmentsAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propassignments/WeightedAssignmentsAsset.java @@ -16,6 +16,7 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import javax.annotation.Nonnull; public class WeightedAssignmentsAsset extends AssignmentsAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( WeightedAssignmentsAsset.class, WeightedAssignmentsAsset::new, AssignmentsAsset.ABSTRACT_CODEC ) @@ -61,6 +62,7 @@ public class WeightedAssignmentsAsset extends AssignmentsAsset { } public static class WeightedAssets implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( WeightedAssignmentsAsset.WeightedAssets.class, WeightedAssignmentsAsset.WeightedAssets::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/BoxPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/BoxPropAsset.java index 4f68c49a..43dc2f8e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/BoxPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/BoxPropAsset.java @@ -14,6 +14,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class BoxPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(BoxPropAsset.class, BoxPropAsset::new, PropAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Range", Vector3i.CODEC, true), (asset, v) -> asset.range = v, asset -> asset.range) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ClusterPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ClusterPropAsset.java index 4c7f0426..af390dcb 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ClusterPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ClusterPropAsset.java @@ -28,6 +28,7 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class ClusterPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ClusterPropAsset.class, ClusterPropAsset::new, PropAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Range", Codec.INTEGER, false), (asset, v) -> asset.range = v, asset -> asset.range) .addValidator(Validators.greaterThanOrEqual(0)) @@ -95,6 +96,7 @@ public class ClusterPropAsset extends PropAsset { } public static class WeightedPropAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( ClusterPropAsset.WeightedPropAsset.class, ClusterPropAsset.WeightedPropAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ColumnPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ColumnPropAsset.java index d7034239..5650772d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ColumnPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ColumnPropAsset.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class ColumnPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ColumnPropAsset.class, ColumnPropAsset::new, PropAsset.ABSTRACT_CODEC) .append( new KeyedCodec<>("ColumnBlocks", new ArrayCodec<>(ColumnPropAsset.ColumnBlock.CODEC, ColumnPropAsset.ColumnBlock[]::new), true), @@ -61,7 +62,7 @@ public class ColumnPropAsset extends PropAsset { blockTypes.add(this.columnBlocks[i].materialAsset.build(argument.materialCache)); } - BlockMask blockMask = null; + BlockMask blockMask; if (this.blockMaskAsset != null) { blockMask = this.blockMaskAsset.build(argument.materialCache); } else { @@ -82,6 +83,7 @@ public class ColumnPropAsset extends PropAsset { } public static class ColumnBlock implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( ColumnPropAsset.ColumnBlock.class, ColumnPropAsset.ColumnBlock::new, @@ -99,7 +101,7 @@ public class ColumnPropAsset extends PropAsset { private String id; private AssetExtraInfo.Data data; private int y = 1; - private MaterialAsset materialAsset = new MaterialAsset("Empty", "Empty"); + private MaterialAsset materialAsset = new MaterialAsset("Empty", "Empty", false); public String getId() { return this.id; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/DensityPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/DensityPropAsset.java index 411849b2..ba34a7fd 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/DensityPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/DensityPropAsset.java @@ -20,6 +20,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class DensityPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(DensityPropAsset.class, DensityPropAsset::new, PropAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Range", Vector3i.CODEC, true), (asset, v) -> asset.range = v, asset -> asset.range) .addValidator((LegacyValidator)((v, r) -> { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ImportedPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ImportedPropAsset.java index 09936da1..6c9e6376 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ImportedPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/ImportedPropAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class ImportedPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(ImportedPropAsset.class, ImportedPropAsset::new, PropAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Name", Codec.STRING, true), (asset, v) -> asset.name = v, asset -> asset.name) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/NoPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/NoPropAsset.java index cc2e4110..2f19fb2c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/NoPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/NoPropAsset.java @@ -13,14 +13,17 @@ import javax.annotation.Nonnull; import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class NoPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(NoPropAsset.class, NoPropAsset::new, PropAsset.ABSTRACT_CODEC).build(); @Nonnull @Override public Prop build(@Nonnull PropAsset.Argument argument) { return new Prop() { + @Nonnull final Bounds3i emptyBounds_voxelGrid = new Bounds3i(); + @Nonnull @Override public ScanResult scan(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { return ScanResult.noScanResult(); @@ -30,6 +33,7 @@ public class NoPropAsset extends PropAsset { public void place(@Nonnull Prop.Context context) { } + @Nonnull @Override public ContextDependency getContextDependency() { return ContextDependency.EMPTY; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/OffsetPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/OffsetPropAsset.java index bf4e43d0..19345d22 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/OffsetPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/OffsetPropAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class OffsetPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(OffsetPropAsset.class, OffsetPropAsset::new, PropAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("Offset", Vector3i.CODEC, true), (asset, value) -> asset.offset_voxelGrid = value, asset -> asset.offset_voxelGrid) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/PondFillerPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/PondFillerPropAsset.java index ba707d72..724f0e81 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/PondFillerPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/PondFillerPropAsset.java @@ -20,6 +20,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class PondFillerPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( PondFillerPropAsset.class, PondFillerPropAsset::new, PropAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/PropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/PropAsset.java index b36d0cb2..6c9f750f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/PropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/PropAsset.java @@ -21,12 +21,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class PropAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(PropAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(PropAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -73,21 +78,22 @@ public abstract class PropAsset implements Cleanable, JsonAssetWithMap CODEC = BuilderCodec.builder(QueuePropAsset.class, QueuePropAsset::new, PropAsset.ABSTRACT_CODEC) .append( new KeyedCodec<>("Queue", new ArrayCodec<>(PropAsset.CODEC, PropAsset[]::new), true), (asset, v) -> asset.propAssets = v, asset -> asset.propAssets diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/UnionPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/UnionPropAsset.java index 0331d6ae..256af177 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/UnionPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/UnionPropAsset.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import javax.annotation.Nonnull; public class UnionPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(UnionPropAsset.class, UnionPropAsset::new, PropAsset.ABSTRACT_CODEC) .append( new KeyedCodec<>("Props", new ArrayCodec<>(PropAsset.CODEC, PropAsset[]::new), true), (asset, v) -> asset.propAssets = v, asset -> asset.propAssets diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/WeightedPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/WeightedPropAsset.java index 069aa954..cb950637 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/WeightedPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/WeightedPropAsset.java @@ -16,6 +16,7 @@ import com.hypixel.hytale.codec.validation.Validators; import javax.annotation.Nonnull; public class WeightedPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(WeightedPropAsset.class, WeightedPropAsset::new, PropAsset.ABSTRACT_CODEC) .append( new KeyedCodec<>("Entries", new ArrayCodec<>(WeightedPropAsset.EntryAsset.CODEC, WeightedPropAsset.EntryAsset[]::new), true), @@ -55,6 +56,7 @@ public class WeightedPropAsset extends PropAsset { } public static class EntryAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( WeightedPropAsset.EntryAsset.class, WeightedPropAsset.EntryAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/PrefabLoader.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/PrefabLoader.java index 8746996d..8adc590e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/PrefabLoader.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/PrefabLoader.java @@ -14,8 +14,7 @@ import javax.annotation.Nullable; import org.bson.BsonDocument; public class PrefabLoader { - @Nonnull - public static void loadAllPrefabBuffersUnder(@Nonnull Path dirPath, List pathPrefabs) { + public static void loadAllPrefabBuffersUnder(@Nonnull Path dirPath, @Nonnull List pathPrefabs) { if (!Files.isDirectory(dirPath)) { PrefabBuffer prefab = loadPrefabBufferAt(dirPath); if (prefab != null) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/PrefabPropAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/PrefabPropAsset.java index e5f382af..a919a244 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/PrefabPropAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/PrefabPropAsset.java @@ -30,6 +30,7 @@ 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.util.ExceptionUtil; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.prefab.selection.buffer.impl.PrefabBuffer; @@ -40,6 +41,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PrefabPropAsset extends PropAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(PrefabPropAsset.class, PrefabPropAsset::new, PropAsset.ABSTRACT_CODEC) .append( new KeyedCodec<>("WeightedPrefabPaths", new ArrayCodec<>(PrefabPropAsset.WeightedPathAsset.CODEC, PrefabPropAsset.WeightedPathAsset[]::new), true), @@ -150,21 +152,25 @@ public class PrefabPropAsset extends PropAsset { List pathPrefabs = new ArrayList<>(); for (AssetPack pack : AssetModule.get().getAssetPacks()) { - Path fullPath = pack.getRoot().resolve("Server"); + Path prefabsDir = pack.getRoot().resolve("Server"); if (this.legacyPath) { - fullPath = fullPath.resolve("World").resolve("Default").resolve("Prefabs"); + prefabsDir = prefabsDir.resolve("World").resolve("Default").resolve("Prefabs"); } else { - fullPath = fullPath.resolve("Prefabs"); + prefabsDir = prefabsDir.resolve("Prefabs"); } - fullPath = fullPath.resolve(path); + Path fullPath = PathUtil.resolvePathWithinDir(prefabsDir, path); + if (fullPath == null) { + LoggerUtil.getLogger().severe("Invalid prefab path: " + path); + return null; + } try { PrefabLoader.loadAllPrefabBuffersUnder(fullPath, pathPrefabs); - } catch (Exception var8) { + } catch (Exception var9) { String msg = "Couldn't load prefab with path: " + path; msg = msg + "\n"; - msg = msg + ExceptionUtil.toStringWithStack(var8); + msg = msg + ExceptionUtil.toStringWithStack(var9); LoggerUtil.getLogger().severe(msg); return null; } @@ -179,6 +185,7 @@ public class PrefabPropAsset extends PropAsset { } public static class WeightedPathAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( PrefabPropAsset.WeightedPathAsset.class, PrefabPropAsset.WeightedPathAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/DirectionalityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/DirectionalityAsset.java index ede3ed98..f2077dc6 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/DirectionalityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/DirectionalityAsset.java @@ -22,12 +22,17 @@ import java.util.Map; import javax.annotation.Nonnull; public abstract class DirectionalityAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new HashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(DirectionalityAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(DirectionalityAsset.class) .append(new KeyedCodec<>("ExportAs", Codec.STRING, false), (t, k) -> t.exportName = k, t -> t.exportName) .add() @@ -61,29 +66,29 @@ public abstract class DirectionalityAsset implements Cleanable, JsonAssetWithMap @Nonnull public static DirectionalityAsset.Argument argumentFrom(@Nonnull PropAsset.Argument argument) { - return new DirectionalityAsset.Argument(argument.parentSeed, argument.materialCache, argument.referenceBundle, argument.workerIndexer); + return new DirectionalityAsset.Argument(argument.parentSeed, argument.materialCache, argument.referenceBundle, argument.workerId); } public static class Argument { public SeedBox parentSeed; public MaterialCache materialCache; public ReferenceBundle referenceBundle; - public WorkerIndexer workerIndexer; + public WorkerIndexer.Id workerId; public Argument( - @Nonnull SeedBox parentSeed, @Nonnull MaterialCache materialCache, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer + @Nonnull SeedBox parentSeed, @Nonnull MaterialCache materialCache, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer.Id workerId ) { this.parentSeed = parentSeed; this.materialCache = materialCache; this.referenceBundle = referenceBundle; - this.workerIndexer = workerIndexer; + this.workerId = workerId; } public Argument(@Nonnull DirectionalityAsset.Argument argument) { this.parentSeed = argument.parentSeed; this.materialCache = argument.materialCache; this.referenceBundle = argument.referenceBundle; - this.workerIndexer = argument.workerIndexer; + this.workerId = argument.workerId; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/ImportedDirectionalityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/ImportedDirectionalityAsset.java index 307657ef..4084414a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/ImportedDirectionalityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/ImportedDirectionalityAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class ImportedDirectionalityAsset extends DirectionalityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedDirectionalityAsset.class, ImportedDirectionalityAsset::new, DirectionalityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/PatternDirectionalityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/PatternDirectionalityAsset.java index 66e7a489..f289af82 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/PatternDirectionalityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/PatternDirectionalityAsset.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class PatternDirectionalityAsset extends DirectionalityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( PatternDirectionalityAsset.class, PatternDirectionalityAsset::new, DirectionalityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/RandomDirectionalityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/RandomDirectionalityAsset.java index 82d6b84e..4b6b4cfd 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/RandomDirectionalityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/RandomDirectionalityAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class RandomDirectionalityAsset extends DirectionalityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( RandomDirectionalityAsset.class, RandomDirectionalityAsset::new, DirectionalityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/StaticDirectionalityAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/StaticDirectionalityAsset.java index 146d6ca2..9f7ae2f3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/StaticDirectionalityAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/props/prefabprop/directionality/StaticDirectionalityAsset.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.server.core.prefab.PrefabRotation; import javax.annotation.Nonnull; public class StaticDirectionalityAsset extends DirectionalityAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( StaticDirectionalityAsset.class, StaticDirectionalityAsset::new, DirectionalityAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propstageiterations/PropRuntimeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propstageiterations/PropRuntimeAsset.java index 95ec5a6a..471bee58 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propstageiterations/PropRuntimeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/propstageiterations/PropRuntimeAsset.java @@ -20,6 +20,7 @@ import com.hypixel.hytale.codec.KeyedCodec; import javax.annotation.Nonnull; public class PropRuntimeAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( PropRuntimeAsset.class, PropRuntimeAsset::new, @@ -58,8 +59,8 @@ public class PropRuntimeAsset implements Cleanable, JsonAssetWithMap CODEC = BuilderCodec.builder(AreaScannerAsset.class, AreaScannerAsset::new, ScannerAsset.ABSTRACT_CODEC) .append(new KeyedCodec<>("ResultCap", Codec.INTEGER, true), (t, k) -> t.resultCap = k, k -> k.resultCap) .addValidator(Validators.greaterThanOrEqual(0)) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ColumnLinearScannerAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ColumnLinearScannerAsset.java index 5670796a..35cd6371 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ColumnLinearScannerAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ColumnLinearScannerAsset.java @@ -1,17 +1,16 @@ package com.hypixel.hytale.builtin.hytalegenerator.assets.scanners; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; -import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.BaseHeightReference; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.DecimalConstantsFrameworkAsset; import com.hypixel.hytale.builtin.hytalegenerator.scanners.ColumnLinearScanner; import com.hypixel.hytale.builtin.hytalegenerator.scanners.Scanner; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.validation.Validators; -import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class ColumnLinearScannerAsset extends ScannerAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ColumnLinearScannerAsset.class, ColumnLinearScannerAsset::new, ScannerAsset.ABSTRACT_CODEC ) @@ -26,7 +25,7 @@ public class ColumnLinearScannerAsset extends ScannerAsset { .add() .append(new KeyedCodec<>("RelativeToPosition", Codec.BOOLEAN, false), (t, k) -> t.isRelativeToPosition = k, k -> k.isRelativeToPosition) .add() - .append(new KeyedCodec<>("BaseHeightName", Codec.STRING, false), (t, k) -> t.baseHeight = k, k -> k.baseHeight) + .append(new KeyedCodec<>("BaseHeightName", Codec.STRING, false), (t, k) -> t.baseHeightName = k, k -> k.baseHeightName) .add() .build(); private int minY = 0; @@ -34,7 +33,7 @@ public class ColumnLinearScannerAsset extends ScannerAsset { private int resultCap = 1; private boolean topDownOrder = true; private boolean isRelativeToPosition = false; - private String baseHeight = ""; + private String baseHeightName = ""; @Nonnull @Override @@ -42,16 +41,14 @@ public class ColumnLinearScannerAsset extends ScannerAsset { if (super.skip()) { return Scanner.noScanner(); } else if (this.isRelativeToPosition) { - return new ColumnLinearScanner(this.minY, this.maxY, this.resultCap, this.topDownOrder, true, null); + return new ColumnLinearScanner(this.minY, this.maxY, this.resultCap, this.topDownOrder, true, 0.0); } else { - BaseHeightReference heightDataLayer = argument.referenceBundle.getLayerWithName(this.baseHeight, BaseHeightReference.class); - if (heightDataLayer == null) { - HytaleLogger.getLogger().atConfig().log("Couldn't find height data layer with name \"" + this.baseHeight + "\", defaulting to not using a bed."); - return new ColumnLinearScanner(this.minY, this.maxY, this.resultCap, this.topDownOrder, false, null); - } else { - BiDouble2DoubleFunction baseHeightFunction = heightDataLayer.getHeightFunction(); - return new ColumnLinearScanner(this.minY, this.maxY, this.resultCap, this.topDownOrder, false, baseHeightFunction); + Double baseHeight = DecimalConstantsFrameworkAsset.Entries.get(this.baseHeightName, argument.referenceBundle); + if (baseHeight == null) { + baseHeight = 0.0; } + + return new ColumnLinearScanner(this.minY, this.maxY, this.resultCap, this.topDownOrder, false, baseHeight); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ColumnRandomScannerAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ColumnRandomScannerAsset.java index 247f2aea..d6df6200 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ColumnRandomScannerAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ColumnRandomScannerAsset.java @@ -1,8 +1,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.assets.scanners; import com.hypixel.hytale.builtin.hytalegenerator.assets.ValidatorUtil; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; -import com.hypixel.hytale.builtin.hytalegenerator.referencebundle.BaseHeightReference; +import com.hypixel.hytale.builtin.hytalegenerator.assets.framework.DecimalConstantsFrameworkAsset; import com.hypixel.hytale.builtin.hytalegenerator.scanners.ColumnRandomScanner; import com.hypixel.hytale.builtin.hytalegenerator.scanners.Scanner; import com.hypixel.hytale.builtin.hytalegenerator.seed.SeedBox; @@ -10,10 +9,10 @@ import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.validation.Validators; -import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class ColumnRandomScannerAsset extends ScannerAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ColumnRandomScannerAsset.class, ColumnRandomScannerAsset::new, ScannerAsset.ABSTRACT_CODEC ) @@ -31,7 +30,7 @@ public class ColumnRandomScannerAsset extends ScannerAsset { .add() .append(new KeyedCodec<>("RelativeToPosition", Codec.BOOLEAN, false), (t, k) -> t.isRelativeToPosition = k, k -> k.isRelativeToPosition) .add() - .append(new KeyedCodec<>("BaseHeightName", Codec.STRING, false), (t, k) -> t.baseHeight = k, k -> k.baseHeight) + .append(new KeyedCodec<>("BaseHeightName", Codec.STRING, false), (t, k) -> t.baseHeightName = k, k -> k.baseHeightName) .add() .build(); private int minY = 0; @@ -40,7 +39,7 @@ public class ColumnRandomScannerAsset extends ScannerAsset { private String seed = "A"; private String strategyName = "DART_THROW"; private boolean isRelativeToPosition = false; - private String baseHeight = ""; + private String baseHeightName = ""; @Nonnull @Override @@ -51,16 +50,14 @@ public class ColumnRandomScannerAsset extends ScannerAsset { SeedBox childSeed = argument.parentSeed.child(this.seed); ColumnRandomScanner.Strategy strategy = ColumnRandomScanner.Strategy.valueOf(this.strategyName); if (this.isRelativeToPosition) { - return new ColumnRandomScanner(this.minY, this.maxY, this.resultCap, childSeed.createSupplier().get(), strategy, true, null); + return new ColumnRandomScanner(this.minY, this.maxY, this.resultCap, childSeed.createSupplier().get(), strategy, true, 0.0); } else { - BaseHeightReference heightDataLayer = argument.referenceBundle.getLayerWithName(this.baseHeight, BaseHeightReference.class); - if (heightDataLayer == null) { - HytaleLogger.getLogger().atConfig().log("Couldn't find height data layer with name \"" + this.baseHeight + "\", defaulting to not using a bed."); - return new ColumnRandomScanner(this.minY, this.maxY, this.resultCap, childSeed.createSupplier().get(), strategy, false, null); - } else { - BiDouble2DoubleFunction baseHeightFunction = heightDataLayer.getHeightFunction(); - return new ColumnRandomScanner(this.minY, this.maxY, this.resultCap, childSeed.createSupplier().get(), strategy, false, baseHeightFunction); + Double baseHeight = DecimalConstantsFrameworkAsset.Entries.get(this.baseHeightName, argument.referenceBundle); + if (baseHeight == null) { + baseHeight = 0.0; } + + return new ColumnRandomScanner(this.minY, this.maxY, this.resultCap, childSeed.createSupplier().get(), strategy, false, baseHeight); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ImportedScannerAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ImportedScannerAsset.java index 8555e53a..1dcaac24 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ImportedScannerAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ImportedScannerAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import javax.annotation.Nonnull; public class ImportedScannerAsset extends ScannerAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedScannerAsset.class, ImportedScannerAsset::new, ScannerAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/OriginScannerAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/OriginScannerAsset.java index 40b77bbc..600b9878 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/OriginScannerAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/OriginScannerAsset.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class OriginScannerAsset extends ScannerAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( OriginScannerAsset.class, OriginScannerAsset::new, ScannerAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ScannerAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ScannerAsset.java index 2c839349..212f826d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ScannerAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/scanners/ScannerAsset.java @@ -20,12 +20,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class ScannerAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(ScannerAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(ScannerAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/terrains/DensityTerrainAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/terrains/DensityTerrainAsset.java index 92f30acd..2a64f3a4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/terrains/DensityTerrainAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/terrains/DensityTerrainAsset.java @@ -11,6 +11,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import javax.annotation.Nonnull; public class DensityTerrainAsset extends TerrainAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DensityTerrainAsset.class, DensityTerrainAsset::new, TerrainAsset.ABSTRACT_CODEC ) @@ -22,8 +23,8 @@ public class DensityTerrainAsset extends TerrainAsset { @Nonnull @Override - public Density buildDensity(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { - return this.densityAsset.build(new DensityAsset.Argument(parentSeed, referenceBundle, workerIndexer)); + public Density buildDensity(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer.Id workerId) { + return this.densityAsset.build(new DensityAsset.Argument(parentSeed, referenceBundle, workerId)); } @Override diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/terrains/TerrainAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/terrains/TerrainAsset.java index 45320dd7..f4cb7a1b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/terrains/TerrainAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/terrains/TerrainAsset.java @@ -16,22 +16,28 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import javax.annotation.Nonnull; public abstract class TerrainAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull private static final TerrainAsset[] EMPTY_INPUTS = new TerrainAsset[0]; + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(TerrainAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(TerrainAsset.class).build(); private String id; private AssetExtraInfo.Data data; + @Nonnull private TerrainAsset[] inputs = EMPTY_INPUTS; private boolean skip = false; protected TerrainAsset() { } - public abstract Density buildDensity(@Nonnull SeedBox var1, @Nonnull ReferenceBundle var2, @Nonnull WorkerIndexer var3); + public abstract Density buildDensity(@Nonnull SeedBox var1, @Nonnull ReferenceBundle var2, @Nonnull WorkerIndexer.Id var3); public String getId() { return this.id; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/ConstantTintProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/ConstantTintProviderAsset.java index 74e846b6..8f3d2ab0 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/ConstantTintProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/ConstantTintProviderAsset.java @@ -10,7 +10,9 @@ import com.hypixel.hytale.server.core.codec.ProtocolCodecs; import javax.annotation.Nonnull; public class ConstantTintProviderAsset extends TintProviderAsset { + @Nonnull public static final Color DEFAULT_COLOR = ColorParseUtil.hexStringToColor("#FF0000"); + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ConstantTintProviderAsset.class, ConstantTintProviderAsset::new, TintProviderAsset.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/DensityDelimitedTintProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/DensityDelimitedTintProviderAsset.java index 5c60f5db..dae46e93 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/DensityDelimitedTintProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/DensityDelimitedTintProviderAsset.java @@ -20,6 +20,7 @@ import java.util.List; import javax.annotation.Nonnull; public class DensityDelimitedTintProviderAsset extends TintProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DensityDelimitedTintProviderAsset.class, DensityDelimitedTintProviderAsset::new, TintProviderAsset.ABSTRACT_CODEC ) @@ -57,6 +58,7 @@ public class DensityDelimitedTintProviderAsset extends TintProviderAsset { } public static class DelimiterAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( DensityDelimitedTintProviderAsset.DelimiterAsset.class, DensityDelimitedTintProviderAsset.DelimiterAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/TintProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/TintProviderAsset.java index c9f540d0..74f6f9b7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/TintProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/tintproviders/TintProviderAsset.java @@ -21,12 +21,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class TintProviderAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(TintProviderAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(TintProviderAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -78,22 +83,22 @@ public abstract class TintProviderAsset implements Cleanable, JsonAssetWithMap CODEC = BuilderCodec.builder( CacheVectorProviderAsset.class, CacheVectorProviderAsset::new, ABSTRACT_CODEC ) @@ -28,13 +29,14 @@ public class CacheVectorProviderAsset extends VectorProviderAsset { this.vectorProviderAsset = vectorProviderAsset; } + @Nonnull @Override public VectorProvider build(@Nonnull VectorProviderAsset.Argument argument) { if (this.isSkipped()) { return new ConstantVectorProvider(new Vector3d()); } else { VectorProvider vectorProvider = this.vectorProviderAsset.build(argument); - return new CacheVectorProvider(vectorProvider, argument.workerIndexer.getWorkerCount()); + return new CacheVectorProvider(vectorProvider); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ConstantVectorProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ConstantVectorProviderAsset.java index ac8b2f4e..e69d4d73 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ConstantVectorProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ConstantVectorProviderAsset.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class ConstantVectorProviderAsset extends VectorProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ConstantVectorProviderAsset.class, ConstantVectorProviderAsset::new, ABSTRACT_CODEC ) @@ -23,6 +24,7 @@ public class ConstantVectorProviderAsset extends VectorProviderAsset { this.value.assign(vector); } + @Nonnull @Override public VectorProvider build(@Nonnull VectorProviderAsset.Argument argument) { return this.isSkipped() ? new ConstantVectorProvider(new Vector3d()) : new ConstantVectorProvider(this.value); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/DensityGradientVectorProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/DensityGradientVectorProviderAsset.java index 4b5fd657..17047208 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/DensityGradientVectorProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/DensityGradientVectorProviderAsset.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class DensityGradientVectorProviderAsset extends VectorProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( DensityGradientVectorProviderAsset.class, DensityGradientVectorProviderAsset::new, VectorProviderAsset.ABSTRACT_CODEC ) @@ -27,6 +28,7 @@ public class DensityGradientVectorProviderAsset extends VectorProviderAsset { private DensityAsset densityAsset = new ConstantDensityAsset(); private double sampleDistance = 1.0; + @Nonnull @Override public VectorProvider build(@Nonnull VectorProviderAsset.Argument argument) { if (this.isSkipped()) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ExportedVectorProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ExportedVectorProviderAsset.java index 0c9386e7..038ceb07 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ExportedVectorProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ExportedVectorProviderAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class ExportedVectorProviderAsset extends VectorProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ExportedVectorProviderAsset.class, ExportedVectorProviderAsset::new, VectorProviderAsset.ABSTRACT_CODEC ) @@ -32,19 +33,16 @@ public class ExportedVectorProviderAsset extends VectorProviderAsset { } else { VectorProviderAsset.Exported exported = getExportedAsset(this.exportName); if (exported == null) { - LoggerUtil.getLogger() - .severe( - "Couldn't find VectorProvider asset exported with name: '" - + this.exportName - + "'. This could indicate a defect in the HytaleGenerator assets." - ); - return this.vectorProviderAsset.build(argument); - } else if (exported.singleInstance) { - if (exported.builtInstance == null) { - exported.builtInstance = this.vectorProviderAsset.build(argument); + LoggerUtil.getLogger().warning("Couldn't find VectorProvider asset exported with name: '" + this.exportName + "'. Using empty Node instead."); + return new ConstantVectorProvider(new Vector3d()); + } else if (exported.isSingleInstance) { + VectorProvider builtInstance = exported.threadInstances.get(argument.workerId); + if (builtInstance == null) { + builtInstance = this.vectorProviderAsset.build(argument); + exported.threadInstances.put(argument.workerId, builtInstance); } - return exported.builtInstance; + return builtInstance; } else { return this.vectorProviderAsset.build(argument); } @@ -55,7 +53,7 @@ public class ExportedVectorProviderAsset extends VectorProviderAsset { public void cleanUp() { VectorProviderAsset.Exported exported = getExportedAsset(this.exportName); if (exported != null) { - exported.builtInstance = null; + exported.threadInstances.clear(); this.vectorProviderAsset.cleanUp(); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ImportedVectorProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ImportedVectorProviderAsset.java index 8aec94fb..237a3ff9 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ImportedVectorProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/ImportedVectorProviderAsset.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class ImportedVectorProviderAsset extends VectorProviderAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ImportedVectorProviderAsset.class, ImportedVectorProviderAsset::new, VectorProviderAsset.ABSTRACT_CODEC ) @@ -27,12 +28,14 @@ public class ImportedVectorProviderAsset extends VectorProviderAsset { if (exported == null) { LoggerUtil.getLogger().warning("Couldn't find VectorProvider asset exported with name: '" + this.importedNodeName + "'. Using empty Node instead."); return new ConstantVectorProvider(new Vector3d()); - } else if (exported.singleInstance) { - if (exported.builtInstance == null) { - exported.builtInstance = exported.asset.build(argument); + } else if (exported.isSingleInstance) { + VectorProvider builtInstance = exported.threadInstances.get(argument.workerId); + if (builtInstance == null) { + builtInstance = exported.asset.build(argument); + exported.threadInstances.put(argument.workerId, builtInstance); } - return exported.builtInstance; + return builtInstance; } else { return exported.asset.build(argument); } @@ -43,7 +46,7 @@ public class ImportedVectorProviderAsset extends VectorProviderAsset { public void cleanUp() { VectorProviderAsset.Exported exported = getExportedAsset(this.importedNodeName); if (exported != null) { - exported.builtInstance = null; + exported.threadInstances.clear(); } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/VectorProviderAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/VectorProviderAsset.java index 8e27604b..36af173b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/VectorProviderAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/vectorproviders/VectorProviderAsset.java @@ -21,12 +21,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; public abstract class VectorProviderAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull private static final Map exportedNodes = new ConcurrentHashMap<>(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(VectorProviderAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(VectorProviderAsset.class) .append(new KeyedCodec<>("Skip", Codec.BOOLEAN, false), (t, k) -> t.skip = k, t -> t.skip) .add() @@ -38,14 +43,14 @@ public abstract class VectorProviderAsset implements Cleanable, JsonAssetWithMap LoggerUtil.getLogger().warning("Duplicate export name for asset: " + asset.exportName); } - VectorProviderAsset.Exported exported = new VectorProviderAsset.Exported(); - exported.asset = asset; + boolean isSingleInstance; if (asset instanceof ExportedVectorProviderAsset exportedAsset) { - exported.singleInstance = exportedAsset.isSingleInstance(); + isSingleInstance = exportedAsset.isSingleInstance(); } else { - exported.singleInstance = false; + isSingleInstance = false; } + VectorProviderAsset.Exported exported = new VectorProviderAsset.Exported(isSingleInstance, asset); exportedNodes.put(asset.exportName, exported); LoggerUtil.getLogger().fine("Registered imported node asset with name '" + asset.exportName + "' with asset id '" + asset.id); } @@ -80,30 +85,38 @@ public abstract class VectorProviderAsset implements Cleanable, JsonAssetWithMap public static class Argument { public SeedBox parentSeed; public ReferenceBundle referenceBundle; - public WorkerIndexer workerIndexer; + public WorkerIndexer.Id workerId; - public Argument(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer workerIndexer) { + public Argument(@Nonnull SeedBox parentSeed, @Nonnull ReferenceBundle referenceBundle, @Nonnull WorkerIndexer.Id workerId) { this.parentSeed = parentSeed; this.referenceBundle = referenceBundle; - this.workerIndexer = workerIndexer; + this.workerId = workerId; } public Argument(@Nonnull VectorProviderAsset.Argument argument) { this.parentSeed = argument.parentSeed; this.referenceBundle = argument.referenceBundle; - this.workerIndexer = argument.workerIndexer; + this.workerId = argument.workerId; } public Argument(@Nonnull DensityAsset.Argument argument) { this.parentSeed = argument.parentSeed; this.referenceBundle = argument.referenceBundle; - this.workerIndexer = argument.workerIndexer; + this.workerId = argument.workerId; } } public static class Exported { - public boolean singleInstance; + public boolean isSingleInstance; + @Nonnull public VectorProviderAsset asset; - public VectorProvider builtInstance; + @Nonnull + public Map 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..2ef58d1b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/WorldStructureAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/WorldStructureAsset.java @@ -6,22 +6,27 @@ 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.assets.positionproviders.PositionProviderAsset; 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; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public abstract class WorldStructureAsset implements Cleanable, JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(WorldStructureAsset.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(WorldStructureAsset.class).build(); private String id; private AssetExtraInfo.Data data; @@ -29,11 +34,11 @@ public abstract class WorldStructureAsset implements Cleanable, JsonAssetWithMap protected WorldStructureAsset() { } - public abstract BiomeMap buildBiomeMap(@Nonnull WorldStructureAsset.Argument var1); + @Nullable + public abstract WorldStructure build(@Nonnull WorldStructureAsset.Argument var1); - public abstract int getBiomeTransitionDistance(); - - public abstract int getMaxBiomeEdgeDistance(); + @Nonnull + public abstract PositionProviderAsset getSpawnPositionsAsset(); public String getId() { return this.id; @@ -46,18 +51,18 @@ public abstract class WorldStructureAsset implements Cleanable, JsonAssetWithMap public static class Argument { public MaterialCache materialCache; public SeedBox parentSeed; - public WorkerIndexer workerIndexer; + public WorkerIndexer.Id workerId; - public Argument(@Nonnull MaterialCache materialCache, @Nonnull SeedBox parentSeed, @Nonnull WorkerIndexer workerIndexer) { + public Argument(@Nonnull MaterialCache materialCache, @Nonnull SeedBox parentSeed, @Nonnull WorkerIndexer.Id workerId) { this.materialCache = materialCache; this.parentSeed = parentSeed; - this.workerIndexer = workerIndexer; + this.workerId = workerId; } public Argument(@Nonnull WorldStructureAsset.Argument argument) { this.materialCache = argument.materialCache; this.parentSeed = argument.parentSeed; - this.workerIndexer = argument.workerIndexer; + this.workerId = argument.workerId; } } } 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..c72fdaaa 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,21 @@ 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.framework.FrameworkAsset; +import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.ListPositionProviderAsset; +import com.hypixel.hytale.builtin.hytalegenerator.assets.positionproviders.PositionProviderAsset; 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.positionproviders.PositionProvider; 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; @@ -25,38 +26,52 @@ import com.hypixel.hytale.codec.validation.Validators; import java.util.HashMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class BasicWorldStructureAsset extends WorldStructureAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( BasicWorldStructureAsset.class, BasicWorldStructureAsset::new, WorldStructureAsset.ABSTRACT_CODEC ) .append( new KeyedCodec<>("Biomes", new ArrayCodec<>(BiomeRangeAsset.CODEC, BiomeRangeAsset[]::new), true), - (t, k) -> t.biomeRangeAssets = k, - t -> t.biomeRangeAssets + (asset, value) -> asset.biomeRangeAssets = value, + asset -> asset.biomeRangeAssets ) .add() - .append(new KeyedCodec<>("Density", DensityAsset.CODEC, true), (t, k) -> t.densityAsset = k, t -> t.densityAsset) + .append(new KeyedCodec<>("Density", DensityAsset.CODEC, true), (asset, value) -> asset.densityAsset = value, asset -> asset.densityAsset) .add() .append( new KeyedCodec<>("DefaultBiome", new ContainedAssetCodec<>(BiomeAsset.class, BiomeAsset.CODEC), true), - (t, k) -> t.defaultBiomeId = k, - t -> t.defaultBiomeId + (asset, value) -> asset.defaultBiomeId = value, + asset -> asset.defaultBiomeId ) .addValidatorLate(() -> BiomeAsset.VALIDATOR_CACHE.getValidator().late()) .add() .append( - new KeyedCodec<>("DefaultTransitionDistance", Codec.INTEGER, true), (t, k) -> t.biomeTransitionDistance = k, t -> t.biomeTransitionDistance + new KeyedCodec<>("DefaultTransitionDistance", Codec.INTEGER, true), + (asset, value) -> asset.biomeTransitionDistance = value, + asset -> asset.biomeTransitionDistance ) .addValidator(Validators.greaterThan(0)) .add() - .append(new KeyedCodec<>("MaxBiomeEdgeDistance", Codec.INTEGER, true), (t, k) -> t.maxBiomeEdgeDistance = k, t -> t.maxBiomeEdgeDistance) + .append( + new KeyedCodec<>("MaxBiomeEdgeDistance", Codec.INTEGER, true), + (asset, value) -> asset.maxBiomeEdgeDistance = value, + asset -> asset.maxBiomeEdgeDistance + ) .addValidator(Validators.greaterThanOrEqual(0)) .add() .append( - new KeyedCodec<>("ContentFields", new ArrayCodec<>(ContentFieldAsset.CODEC, ContentFieldAsset[]::new), false), - (t, k) -> t.contentFieldAssets = k, - t -> t.contentFieldAssets + new KeyedCodec<>("Framework", new ArrayCodec<>(FrameworkAsset.CODEC, FrameworkAsset[]::new), false), + (asset, value) -> asset.frameworkAssets = value, + asset -> asset.frameworkAssets + ) + .add() + .append( + new KeyedCodec<>("SpawnPositions", PositionProviderAsset.CODEC, false), + (asset, value) -> asset.spawnPositionsAsset = value, + asset -> asset.spawnPositionsAsset ) .add() .build(); @@ -65,32 +80,30 @@ public class BasicWorldStructureAsset extends WorldStructureAsset { private int maxBiomeEdgeDistance = 0; private DensityAsset densityAsset = new ConstantDensityAsset(); private String defaultBiomeId = ""; - private ContentFieldAsset[] contentFieldAssets = new ContentFieldAsset[0]; + private FrameworkAsset[] frameworkAssets = new FrameworkAsset[0]; + private PositionProviderAsset spawnPositionsAsset = new ListPositionProviderAsset(); @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--) { - if (this.contentFieldAssets[i] instanceof BaseHeightContentFieldAsset bedAsset) { - String name = bedAsset.getName(); - double y = bedAsset.getY(); - BaseHeightReference bedLayer = new BaseHeightReference((x, z) -> y); - referenceBundle.put(name, bedLayer, bedLayer.getClass()); - } + for (FrameworkAsset frameworkAsset : this.frameworkAssets) { + frameworkAsset.build(argument, referenceBundle); } - 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, argument.workerId); 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,41 +111,37 @@ 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, argument.workerId); 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 biomeTransitionDistance = Math.max(1, this.biomeTransitionDistance); + PositionProvider spawnPositions = this.spawnPositionsAsset + .build(new PositionProviderAsset.Argument(argument.parentSeed, referenceBundle, argument.workerId)); + return new WorldStructure(carta, biomeRegistry, biomeTransitionDistance, this.maxBiomeEdgeDistance, spawnPositions); } } + @NonNullDecl @Override - public int getBiomeTransitionDistance() { - return this.biomeTransitionDistance; - } - - @Override - public int getMaxBiomeEdgeDistance() { - return this.maxBiomeEdgeDistance; + public PositionProviderAsset getSpawnPositionsAsset() { + return this.spawnPositionsAsset; } @Override public void cleanUp() { this.densityAsset.cleanUp(); - for (ContentFieldAsset contentFieldAsset : this.contentFieldAssets) { - contentFieldAsset.cleanUp(); + for (FrameworkAsset frameworkAsset : this.frameworkAssets) { + frameworkAsset.cleanUp(); } BiomeAsset defaultBiomeAsset = (BiomeAsset)((DefaultAssetMap)BiomeAsset.getAssetStore().getAssetMap()).getAsset(this.defaultBiomeId); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/basic/BiomeRangeAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/basic/BiomeRangeAsset.java index 3715b2ae..c1580b67 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/basic/BiomeRangeAsset.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/basic/BiomeRangeAsset.java @@ -13,6 +13,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BiomeRangeAsset implements JsonAssetWithMap> { + @Nonnull public static final AssetBuilderCodec CODEC = AssetBuilderCodec.builder( BiomeRangeAsset.class, BiomeRangeAsset::new, diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/mapcontentfield/BaseHeightContentFieldAsset.java b/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/mapcontentfield/BaseHeightContentFieldAsset.java deleted file mode 100644 index 7f3dff6d..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/assets/worldstructures/mapcontentfield/BaseHeightContentFieldAsset.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.assets.worldstructures.mapcontentfield; - -import com.hypixel.hytale.assetstore.AssetExtraInfo; -import com.hypixel.hytale.codec.Codec; -import com.hypixel.hytale.codec.KeyedCodec; -import com.hypixel.hytale.codec.builder.BuilderCodec; - -public class BaseHeightContentFieldAsset extends ContentFieldAsset { - public static final BuilderCodec CODEC = BuilderCodec.builder( - BaseHeightContentFieldAsset.class, BaseHeightContentFieldAsset::new, ContentFieldAsset.ABSTRACT_CODEC - ) - .append(new KeyedCodec<>("Name", Codec.STRING, true), (t, k) -> t.name = k, t -> t.name) - .add() - .append(new KeyedCodec<>("Y", Codec.DOUBLE, false), (t, k) -> t.y = k, t -> t.y) - .add() - .build(); - private String id; - private AssetExtraInfo.Data data; - private String name = ""; - private double y = 0.0; - - private BaseHeightContentFieldAsset() { - } - - @Override - public String getId() { - return this.id; - } - - public String getName() { - return this.name; - } - - public double getY() { - return this.y; - } -} 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 92% rename from src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiomeType.java rename to src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiome.java index b31777e8..a37faaa5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiomeType.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/biome/SimpleBiome.java @@ -11,15 +11,21 @@ import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; -public class SimpleBiomeType implements BiomeType { +public class SimpleBiome implements Biome { + @Nonnull private final Density terrainDensity; + @Nonnull private final MaterialProvider materialProvider; + @Nonnull private final List propFields; + @Nonnull private final EnvironmentProvider environmentProvider; + @Nonnull private final TintProvider tintProvider; + @Nonnull private final String biomeName; - public SimpleBiomeType( + public SimpleBiome( @Nonnull String biomeName, @Nonnull Density terrainDensity, @Nonnull MaterialProvider materialProvider, @@ -38,6 +44,7 @@ public class SimpleBiomeType implements BiomeType { this.propFields.add(propField); } + @Nonnull @Override public MaterialProvider getMaterialProvider() { return this.materialProvider; @@ -49,26 +56,31 @@ public class SimpleBiomeType implements BiomeType { return this.terrainDensity; } + @Nonnull @Override public String getBiomeName() { return this.biomeName; } + @Nonnull @Override public List getPropFields() { return this.propFields; } + @Nonnull @Override public EnvironmentProvider getEnvironmentProvider() { return this.environmentProvider; } + @Nonnull @Override public TintProvider getTintProvider() { return this.tintProvider; } + @Nonnull @Override public List getAllPropDistributions() { ArrayList list = new ArrayList<>(); 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/bounds/Bounds3d.java b/src/com/hypixel/hytale/builtin/hytalegenerator/bounds/Bounds3d.java index 25592c5a..de189a44 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/bounds/Bounds3d.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/bounds/Bounds3d.java @@ -5,7 +5,9 @@ import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class Bounds3d implements MemInstrument { + @Nonnull public final Vector3d min; + @Nonnull public final Vector3d max; public Bounds3d() { @@ -49,6 +51,7 @@ public class Bounds3d implements MemInstrument { return this.min.x >= this.max.x || this.min.y >= this.max.y || this.min.z >= this.max.z; } + @Nonnull public Vector3d getSize() { return this.max.clone().subtract(this.min); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/bounds/Bounds3i.java b/src/com/hypixel/hytale/builtin/hytalegenerator/bounds/Bounds3i.java index aa5f1a11..3363836a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/bounds/Bounds3i.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/bounds/Bounds3i.java @@ -5,7 +5,9 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class Bounds3i implements MemInstrument { + @Nonnull public final Vector3i min; + @Nonnull public final Vector3i max; public Bounds3i() { @@ -49,6 +51,7 @@ public class Bounds3i implements MemInstrument { return this.min.x >= this.max.x || this.min.y >= this.max.y || this.min.z >= this.max.z; } + @Nonnull public Vector3i getSize() { return this.max.clone().subtract(this.min); } 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/ChunkGenerator.java b/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkGenerator.java index 2352ea96..e0b8c99a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkGenerator.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkGenerator.java @@ -1,8 +1,13 @@ package com.hypixel.hytale.builtin.hytalegenerator.chunkgenerator; +import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; import com.hypixel.hytale.server.core.universe.world.worldgen.GeneratedChunk; import javax.annotation.Nonnull; public interface ChunkGenerator { + @Nonnull GeneratedChunk generate(@Nonnull ChunkRequest.Arguments var1); + + @Nonnull + PositionProvider getSpawnPositions(); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkRequest.java b/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/ChunkRequest.java index 6eacfd6c..e0cb3ca4 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,25 @@ 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); } + public ChunkRequest.GeneratorProfile clone() { + return new ChunkRequest.GeneratorProfile(this.worldStructureName, this.seed, this.worldCounter); + } + + @Nonnull @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/chunkgenerator/FallbackGenerator.java b/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/FallbackGenerator.java index b57132f3..a54ecae7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/FallbackGenerator.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/chunkgenerator/FallbackGenerator.java @@ -1,14 +1,18 @@ package com.hypixel.hytale.builtin.hytalegenerator.chunkgenerator; +import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; import com.hypixel.hytale.server.core.universe.world.worldgen.GeneratedBlockChunk; import com.hypixel.hytale.server.core.universe.world.worldgen.GeneratedBlockStateChunk; import com.hypixel.hytale.server.core.universe.world.worldgen.GeneratedChunk; import com.hypixel.hytale.server.core.universe.world.worldgen.GeneratedEntityChunk; import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class FallbackGenerator implements ChunkGenerator { + @Nonnull public static final FallbackGenerator INSTANCE = new FallbackGenerator(); + @NonNullDecl @Override public GeneratedChunk generate(@Nonnull ChunkRequest.Arguments arguments) { return new GeneratedChunk( @@ -18,4 +22,10 @@ public class FallbackGenerator implements ChunkGenerator { GeneratedChunk.makeSections() ); } + + @NonNullDecl + @Override + public PositionProvider getSpawnPositions() { + return PositionProvider.noPositionProvider(); + } } 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/conveyor/stagedconveyor/ContextDependency.java b/src/com/hypixel/hytale/builtin/hytalegenerator/conveyor/stagedconveyor/ContextDependency.java index 4127ba7f..c84653ec 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/conveyor/stagedconveyor/ContextDependency.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/conveyor/stagedconveyor/ContextDependency.java @@ -12,7 +12,9 @@ import javax.annotation.Nonnull; public class ContextDependency { @Nonnull public static ContextDependency EMPTY = new ContextDependency(new Vector3i(), new Vector3i()); + @Nonnull private final Vector3i readRange; + @Nonnull private final Vector3i writeRange; private Vector3i trashRange; private Vector3i externalDependencyRange; @@ -174,6 +176,7 @@ public class ContextDependency { return new ContextDependency(rangeFromBounds(readBounds), rangeFromBounds(writeBounds)); } + @Nonnull private static Vector3i rangeFromBounds(@Nonnull Bounds3i readBounds) { Vector3i readRange = new Vector3i(); readRange.x = Math.max(Math.abs(readBounds.min.x), Math.abs(readBounds.max.x - 1)); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/datastructures/voxelspace/NullSpace.java b/src/com/hypixel/hytale/builtin/hytalegenerator/datastructures/voxelspace/NullSpace.java index fa676f31..b0b098b3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/datastructures/voxelspace/NullSpace.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/datastructures/voxelspace/NullSpace.java @@ -6,12 +6,15 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class NullSpace implements VoxelSpace { + @Nonnull private static final NullSpace INSTANCE = new NullSpace(); + @Nonnull public static NullSpace instance() { return INSTANCE; } + @Nonnull public static NullSpace instance(@Nonnull Class clazz) { return INSTANCE; } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/Density.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/Density.java index f66cab3d..fb107bd6 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; @@ -13,6 +12,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class Density { + @Nonnull private static final Bounds3i DEFAULT_READ_BOUNDS = new Bounds3i(); public static final double DEFAULT_VALUE = Double.MAX_VALUE; public static final double DEFAULT_DENSITY = 0.0; @@ -25,8 +25,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 +37,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 +47,6 @@ public abstract class Density { public Context( @Nonnull Vector3d position, - @Nonnull WorkerIndexer.Id workerId, @Nullable Vector3d densityAnchor, int switchState, double distanceFromCellWall, @@ -58,7 +54,6 @@ public abstract class Density { double distanceToBiomeEdge ) { this.position = position; - this.workerId = workerId; this.densityAnchor = densityAnchor; this.switchState = switchState; this.distanceFromCellWall = distanceFromCellWall; @@ -73,37 +68,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..be2cf3de 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,34 @@ public class AnchorDensity extends Density { @Nullable private Density input; private final boolean isReversed; + @Nonnull + private final Vector3d rChildPosition; + @Nonnull + 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..6be879e8 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,24 @@ public class AngleDensity extends Density { @Nonnull private final Vector3d vector; private final boolean toAxis; + @Nonnull + private final Vector3d rOtherVector; + @Nonnull + 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..bfc31dae 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AxisDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/AxisDensity.java @@ -8,17 +8,36 @@ import javax.annotation.Nonnull; public class AxisDensity extends Density { public static final double ZERO_DELTA = 1.0E-9; + @Nonnull private static final Vector3d ZERO_VECTOR = new Vector3d(); @Nonnull private final Double2DoubleFunction distanceCurve; @Nonnull private final Vector3d axis; private final boolean isAnchored; + @Nonnull + private final Vector3d rPosition; + @Nonnull + private final Vector3d r0; + @Nonnull + private final Vector3d r1; + @Nonnull + private final Vector3d r2; + @Nonnull + private final Vector3d r3; + @Nonnull + 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 +47,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 +60,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/BaseHeightDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/BaseHeightDensity.java index bab58a8b..36e89eb9 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/BaseHeightDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/BaseHeightDensity.java @@ -1,24 +1,21 @@ package com.hypixel.hytale.builtin.hytalegenerator.density.nodes; import com.hypixel.hytale.builtin.hytalegenerator.density.Density; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; import javax.annotation.Nonnull; public class BaseHeightDensity extends Density { @Nonnull - private final BiDouble2DoubleFunction heightFunction; + private final double baseHeight; private final boolean isDistance; - public BaseHeightDensity(@Nonnull BiDouble2DoubleFunction heightFunction, boolean isDistance) { - this.heightFunction = heightFunction; + public BaseHeightDensity(double baseHeight, boolean isDistance) { + this.baseHeight = baseHeight; this.isDistance = isDistance; } @Override public double process(@Nonnull Density.Context context) { - return this.isDistance - ? context.position.y - this.heightFunction.apply(context.position.x, context.position.z) - : this.heightFunction.apply(context.position.x, context.position.z); + return this.isDistance ? context.position.y - this.baseHeight : this.baseHeight; } public boolean skipInputs(double y) { 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..f4a8ee82 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,35 @@ 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; + @Nonnull + 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..88fe8612 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,12 @@ public class FastGradientWarpDensity extends Density { private final double warpScale; @Nonnull private final FastNoiseLite warper; + @Nonnull + private final FastNoiseLite.Vector3 rWarpedPosition; + @Nonnull + private final Density.Context rChildContext; + @Nonnull + private final Vector3d rPosition; public FastGradientWarpDensity( @Nonnull Density input, float warpLacunarity, float warpPersistence, int warpOctaves, float warpScale, float warpFactor, int seed @@ -30,6 +36,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 +47,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..033dcb58 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,12 @@ public class GradientDensity extends Density { private final double slopeRange; @Nonnull private final Vector3d axis; + @Nonnull + private final Density.Context rChildContext; + @Nonnull + private final Vector3d rSlopeDirection; + @Nonnull + private final Vector3d rPosition; public GradientDensity(@Nonnull Density input, double slopeRange, @Nonnull Vector3d axis) { if (slopeRange <= 0.0) { @@ -21,6 +27,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 +38,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..9bf4d647 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,12 @@ public class GradientWarpDensity extends Density { private Density warpInput; private final double slopeRange; private final double warpFactor; + @Nonnull + private final Density.Context rChildContext; + @Nonnull + private final Vector3d rGradient; + @Nonnull + public final Vector3d rPosition; public GradientWarpDensity(@Nonnull Density input, @Nonnull Density warpInput, double slopeRange, double warpFactor) { if (slopeRange <= 0.0) { @@ -22,6 +28,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 +45,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..6b364495 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(); } @@ -91,6 +91,7 @@ public class MultiCacheDensity extends Density { } private static class Entry { + @Nullable Vector3d position = null; double value = 0.0; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/MultiMixDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/MultiMixDensity.java index 82b9b067..42c1d744 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/MultiMixDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/MultiMixDensity.java @@ -123,6 +123,7 @@ public class MultiMixDensity extends Density { } public static class GaugeSegmentComparator implements BiFunction { + @Nonnull public static final MultiMixDensity.Segment.GaugeSegmentComparator INSTANCE = new MultiMixDensity.Segment.GaugeSegmentComparator(); @Nonnull 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..d5cc0d73 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PlaneDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/PlaneDensity.java @@ -9,6 +9,7 @@ import javax.annotation.Nullable; public class PlaneDensity extends Density { public static final double ZERO_DELTA = 1.0E-9; + @Nonnull private static final Vector3d ZERO_VECTOR = new Vector3d(); @Nonnull private final Double2DoubleFunction distanceCurve; @@ -16,12 +17,33 @@ public class PlaneDensity extends Density { private final Vector3d planeNormal; private final boolean isPlaneHorizontal; private final boolean isAnchored; + @Nonnull + private final Vector3d rNearestPoint; + @Nonnull + private final Vector3d rPosition; + @Nonnull + private final Vector3d rVectorFromPlane; + @Nonnull + private final Vector3d r0; + @Nonnull + private final Vector3d r1; + @Nonnull + private final Vector3d r2; + @Nonnull + 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 +57,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 +69,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..891876d2 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,33 @@ 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; + @Nonnull + private final Vector3d rWarpVector; + @Nonnull + private final Vector3d rSamplePoint; + @Nonnull + private final Vector3d rMin; + @Nonnull + private final Vector3d rMax; + @Nonnull + private final Vector3d rPosition; + @Nonnull + private final Vector3d rConsumerResult; + @Nonnull + private final ReusableList rWarpVectors; + @Nonnull + private final ReusableList rWarpDistances; + @Nonnull + private final ReusableList rWeights; + @Nonnull + private final PositionProvider.Context rPositionsContext; + @Nonnull + private final Density.Context rChildContext; public PositionsHorizontalPinchDensity( @Nonnull Density input, @@ -31,8 +51,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 +67,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 +89,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 +112,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..98b2d0b8 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,22 @@ public class PositionsPinchDensity extends Density { private Double2DoubleFunction pinchCurve; private double maxDistance; private boolean distanceNormalized; + @Nonnull + private final Vector3d rMin; + @Nonnull + private final Vector3d rMax; + @Nonnull + private final Vector3d rSamplePoint; + @Nonnull + private final Vector3d rWarpVector; + @Nonnull + private final ReusableList rWarpVectors; + @Nonnull + private final ReusableList rWarpDistances; + @Nonnull + private final ReusableList rWeights; + @Nonnull + private final Density.Context rChildContext; public PositionsPinchDensity( @Nullable Density input, @Nullable PositionProvider positions, @Nonnull Double2DoubleFunction pinchCurve, double maxDistance, boolean distanceNormalized @@ -29,6 +44,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 +89,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..c56870d8 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,26 @@ public class PositionsTwistDensity extends Density { private double maxDistance; private boolean distanceNormalized; private boolean zeroPositionsY; + @Nonnull + private final Vector3d rMin; + @Nonnull + private final Vector3d rMax; + @Nonnull + private final Vector3d rSamplePoint; + @Nonnull + private final Vector3d rQueryPosition; + @Nonnull + private final Vector3d rWarpVector; + @Nonnull + private final ReusableList rWarpVectors; + @Nonnull + private final ReusableList rWarpDistances; + @Nonnull + private final ReusableList rWeights; + @Nonnull + private final PositionProvider.Context rPositionsContext; + @Nonnull + private final Density.Context rChildContext; public PositionsTwistDensity( @Nullable Density input, @@ -44,6 +63,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 +115,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..a619b074 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/RotatorDensity.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/RotatorDensity.java @@ -7,6 +7,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class RotatorDensity extends Density { + @Nonnull private static final Vector3d Y_AXIS = new Vector3d(0.0, 1.0, 0.0); @Nullable private Density input; @@ -16,6 +17,10 @@ public class RotatorDensity extends Density { private final double spinAngle; @Nonnull private final RotatorDensity.SpecialCase axisSpecialCase; + @Nonnull + private final Vector3d rChildPosition; + @Nonnull + private final Density.Context rChildContext; public RotatorDensity(@Nonnull Density input, @Nonnull Vector3d newYAxis, double spinAngle) { this.input = input; @@ -41,6 +46,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 +55,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..a59e1861 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,17 @@ public class ScaleDensity extends Density { private final boolean isInvalid; @Nullable private Density input; + @Nonnull + private final Vector3d rChildPosition; + @Nonnull + 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 +31,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..7c4e47ac 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,15 @@ public class ShellDensity extends Density { @Nonnull private final Vector3d axis; private final boolean isMirrored; + @Nonnull + 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 +33,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..43805139 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,18 @@ public class SliderDensity extends Density { private final double slideZ; @Nullable private Density input; + @Nonnull + private final Vector3d rChildPosition; + @Nonnull + 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 +30,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..1b002ee3 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,13 @@ public class SwitchStateDensity extends Density { @Nullable private Density input; private final int switchState; + @Nonnull + 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 +23,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..5768e2a2 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,18 @@ public class VectorWarpDensity extends Density { private final double warpFactor; @Nonnull private final Vector3d warpVector; + @Nonnull + private final Vector3d rSamplePoint; + @Nonnull + 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 +36,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..f56b829b 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,24 @@ public class XOverrideDensity extends Density { @Nonnull private Density input; private final double value; + @Nonnull + private final Density.Context rChildContext; + @Nonnull + 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..e9ab8223 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,24 @@ public class YOverrideDensity extends Density { @Nonnull private Density input; private final double value; + @Nonnull + private final Density.Context rChildContext; + @Nonnull + 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/YSampledDensity.java b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/YSampledDensity.java new file mode 100644 index 00000000..e76befe4 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/density/nodes/YSampledDensity.java @@ -0,0 +1,96 @@ +package com.hypixel.hytale.builtin.hytalegenerator.density.nodes; + +import com.hypixel.hytale.builtin.hytalegenerator.density.Density; +import com.hypixel.hytale.builtin.hytalegenerator.framework.math.Interpolation; +import com.hypixel.hytale.math.vector.Vector3d; +import javax.annotation.Nonnull; + +public class YSampledDensity extends Density { + @Nonnull + private Density input; + private final double sampleDistance; + private final double sampleDistanceInverse; + private final double sampleOffset; + private double value0; + private double value1; + private double y0; + private double y1; + private double x; + private double z; + private boolean isEmpty; + private final Vector3d rChildPosition; + private final Density.Context rChildContext; + + public YSampledDensity(@Nonnull Density input, double sampleDistance, double sampleOffset) { + assert sampleDistance > 0.0; + + this.input = input; + this.sampleDistance = sampleDistance; + this.sampleDistanceInverse = 1.0 / sampleDistance; + this.sampleOffset = sampleOffset; + this.isEmpty = true; + this.rChildPosition = new Vector3d(); + this.rChildContext = new Density.Context(); + } + + @Override + public double process(@Nonnull Density.Context context) { + if (context.position.x != this.x || context.position.z != this.z || this.isEmpty) { + double newY0 = this.toY0(context.position.y); + double newY1 = newY0 + this.sampleDistance; + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + this.y0 = newY0; + this.y1 = newY1; + this.rChildPosition.assign(context.position.x, this.y0, context.position.z); + this.value0 = this.input.process(this.rChildContext); + this.rChildPosition.assign(context.position.x, this.y1, context.position.z); + this.value1 = this.input.process(this.rChildContext); + this.isEmpty = false; + this.x = context.position.x; + this.z = context.position.z; + } else if (context.position.y < this.y0 || context.position.y > this.y1) { + double newY0 = this.toY0(context.position.y); + double newY1 = newY0 + this.sampleDistance; + this.rChildContext.assign(context); + this.rChildContext.position = this.rChildPosition; + if (newY0 == this.y1) { + this.y0 = this.y1; + this.value0 = this.value1; + } else { + this.y0 = newY0; + this.rChildPosition.assign(context.position.x, this.y0, context.position.z); + this.value0 = this.input.process(this.rChildContext); + } + + if (newY1 == this.y0) { + this.y1 = this.y0; + this.value1 = this.value0; + } else { + this.y1 = newY1; + this.rChildPosition.assign(context.position.x, this.y1, context.position.z); + this.value1 = this.input.process(this.rChildContext); + } + } + + double ratio = (context.position.y - this.y0) * this.sampleDistanceInverse; + return Interpolation.linear(this.value0, this.value1, ratio); + } + + private double toY0(double position) { + return this.toCellGrid(position) * this.sampleDistance + this.sampleOffset; + } + + private double toCellGrid(double position) { + return Math.floor((position - this.sampleOffset) * this.sampleDistanceInverse); + } + + @Override + public void setInputs(@Nonnull Density[] inputs) { + assert inputs.length != 0; + + assert inputs[0] != null; + + this.input = inputs[0]; + } +} 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..91bf732b 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,24 @@ public class ZOverrideDensity extends Density { @Nonnull private Density input; private final double value; + @Nonnull + private final Density.Context rChildContext; + @Nonnull + 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..e83d9bbe 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,20 @@ public class PositionsDensity extends Density { private final ReturnType returnType; @Nonnull private final DistanceFunction distanceFunction; + @Nonnull + private final Vector3d rMin; + @Nonnull + private final Vector3d rMax; + @Nonnull + private final Vector3d rClosestPoint; + @Nonnull + private final Vector3d rPreviousClosestPoint; + @Nonnull + private final Vector3d rLocalPoint; + @Nonnull + private final double[] rDistance; + @Nonnull + private final boolean[] rHasClosestPoint; public PositionsDensity( @Nonnull PositionProvider positionsField, @Nonnull ReturnType returnType, @Nonnull DistanceFunction distanceFunction, double maxDistance @@ -30,6 +44,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 +61,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..900e3f52 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,13 @@ public class CellValueReturnType extends ReturnType { @Nonnull private final Density sampleField; private final double defaultValue; + @Nonnull + 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 +30,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..2f498d1c 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,13 @@ public class DensityReturnType extends ReturnType { @Nonnull private final Density[] sampleDensities; private final boolean calculateDistanceFromWall; + @Nonnull + private final Vector3d rScaledSamplePointClone; + @Nonnull + 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 +41,9 @@ public class DensityReturnType extends ReturnType { this.sampleDensities[i] = entry.getValue(); i++; } + + this.rScaledSamplePointClone = new Vector3d(); + this.rChildContext = new Density.Context(); } @Override @@ -50,19 +57,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 +78,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..18845f7b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/DensityDelimitedEnvironmentProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/DensityDelimitedEnvironmentProvider.java @@ -12,6 +12,8 @@ public class DensityDelimitedEnvironmentProvider extends EnvironmentProvider { private final List> delimiters = new ArrayList<>(); @Nonnull private final Density density; + @Nonnull + private final Density.Context rDensityContext; public DensityDelimitedEnvironmentProvider(@Nonnull List> delimiters, @Nonnull Density density) { for (DelimiterDouble delimiter : delimiters) { @@ -22,11 +24,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/environmentproviders/EnvironmentProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/EnvironmentProvider.java index f901e0e1..85c6cb6a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/EnvironmentProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/environmentproviders/EnvironmentProvider.java @@ -1,6 +1,5 @@ package com.hypixel.hytale.builtin.hytalegenerator.environmentproviders; -import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; @@ -14,16 +13,13 @@ public abstract class EnvironmentProvider { public static class Context { public Vector3i position; - public WorkerIndexer.Id workerId; - public Context(@Nonnull Vector3i position, WorkerIndexer.Id workerId) { + public Context(@Nonnull Vector3i position) { this.position = position; - this.workerId = workerId; } public Context(@Nonnull EnvironmentProvider.Context other) { this.position = other.position; - this.workerId = other.workerId; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/fields/FastNoiseLite.java b/src/com/hypixel/hytale/builtin/hytalegenerator/fields/FastNoiseLite.java index 1ab442ea..a999fd86 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/fields/FastNoiseLite.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/fields/FastNoiseLite.java @@ -28,6 +28,7 @@ public class FastNoiseLite { private FastNoiseLite.TransformType3D mWarpTransformType3D = FastNoiseLite.TransformType3D.DefaultOpenSimplex2; private float mDomainWarpAmp = 1.0F; private float mDomainWarpFreq = 1.0F; + @Nonnull private static final float[] Gradients2D = new float[]{ 0.13052619F, 0.9914449F, @@ -286,6 +287,7 @@ public class FastNoiseLite { -0.38268343F, 0.9238795F }; + @Nonnull private static final float[] RandVecs2D = new float[]{ -0.2700222F, -0.9628541F, @@ -800,6 +802,7 @@ public class FastNoiseLite { -0.774312F, -0.632804F }; + @Nonnull private static final float[] Gradients3D = new float[]{ 0.0F, 1.0F, @@ -1058,6 +1061,7 @@ public class FastNoiseLite { -1.0F, 0.0F }; + @Nonnull private static final float[] randVecs3D = new float[]{ -0.7292737F, -0.66184396F, @@ -3826,6 +3830,7 @@ public class FastNoiseLite { Distance2Mul, Distance2Div; + @Nonnull public static final Codec CODEC = new EnumCodec<>(FastNoiseLite.CellularReturnType.class); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/fields/noise/Simplex.java b/src/com/hypixel/hytale/builtin/hytalegenerator/fields/noise/Simplex.java index 31fb6afc..2cebcf84 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/fields/noise/Simplex.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/fields/noise/Simplex.java @@ -9,6 +9,7 @@ class Simplex { private static final double G3 = 0.16666666666666666; private static final double F4 = (Math.sqrt(5.0) - 1.0) / 4.0; private static final double G4 = (5.0 - Math.sqrt(5.0)) / 20.0; + @Nonnull private static final Simplex.Grad[] grad3 = new Simplex.Grad[]{ new Simplex.Grad(1.0, 1.0, 0.0), new Simplex.Grad(-1.0, 1.0, 0.0), @@ -23,6 +24,7 @@ class Simplex { new Simplex.Grad(0.0, 1.0, -1.0), new Simplex.Grad(0.0, -1.0, -1.0) }; + @Nonnull private static final Simplex.Grad[] grad4 = new Simplex.Grad[]{ new Simplex.Grad(0.0, 1.0, 1.0, 1.0), new Simplex.Grad(0.0, 1.0, 1.0, -1.0), @@ -57,6 +59,7 @@ class Simplex { new Simplex.Grad(-1.0, -1.0, 1.0, 0.0), new Simplex.Grad(-1.0, -1.0, -1.0, 0.0) }; + @Nonnull private static final short[] p = new short[]{ 151, 160, @@ -315,7 +318,9 @@ class Simplex { 156, 180 }; + @Nonnull private static final short[] perm = new short[512]; + @Nonnull private static final short[] permMod12 = new short[512]; private static int fastfloor(double x) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/framework/math/Interpolation.java b/src/com/hypixel/hytale/builtin/hytalegenerator/framework/math/Interpolation.java index 8cc1bbe5..7ba5bdfa 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/framework/math/Interpolation.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/framework/math/Interpolation.java @@ -1,11 +1,11 @@ package com.hypixel.hytale.builtin.hytalegenerator.framework.math; public class Interpolation { - public static double linear(double valueA, double valueB, double weight) { - if (!(weight < 0.0) && !(weight > 1.0)) { - return valueA * (1.0 - weight) + valueB * weight; + public static double linear(double value0, double value1, double weight) { + if (weight <= 0.0) { + return value0; } else { - throw new IllegalArgumentException("weight outside range"); + return weight >= 1.0 ? value1 : value0 * (1.0 - weight) + value1 * weight; } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/material/FluidMaterial.java b/src/com/hypixel/hytale/builtin/hytalegenerator/material/FluidMaterial.java index bf10113e..09b595e1 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/material/FluidMaterial.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/material/FluidMaterial.java @@ -4,6 +4,7 @@ import java.util.Objects; import javax.annotation.Nonnull; public class FluidMaterial { + @Nonnull private final MaterialCache materialCache; public final int fluidId; public final byte fluidLevel; @@ -14,6 +15,7 @@ public class FluidMaterial { this.fluidLevel = fluidLevel; } + @Nonnull public MaterialCache getVoxelCache() { return this.materialCache; } @@ -34,6 +36,7 @@ public class FluidMaterial { return Objects.hash(blockId, fluidLevel); } + @Nonnull @Override public String toString() { return "FluidMaterial{materialCache=" + this.materialCache + ", fluidId=" + this.fluidId + ", fluidLevel=" + this.fluidLevel + "}"; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/material/Material.java b/src/com/hypixel/hytale/builtin/hytalegenerator/material/Material.java index 7e99f13b..0611c4c8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/material/Material.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/material/Material.java @@ -53,14 +53,17 @@ public final class Material { return Objects.hash(solid.blockId, fluid.fluidId); } + @Nonnull public SolidMaterial solid() { return this.solid; } + @Nonnull public FluidMaterial fluid() { return this.fluid; } + @Nonnull @Override public String toString() { return "Material[solid=" + this.solid + ", fluid=" + this.fluid + "]"; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/material/MaterialCache.java b/src/com/hypixel/hytale/builtin/hytalegenerator/material/MaterialCache.java index 7373d9c0..d5036d2f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/material/MaterialCache.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/material/MaterialCache.java @@ -4,32 +4,50 @@ import com.hypixel.hytale.builtin.hytalegenerator.LoggerUtil; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.Rotation; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple; import com.hypixel.hytale.server.core.asset.type.fluid.Fluid; import com.hypixel.hytale.server.core.prefab.PrefabRotation; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MaterialCache { - private final Map hashToSolidMap = new HashMap<>(); - private final Map hashToFluidMap = new HashMap<>(); - private final Map hashToMaterialMap = new HashMap<>(); + @Nonnull + private final ConcurrentHashMap hashToSolidMap = new ConcurrentHashMap<>(); + @Nonnull + private final ConcurrentHashMap hashToFluidMap = new ConcurrentHashMap<>(); + @Nonnull + private final ConcurrentHashMap hashToMaterialMap = new ConcurrentHashMap<>(); + @Nullable public final SolidMaterial EMPTY_AIR = this.getSolidMaterial("Empty_Air"); + @Nullable public final SolidMaterial ROCK_STONE = this.getSolidMaterial("Rock_Stone"); + @Nullable public final SolidMaterial SOIL_GRASS = this.getSolidMaterial("Soil_Grass"); + @Nullable public final SolidMaterial SOIL_DIRT = this.getSolidMaterial("Soil_Dirt"); + @Nullable public final SolidMaterial SOIL_MUD = this.getSolidMaterial("Soil_Mud"); + @Nullable public final SolidMaterial SOIL_NEEDLES = this.getSolidMaterial("Soil_Needles"); + @Nullable public final SolidMaterial SOIL_GRAVEL = this.getSolidMaterial("Soil_Gravel"); + @Nullable public final SolidMaterial ROCK_QUARTZITE = this.getSolidMaterial("Rock_Quartzite"); + @Nullable public final SolidMaterial ROCK_MARBLE = this.getSolidMaterial("Rock_Marble"); + @Nullable public final SolidMaterial ROCK_SHALE = this.getSolidMaterial("Rock_Shale"); + @Nullable public final SolidMaterial FLUID_WATER = this.getSolidMaterial("Fluid_Water"); + @Nullable public final SolidMaterial BEDROCK = this.getSolidMaterial("Rock_Volcanic"); + @Nullable public final FluidMaterial UNKNOWN_FLUID = this.getFluidMaterial(Fluid.UNKNOWN.getId()); + @Nullable public final FluidMaterial EMPTY_FLUID = this.getFluidMaterial(Fluid.EMPTY.getId()); + @Nonnull public final Material EMPTY = this.getMaterial(this.EMPTY_AIR, this.EMPTY_FLUID); @Nonnull @@ -45,6 +63,7 @@ public class MaterialCache { } } + @Nullable public FluidMaterial getFluidMaterial(@Nonnull String fluidString) { int fluidId = 0; Fluid key = Fluid.getAssetMap().getAsset(fluidString); @@ -58,6 +77,7 @@ public class MaterialCache { } } + @Nullable public FluidMaterial getFluidMaterial(int fluidId, byte level) { Fluid key = Fluid.getAssetMap().getAsset(fluidId); if (key == null) { @@ -68,6 +88,7 @@ public class MaterialCache { } } + @Nonnull private FluidMaterial getOrRegisterFluid(int fluidId, byte level) { int hash = FluidMaterial.contentHash(fluidId, level); FluidMaterial fluidMaterial = this.hashToFluidMap.get(hash); @@ -80,7 +101,8 @@ public class MaterialCache { } } - public SolidMaterial getSolidMaterial(@Nonnull String solidString) { + @Nullable + public SolidMaterial getSolidMaterial(@Nonnull String solidString, @Nonnull RotationTuple rotation) { int blockId = 0; BlockType key = BlockType.fromString(solidString); if (key != null) { @@ -91,19 +113,25 @@ public class MaterialCache { System.out.println("Attempted to register an invalid block ID " + blockId + ": using Empty_Air instead."); return this.EMPTY_AIR; } else { - int hash = SolidMaterial.contentHash(blockId, 0, 0, 0, null); + int hash = SolidMaterial.contentHash(blockId, 0, rotation.index(), 0, null); SolidMaterial solidMaterial = this.hashToSolidMap.get(hash); if (solidMaterial != null) { return solidMaterial; } else { - solidMaterial = new SolidMaterial(this, blockId, 0, 0, 0, null); + solidMaterial = new SolidMaterial(this, blockId, 0, rotation.index(), 0, null); this.hashToSolidMap.put(blockId, solidMaterial); return solidMaterial; } } } - public SolidMaterial getSolidMaterialRotatedY(@Nonnull SolidMaterial solidMaterial, Rotation rotation) { + @Nullable + public SolidMaterial getSolidMaterial(@Nonnull String solidString) { + return this.getSolidMaterial(solidString, RotationTuple.NONE); + } + + @Nonnull + public SolidMaterial getSolidMaterialRotatedY(@Nonnull SolidMaterial solidMaterial, @Nonnull Rotation rotation) { PrefabRotation prefabRotation = PrefabRotation.fromRotation(rotation); int rotatedRotation = prefabRotation.getRotation(solidMaterial.rotation); int rotatedFiller = prefabRotation.getFiller(solidMaterial.filler); @@ -118,6 +146,7 @@ public class MaterialCache { } } + @Nullable public SolidMaterial getSolidMaterial(int blockId, int support, int rotation, int filler, @Nullable Holder holder) { if (BlockType.getAssetMap().getAsset(blockId) == null) { System.out.println("Attempted to register an invalid block ID " + blockId + ": using Empty_Air instead."); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/material/SolidMaterial.java b/src/com/hypixel/hytale/builtin/hytalegenerator/material/SolidMaterial.java index e8c15bc6..6df79e5a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/material/SolidMaterial.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/material/SolidMaterial.java @@ -7,6 +7,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SolidMaterial { + @Nonnull private final MaterialCache materialCache; public final int blockId; public final int support; @@ -45,6 +46,7 @@ public class SolidMaterial { return Objects.hash(blockId, support, rotation, filler, holder); } + @Nonnull @Override public String toString() { return "SolidMaterial{materialCache=" 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..908a2bda 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/FieldFunctionMaterialProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/FieldFunctionMaterialProvider.java @@ -10,6 +10,8 @@ public class FieldFunctionMaterialProvider extends MaterialProvider { private final Density density; @Nonnull private final FieldFunctionMaterialProvider.FieldDelimiter[] fieldDelimiters; + @Nonnull + private final Density.Context rDensityContext; public FieldFunctionMaterialProvider(@Nonnull Density density, @Nonnull List> delimiters) { this.density = density; @@ -24,13 +26,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/HorizontalMaterialProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/HorizontalMaterialProvider.java index 7f3ef813..f4ce5704 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/HorizontalMaterialProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/HorizontalMaterialProvider.java @@ -1,18 +1,15 @@ package com.hypixel.hytale.builtin.hytalegenerator.materialproviders; -import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.functions.DoubleFunctionXZ; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class HorizontalMaterialProvider extends MaterialProvider { @Nonnull private final MaterialProvider materialProvider; - @Nonnull - private final DoubleFunctionXZ topY; - @Nonnull - private final DoubleFunctionXZ bottomY; + private double topY; + private double bottomY; - public HorizontalMaterialProvider(@Nonnull MaterialProvider materialProvider, @Nonnull DoubleFunctionXZ topY, @Nonnull DoubleFunctionXZ bottomY) { + public HorizontalMaterialProvider(@Nonnull MaterialProvider materialProvider, double topY, double bottomY) { this.materialProvider = materialProvider; this.topY = topY; this.bottomY = bottomY; @@ -21,8 +18,6 @@ public class HorizontalMaterialProvider extends MaterialProvider { @Nullable @Override public V getVoxelTypeAt(@Nonnull MaterialProvider.Context context) { - double topY = this.topY.apply(context.position.x, context.position.z); - double bottomY = this.bottomY.apply(context.position.x, context.position.z); - return !(context.position.y >= topY) && !(context.position.y < bottomY) ? this.materialProvider.getVoxelTypeAt(context) : null; + return !(context.position.y >= this.topY) && !(context.position.y < this.bottomY) ? this.materialProvider.getVoxelTypeAt(context) : null; } } 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/SpaceAndDepthMaterialProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/SpaceAndDepthMaterialProvider.java index b88e2670..2cc550f7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/SpaceAndDepthMaterialProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/SpaceAndDepthMaterialProvider.java @@ -102,6 +102,7 @@ public class SpaceAndDepthMaterialProvider extends MaterialProvider { DEPTH_INTO_FLOOR, DEPTH_INTO_CEILING; + @Nonnull public static final Codec CODEC = new EnumCodec<>( SpaceAndDepthMaterialProvider.LayerContextType.class, EnumCodec.EnumStyle.LEGACY ); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/conditions/AlwaysTrueCondition.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/conditions/AlwaysTrueCondition.java index 986648de..ce9c0165 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/conditions/AlwaysTrueCondition.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/conditions/AlwaysTrueCondition.java @@ -1,8 +1,10 @@ package com.hypixel.hytale.builtin.hytalegenerator.materialproviders.spaceanddepth.conditions; import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.spaceanddepth.SpaceAndDepthMaterialProvider; +import javax.annotation.Nonnull; public class AlwaysTrueCondition implements SpaceAndDepthMaterialProvider.Condition { + @Nonnull public static final AlwaysTrueCondition INSTANCE = new AlwaysTrueCondition(); private AlwaysTrueCondition() { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/conditions/ConditionParameter.java b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/conditions/ConditionParameter.java index e9e1ab99..7946448f 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/conditions/ConditionParameter.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/materialproviders/spaceanddepth/conditions/ConditionParameter.java @@ -2,10 +2,12 @@ package com.hypixel.hytale.builtin.hytalegenerator.materialproviders.spaceanddep import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.codecs.EnumCodec; +import javax.annotation.Nonnull; public enum ConditionParameter { SPACE_ABOVE_FLOOR, SPACE_BELOW_CEILING; + @Nonnull public static final Codec CODEC = new EnumCodec<>(ConditionParameter.class, EnumCodec.EnumStyle.LEGACY); } 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..dd806b37 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,22 @@ public class NoiseThickness extends SpaceAndDepthMaterialProvider.Layer { private final Density density; @Nullable private final MaterialProvider materialProvider; + @Nonnull + 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..950d898d 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/NStagedChunkGenerator.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/NStagedChunkGenerator.java @@ -21,6 +21,7 @@ import com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages.NStage; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NEntityBufferView; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NPixelBufferView; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.views.NVoxelBufferView; +import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.math.util.ChunkUtil; @@ -28,6 +29,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,18 +42,20 @@ 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; import java.util.concurrent.ExecutorService; import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class NStagedChunkGenerator implements ChunkGenerator { public static final int WORLD_MIN_Y_BUFFER_GRID = 0; public static final int WORLD_MAX_Y_BUFFER_GRID = 40; public static final int WORLD_HEIGHT_BUFFER_GRID = 40; + @Nonnull public static final Bounds3i CHUNK_BOUNDS_BUFFER_GRID = new Bounds3i(Vector3i.ZERO, new Vector3i(4, 40, 4)); + @Nonnull public static final Bounds3i SINGLE_BUFFER_TILE_BOUNDS_BUFFER_GRID = new Bounds3i( new Vector3i(0, 0, 0), new Vector3i(NVoxelBuffer.SIZE.x, 320, NVoxelBuffer.SIZE.x) ); @@ -65,6 +69,7 @@ public class NStagedChunkGenerator implements ChunkGenerator { private ExecutorService concurrentExecutor; private MaterialCache materialCache; private WorkerIndexer workerIndexer; + private PositionProvider spawnPositions; private TimeInstrument timeInstrument; private Set statsCheckpoints; private int generatedChunkCount; @@ -74,6 +79,7 @@ public class NStagedChunkGenerator implements ChunkGenerator { private NStagedChunkGenerator() { } + @NonNullDecl @Override public GeneratedChunk generate(@Nonnull ChunkRequest.Arguments arguments) { if (arguments.stillNeeded() != null && !arguments.stillNeeded().test(arguments.index())) { @@ -212,6 +218,12 @@ public class NStagedChunkGenerator implements ChunkGenerator { } } + @NonNullDecl + @Override + public PositionProvider getSpawnPositions() { + return this.spawnPositions; + } + @Nonnull private Map createAccesses(@Nonnull Bounds3i localChunkBounds_bufferGrid) { Map accessMap = new HashMap<>(); @@ -330,6 +342,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,16 +351,11 @@ 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); - if (material == null) { - blockChunk.setBlock(x_voxelGrid, y_voxelGrid, z_voxelGrid, 0, 0, 0); - fluidSection.setFluid( - x_voxelGrid, sectionY, z_voxelGrid, this.materialCache.EMPTY_FLUID.fluidId, this.materialCache.EMPTY_FLUID.fluidLevel - ); - } else { + 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 && !material.equals(this.materialCache.EMPTY)) { blockChunk.setBlock( x_voxelGrid, y_voxelGrid, z_voxelGrid, material.solid().blockId, material.solid().rotation, material.solid().filler ); @@ -385,16 +393,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 +431,54 @@ 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; + world_voxelGrid.dropHash(); + 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); + } + } + + TimeInstrument.Probe timeProbe = transfer_timeProbe.createProbe("Environment Write"); + return FutureUtils.allOf(futures).thenRun(() -> { + timeProbe.start(); + bulkWriter.write(generatedChunk.getBlockChunk().getEnvironmentChunk()); + timeProbe.start(); + }).handle((r, e) -> { if (e == null) { return (Void)r; } else { @@ -551,15 +586,19 @@ public class NStagedChunkGenerator implements ChunkGenerator { } public static class Builder { + @Nonnull public final NParametrizedBufferType MATERIAL_OUTPUT_BUFFER_TYPE = new NParametrizedBufferType( "MaterialResult", -1, NVoxelBuffer.class, Material.class, () -> new NVoxelBuffer<>(Material.class) ); + @Nonnull public final NParametrizedBufferType TINT_OUTPUT_BUFFER_TYPE = new NParametrizedBufferType( "TintResult", -3, NSimplePixelBuffer.class, Integer.class, () -> new NSimplePixelBuffer<>(Integer.class) ); + @Nonnull public final NParametrizedBufferType ENVIRONMENT_OUTPUT_BUFFER_TYPE = new NParametrizedBufferType( "EnvironmentResult", -4, NVoxelBuffer.class, Integer.class, () -> new NVoxelBuffer<>(Integer.class) ); + @Nonnull public final NBufferType ENTITY_OUTPUT_BUFFER_TYPE = new NBufferType("EntityResult", -5, NEntityBuffer.class, NEntityBuffer::new); private List stages = new ArrayList<>(); private ExecutorService concurrentExecutor; @@ -567,6 +606,7 @@ public class NStagedChunkGenerator implements ChunkGenerator { private WorkerIndexer workerIndexer; private String statsHeader; private Set statsCheckpoints; + private PositionProvider spawnPositions; private double bufferCapacityFactor; private double targetViewDistance; private double targetPlayerCount; @@ -583,6 +623,8 @@ public class NStagedChunkGenerator implements ChunkGenerator { assert this.statsCheckpoints != null; + assert this.spawnPositions != null; + NStagedChunkGenerator instance = new NStagedChunkGenerator(); instance.materialOutput_bufferType = this.MATERIAL_OUTPUT_BUFFER_TYPE; instance.tintOutput_bufferType = this.TINT_OUTPUT_BUFFER_TYPE; @@ -617,6 +659,7 @@ public class NStagedChunkGenerator implements ChunkGenerator { instance.timeInstrument = new TimeInstrument(this.statsHeader); instance.statsCheckpoints = new HashSet<>(this.statsCheckpoints); instance.generatedChunkCount = 0; + instance.spawnPositions = this.spawnPositions; return instance; } @@ -627,6 +670,12 @@ public class NStagedChunkGenerator implements ChunkGenerator { return this; } + @Nonnull + public NStagedChunkGenerator.Builder withSpawnPositions(@Nonnull PositionProvider spawnPositions) { + this.spawnPositions = spawnPositions; + return this; + } + @Nonnull public NStagedChunkGenerator.Builder withConcurrentExecutor(@Nonnull ExecutorService executor, @Nonnull WorkerIndexer workerIndexer) { this.concurrentExecutor = executor; @@ -807,6 +856,7 @@ public class NStagedChunkGenerator implements ChunkGenerator { return allBufferTypes; } + @Nonnull private static Bounds3i getEncompassingBounds(@Nonnull Collection set) { Bounds3i out = new Bounds3i(); 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/bufferbundle/NBufferBundle.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/NBufferBundle.java index 57282add..26e8a53b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/NBufferBundle.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/NBufferBundle.java @@ -17,6 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; public class NBufferBundle implements MemInstrument { + @Nonnull private final Map grids = new HashMap<>(); @Nonnull @@ -90,8 +91,11 @@ public class NBufferBundle implements MemInstrument { } public static class Access implements MemInstrument { + @Nonnull private final NBufferBundle.Grid grid; + @Nonnull private final Bounds3i bounds_bufferGrid; + @Nonnull private final NBufferBundle.Grid.TrackedBuffer[] buffers; private boolean isClosed; @@ -174,7 +178,9 @@ public class NBufferBundle implements MemInstrument { } public static class View { + @Nonnull private final NBufferBundle.Access access; + @Nonnull private final Bounds3i bounds_bufferGrid; private View(@Nonnull NBufferBundle.Access access, @Nonnull Bounds3i bounds_bufferGrid) { @@ -201,10 +207,14 @@ public class NBufferBundle implements MemInstrument { } public static class Grid implements MemInstrument { + @Nonnull private final NBufferType bufferType; + @Nonnull private final Map buffers; + @Nonnull private final Deque oldestColumnEntryDeque_bufferGrid; private final int capacity; + @Nonnull private final List accessors; private Grid(@Nonnull NBufferType bufferType, int capacity) { @@ -361,6 +371,7 @@ public class NBufferBundle implements MemInstrument { } public static class MemoryReport { + @Nonnull public final List gridEntries = new ArrayList<>(); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NCountedPixelBuffer.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NCountedPixelBuffer.java index d383caf8..25eeafd0 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NCountedPixelBuffer.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NCountedPixelBuffer.java @@ -12,7 +12,9 @@ import javax.annotation.Nullable; public class NCountedPixelBuffer extends NPixelBuffer { public static final int BUFFER_SIZE_BITS = 3; + @Nonnull public static final Vector3i SIZE_VOXEL_GRID = new Vector3i(8, 1, 8); + @Nonnull public static final Bounds3i BOUNDS_VOXEL_GRID = new Bounds3i(Vector3i.ZERO, SIZE_VOXEL_GRID); @Nonnull private final Class pixelType; @@ -128,9 +130,11 @@ public class NCountedPixelBuffer extends NPixelBuffer { } public static class CountedArrayContents implements MemInstrument { + @Nonnull private final T[] array = (T[])(new Object[NCountedPixelBuffer.SIZE_VOXEL_GRID.x * NCountedPixelBuffer.SIZE_VOXEL_GRID.y * NCountedPixelBuffer.SIZE_VOXEL_GRID.z]); + @Nonnull private final List allBiomes = new ArrayList<>(1); public void copyFrom(@Nonnull NCountedPixelBuffer.CountedArrayContents countedArrayContents) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NEntityBuffer.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NEntityBuffer.java index e682dc18..ac600406 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NEntityBuffer.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NEntityBuffer.java @@ -6,8 +6,10 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class NEntityBuffer extends NBuffer { + @Nullable private List entities = null; private boolean isReference = false; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NPixelBuffer.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NPixelBuffer.java index fe3b4fe0..c1c4338a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NPixelBuffer.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NPixelBuffer.java @@ -6,6 +6,7 @@ import javax.annotation.Nullable; public abstract class NPixelBuffer extends NBuffer { public static final int BUFFER_SIZE_BITS = 3; + @Nonnull public static final Vector3i SIZE = new Vector3i(8, 1, 8); @Nullable diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NSimplePixelBuffer.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NSimplePixelBuffer.java index 320ef12d..c3f59839 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NSimplePixelBuffer.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NSimplePixelBuffer.java @@ -9,6 +9,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class NSimplePixelBuffer extends NPixelBuffer { + @Nonnull private static final Bounds3i bounds = new Bounds3i(Vector3i.ZERO, SIZE); @Nonnull private final Class pixelType; @@ -112,6 +113,7 @@ public class NSimplePixelBuffer extends NPixelBuffer { } public static class ArrayContents implements MemInstrument { + @Nonnull private final T[] array = (T[])(new Object[NPixelBuffer.SIZE.x * NPixelBuffer.SIZE.y * NPixelBuffer.SIZE.z]); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NVoxelBuffer.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NVoxelBuffer.java index 52333d3c..ec8e3461 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NVoxelBuffer.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/NVoxelBuffer.java @@ -10,7 +10,9 @@ import javax.annotation.Nullable; public class NVoxelBuffer extends NBuffer { public static final int BUFFER_SIZE_BITS = 3; + @Nonnull public static final Vector3i SIZE = new Vector3i(8, 8, 8); + @Nonnull private static final Bounds3i bounds = new Bounds3i(Vector3i.ZERO, SIZE); @Nonnull private final Class voxelType; @@ -135,6 +137,7 @@ public class NVoxelBuffer extends NBuffer { } public static class ArrayContents implements MemInstrument { + @Nonnull private final T[] array = (T[])(new Object[NVoxelBuffer.SIZE.x * NVoxelBuffer.SIZE.y * NVoxelBuffer.SIZE.z]); @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/type/NBufferType.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/type/NBufferType.java index 23946ac2..89a71566 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/type/NBufferType.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/bufferbundle/buffers/type/NBufferType.java @@ -5,9 +5,12 @@ import java.util.function.Supplier; import javax.annotation.Nonnull; public class NBufferType { + @Nonnull public final Class bufferClass; public final int index; + @Nonnull public final Supplier bufferSupplier; + @Nonnull public final String name; public NBufferType(@Nonnull String name, int index, @Nonnull Class bufferClass, @Nonnull Supplier bufferSupplier) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/containers/FloatContainer3d.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/containers/FloatContainer3d.java index bdfff465..2a616e06 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/containers/FloatContainer3d.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/containers/FloatContainer3d.java @@ -6,8 +6,11 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class FloatContainer3d { + @Nonnull private final Bounds3i bounds_voxelGrid; + @Nonnull private final Vector3i size_voxelGrid; + @Nonnull private final float[] data; private final float outOfBoundsValue; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/performanceinstruments/TimeInstrument.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/performanceinstruments/TimeInstrument.java index d41eaaae..81033daf 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/performanceinstruments/TimeInstrument.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/performanceinstruments/TimeInstrument.java @@ -44,12 +44,11 @@ public class TimeInstrument { @Nonnull private String toString(int indentation, @Nonnull TimeInstrument.Probe probe) { - long ms = probe.getTotalTime() / this.sampleCount; - ms /= 1000000L; + long ns = probe.getTotalTime() / this.sampleCount; StringBuilder s = new StringBuilder(); s.append("\t".repeat(indentation)); s.append(probe.getName()).append(": "); - s.append(Long.toString(ms)).append(" ms"); + s.append(LoggerUtil.nsToMsDecimal(ns)).append(" ms"); s.append("\n"); List childProbes = probe.getProbes(); @@ -61,6 +60,7 @@ public class TimeInstrument { } public static class Probe { + @Nonnull private final String name; private long startTime; private long totalTime; 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..149dfe0b 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; @@ -22,15 +21,23 @@ public class NBiomeDistanceStage implements NStage { private static final double ORIGIN_REACH = 1.0; 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; + @Nonnull public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + @Nonnull + public static final Class biomeClass = Integer.class; + @Nonnull public static final Class biomeDistanceBufferClass = NSimplePixelBuffer.class; + @Nonnull public static final Class biomeDistanceClass = NBiomeDistanceStage.BiomeDistanceEntries.class; + @Nonnull private final NParametrizedBufferType biomeInputBufferType; + @Nonnull private final NParametrizedBufferType biomeDistanceOutputBufferType; + @Nonnull private final String stageName; private final double maxDistance_voxelGrid; private final int maxDistance_bufferGrid; + @Nonnull private final Bounds3i inputBounds_bufferGrid; public NBiomeDistanceStage( @@ -56,7 +63,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 +78,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 +91,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 +118,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 +190,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 +210,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 +220,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 +239,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; @@ -241,17 +248,18 @@ public class NBiomeDistanceStage implements NStage { } public static class BiomeDistanceEntries { + @Nonnull public final List entries; public BiomeDistanceEntries(@Nonnull List entries) { 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 +269,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..26959713 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,42 @@ 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 { + @Nonnull public static final Class bufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + @Nonnull + public static final Class biomeClass = Integer.class; + @Nonnull private final NParametrizedBufferType biomeOutputBufferType; + @Nonnull private final String stageName; - private BiCarta biomeCarta; + @Nonnull + 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, context.workerId); + 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..281abb1d 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,23 +12,38 @@ 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; import javax.annotation.Nonnull; public class NEnvironmentStage implements NStage { + @Nonnull public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + @Nonnull + public static final Class biomeTypeClass = Integer.class; + @Nonnull public static final Class environmentBufferClass = NVoxelBuffer.class; + @Nonnull public static final Class environmentClass = Integer.class; + @Nonnull private final NParametrizedBufferType biomeInputBufferType; + @Nonnull private final NParametrizedBufferType environmentOutputBufferType; + @Nonnull private final Bounds3i inputBounds_bufferGrid; + @Nonnull private final String stageName; + @Nonnull + 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,29 +52,36 @@ 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 environmentContext = new EnvironmentProvider.Context(position_voxelGrid); + 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; EnvironmentProvider environmentProvider = biome.getEnvironmentProvider(); for (position_voxelGrid.y = outputBounds_voxelGrid.min.y; position_voxelGrid.y < outputBounds_voxelGrid.max.y; position_voxelGrid.y++) { - int environment = environmentProvider.getValue(tintContext); + position_voxelGrid.dropHash(); + int environment = environmentProvider.getValue(environmentContext); environmentSpace.set(environment, position_voxelGrid); } } 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..bfb28f23 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; @@ -33,23 +37,42 @@ import javax.annotation.Nullable; public class NPropStage implements NStage { public static final double DEFAULT_BACKGROUND_DENSITY = 0.0; + @Nonnull public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + @Nonnull + public static final Class biomeClass = Integer.class; + @Nonnull public static final Class biomeDistanceBufferClass = NSimplePixelBuffer.class; + @Nonnull public static final Class biomeDistanceClass = NBiomeDistanceStage.BiomeDistanceEntries.class; + @Nonnull public static final Class materialBufferClass = NVoxelBuffer.class; + @Nonnull public static final Class materialClass = Material.class; + @Nonnull public static final Class entityBufferClass = NEntityBuffer.class; + @Nonnull private final NParametrizedBufferType biomeInputBufferType; + @Nonnull private final NParametrizedBufferType biomeDistanceInputBufferType; + @Nonnull private final NParametrizedBufferType materialInputBufferType; + @Nullable private final NBufferType entityInputBufferType; + @Nonnull private final NParametrizedBufferType materialOutputBufferType; + @Nonnull private final NBufferType entityOutputBufferType; + @Nonnull private final Bounds3i inputBounds_bufferGrid; + @Nonnull private final Bounds3i inputBounds_voxelGrid; + @Nonnull private final String stageName; + @Nonnull private final MaterialCache materialCache; + @Nonnull + private final WorkerIndexer.Data worldStructure_workerData; private final int runtimeIndex; public NPropStage( @@ -61,10 +84,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 +105,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 +141,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 +166,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,18 +187,19 @@ 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); + double distanceToBiomeEdge = biomeDistanceSpace.getContent(position2d_voxelGrid).distanceToClosestOtherBiome(biomeIdAtPosition); Prop prop = propField.getPropDistribution().propAt(position, context.workerId, distanceToBiomeEdge); Bounds3i propWriteBounds = prop.getWriteBounds_voxelGrid().clone(); propWriteBounds.offset(positionInt_voxelGrid); @@ -181,7 +212,7 @@ public class NPropStage implements NStage { } }; 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..bb1921ed 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; @@ -30,20 +32,35 @@ public class NTerrainStage implements NStage { public static final double ORIGIN_REACH = 1.0; public static final double ORIGIN_REACH_HALF = 0.5; public static final double QUARTER_PI = Math.PI / 4; + @Nonnull public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeClass = BiomeType.class; + @Nonnull + public static final Class biomeClass = Integer.class; + @Nonnull public static final Class biomeDistanceBufferClass = NSimplePixelBuffer.class; + @Nonnull public static final Class biomeDistanceClass = NBiomeDistanceStage.BiomeDistanceEntries.class; + @Nonnull public static final Class materialBufferClass = NVoxelBuffer.class; + @Nonnull public static final Class materialClass = Material.class; + @Nonnull private final NParametrizedBufferType biomeInputBufferType; + @Nonnull private final NParametrizedBufferType biomeDistanceInputBufferType; + @Nonnull private final NParametrizedBufferType materialOutputBufferType; + @Nonnull private final Bounds3i inputBounds_bufferGrid; + @Nonnull private final String stageName; private final int maxInterpolationRadius_voxelGrid; + @Nonnull private final MaterialCache materialCache; + @Nonnull private final WorkerIndexer.Data densityContainers; + @Nonnull + private final WorkerIndexer.Data worldStructure_workerdata; public NTerrainStage( @Nonnull String stageName, @@ -52,7 +69,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 +80,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 +99,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 +107,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 +135,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 +151,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 +197,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 +238,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 +282,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 +294,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 +347,7 @@ public class NTerrainStage implements NStage { } static class Entry { - BiomeType biomeType; + int biomeId; float weight; } } @@ -337,31 +366,31 @@ 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 +405,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 +413,13 @@ 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++) { + position.y = yx; + positionBelow.y = yx - 1; + 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 +432,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/NTestPropStage.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTestPropStage.java index 9d99d43b..fa6e87c3 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTestPropStage.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTestPropStage.java @@ -15,14 +15,22 @@ import java.util.Random; import javax.annotation.Nonnull; public class NTestPropStage implements NStage { + @Nonnull private static final Class bufferClass = NVoxelBuffer.class; + @Nonnull private static final Class solidMaterialClass = SolidMaterial.class; private final int CONTEXT_DEPENDENCY_RANGE_BUFFER_GRID = 0; + @Nonnull private final Bounds3i inputBounds_bufferGrid = new Bounds3i(new Vector3i(0, 0, 0), new Vector3i(1, 40, 1)); + @Nonnull private final NParametrizedBufferType inputBufferType; + @Nonnull private final NParametrizedBufferType outputBufferType; + @Nonnull private final SolidMaterial floorMaterial; + @Nonnull private final SolidMaterial anchorMaterial; + @Nonnull private final SolidMaterial propMaterial; public NTestPropStage( diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTestTerrainStage.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTestTerrainStage.java index c641592f..02523cc2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTestTerrainStage.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/stages/NTestTerrainStage.java @@ -15,10 +15,15 @@ import java.util.Map; import javax.annotation.Nonnull; public class NTestTerrainStage implements NStage { + @Nonnull private static final Class bufferClass = NVoxelBuffer.class; + @Nonnull private static final Class solidMaterialClass = SolidMaterial.class; + @Nonnull private final NParametrizedBufferType outputBufferType; + @Nonnull private final SolidMaterial ground; + @Nonnull private final SolidMaterial empty; public NTestTerrainStage(@Nonnull NBufferType outputBufferType, @Nonnull SolidMaterial groundMaterial, @Nonnull SolidMaterial emptyMaterial) { 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..138a8ffe 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,47 +10,70 @@ 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; import javax.annotation.Nonnull; public class NTintStage implements NStage { + @Nonnull public static final Class biomeBufferClass = NCountedPixelBuffer.class; - public static final Class biomeTypeClass = BiomeType.class; + @Nonnull + public static final Class biomeClass = Integer.class; + @Nonnull public static final Class tintBufferClass = NSimplePixelBuffer.class; + @Nonnull public static final Class tintClass = Integer.class; + @Nonnull private final NParametrizedBufferType biomeInputBufferType; + @Nonnull private final NParametrizedBufferType tintOutputBufferType; + @Nonnull private final Bounds3i inputBounds_bufferGrid; + @Nonnull private final String stageName; + @Nonnull + 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); 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/NEntityBufferView.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NEntityBufferView.java index e64a2bbe..dc55636c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NEntityBufferView.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NEntityBufferView.java @@ -12,8 +12,11 @@ import java.util.function.Consumer; import javax.annotation.Nonnull; public class NEntityBufferView implements EntityContainer { + @Nonnull private final NBufferBundle.Access.View access; + @Nonnull private final Bounds3i bounds_voxelGrid; + @Nonnull private final Bounds3i bounds_bufferGrid; public NEntityBufferView(@Nonnull NBufferBundle.Access.View bufferAccess) { @@ -46,6 +49,7 @@ public class NEntityBufferView implements EntityContainer { } } + @Nonnull private NEntityBuffer getBuffer_fromBufferGrid(@Nonnull Vector3i position_bufferGrid) { return (NEntityBuffer)this.access.getBuffer(position_bufferGrid).buffer(); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NPixelBufferView.java b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NPixelBufferView.java index 11d3c688..fb93425e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NPixelBufferView.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NPixelBufferView.java @@ -14,9 +14,13 @@ import javax.annotation.Nullable; public class NPixelBufferView implements VoxelSpace { public static final int Y_LEVEL_BUFFER_GRID = 0; public static final int Y_LEVEL_VOXEL_GRID = 0; + @Nonnull private final Class voxelType; + @Nonnull private final NBufferBundle.Access.View bufferAccess; + @Nonnull private final Bounds3i bounds_voxelGrid; + @Nonnull private final Vector3i size_voxelGrid; public NPixelBufferView(@Nonnull NBufferBundle.Access.View bufferAccess, @Nonnull Class pixelType) { @@ -74,6 +78,7 @@ public class NPixelBufferView implements VoxelSpace { return buffer.getPixelContent(positionInBuffer_voxelGrid); } + @Nonnull private NPixelBuffer getBuffer(@Nonnull Vector3i position_voxelGrid) { assert this.bounds_voxelGrid.contains(position_voxelGrid); 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..e65ead86 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NVoxelBufferView.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/newsystem/views/NVoxelBufferView.java @@ -12,9 +12,13 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class NVoxelBufferView implements VoxelSpace { + @Nonnull private final Class voxelType; + @Nonnull private final NBufferBundle.Access.View bufferAccess; + @Nonnull private final Bounds3i bounds_voxelGrid; + @Nonnull private final Vector3i size_voxelGrid; public NVoxelBufferView(@Nonnull NBufferBundle.Access.View bufferAccess, @Nonnull Class voxelType) { @@ -61,10 +65,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 +96,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 deleted file mode 100644 index 7d36b581..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CeilingPattern.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.patterns; - -import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize; -import com.hypixel.hytale.math.vector.Vector3i; -import javax.annotation.Nonnull; - -public class CeilingPattern extends Pattern { - @Nonnull - private final Pattern ceilingPattern; - @Nonnull - private final Pattern airPattern; - @Nonnull - private final SpaceSize readSpaceSize; - - public CeilingPattern(@Nonnull Pattern ceilingPattern, @Nonnull Pattern airPattern) { - this.ceilingPattern = ceilingPattern; - this.airPattern = airPattern; - SpaceSize ceilingSpace = ceilingPattern.readSpace(); - ceilingSpace.moveBy(new Vector3i(0, 1, 0)); - this.readSpaceSize = SpaceSize.merge(ceilingSpace, airPattern.readSpace()); - } - - @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); - } else { - return false; - } - } - - @Nonnull - @Override - public SpaceSize readSpace() { - return this.readSpaceSize.clone(); - } -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CuboidPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CuboidPattern.java index f6cc81ff..70ba36b7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CuboidPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/CuboidPattern.java @@ -13,30 +13,42 @@ public class CuboidPattern extends Pattern { private final Vector3i max; @Nonnull private final SpaceSize readSpaceSize; + @Nonnull + private final Vector3i rScanMin; + @Nonnull + private final Vector3i rScanMax; + @Nonnull + private final Vector3i rChildPosition; + @Nonnull + 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..316f5d7c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/FieldFunctionPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/FieldFunctionPattern.java @@ -13,17 +13,20 @@ public class FieldFunctionPattern extends Pattern { private final SpaceSize readSpaceSize; @Nonnull private final List delimiters; + @Nonnull + 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..496228e0 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/GapPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/GapPattern.java @@ -19,6 +19,10 @@ public class GapPattern extends Pattern { private Pattern gapPattern; private Pattern anchorPattern; private SpaceSize readSpaceSize; + @Nonnull + private final Vector3i rChildPosition; + @Nonnull + private final Pattern.Context rChildContext; public GapPattern( @Nonnull List angles, @@ -38,6 +42,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 +78,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 +205,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/MaterialPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/MaterialPattern.java index f11956b6..05fe09ff 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/MaterialPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/MaterialPattern.java @@ -6,7 +6,9 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class MaterialPattern extends Pattern { + @Nonnull private static final SpaceSize READ_SPACE_SIZE = new SpaceSize(new Vector3i(0, 0, 0), new Vector3i(1, 0, 1)); + @Nonnull private final Material material; public MaterialPattern(@Nonnull Material material) { @@ -23,6 +25,7 @@ public class MaterialPattern extends Pattern { } } + @Nonnull @Override public SpaceSize readSpace() { return READ_SPACE_SIZE.clone(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/MaterialSetPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/MaterialSetPattern.java index 7692c2fe..87f90b9a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/MaterialSetPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/MaterialSetPattern.java @@ -7,7 +7,9 @@ import com.hypixel.hytale.math.vector.Vector3i; import javax.annotation.Nonnull; public class MaterialSetPattern extends Pattern { + @Nonnull private static final SpaceSize READ_SPACE_SIZE = new SpaceSize(new Vector3i(0, 0, 0), new Vector3i(1, 0, 1)); + @Nonnull private final MaterialSet materialSet; public MaterialSetPattern(@Nonnull MaterialSet materialSet) { @@ -25,6 +27,7 @@ public class MaterialSetPattern extends Pattern { } } + @Nonnull @Override public SpaceSize readSpace() { return READ_SPACE_SIZE.clone(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/OffsetPattern.java b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/OffsetPattern.java index 752edae5..352bde64 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/OffsetPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/OffsetPattern.java @@ -11,18 +11,25 @@ public class OffsetPattern extends Pattern { private final Vector3i offset; @Nonnull private final SpaceSize readSpaceSize; + @Nonnull + private final Vector3i rChildPosition; + @Nonnull + 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..a034cb15 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/Pattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/Pattern.java @@ -1,11 +1,12 @@ package com.hypixel.hytale.builtin.hytalegenerator.patterns; import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize; +import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.NullSpace; 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 +48,29 @@ public abstract class Pattern { } public static class Context { + @Nonnull public Vector3i position; + @Nonnull 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 = NullSpace.instance(); + } + + 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..f6f38c7e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/SurfacePattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/SurfacePattern.java @@ -20,6 +20,10 @@ public class SurfacePattern extends Pattern { private final List surfacePositions; @Nonnull private final List originPositions; + @Nonnull + private final Vector3i rChildPosition; + @Nonnull + private final Pattern.Context rChildContext; public SurfacePattern( @Nonnull Pattern surfacePattern, @@ -32,6 +36,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 +87,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 +155,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..d50f54e2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/WallPattern.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/patterns/WallPattern.java @@ -17,12 +17,18 @@ public class WallPattern extends Pattern { private final List directions; private final boolean matchAll; private final SpaceSize readSpaceSize; + @Nonnull + private final Vector3i rWallPosition; + @Nonnull + 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 +63,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 @@ -89,6 +95,7 @@ public class WallPattern extends Pattern { E, W; + @Nonnull public static final Codec CODEC = new EnumCodec<>(WallPattern.WallDirection.class, EnumCodec.EnumStyle.LEGACY); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/Handle.java b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/Handle.java index ef7ea733..e4a0d058 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/Handle.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/Handle.java @@ -2,10 +2,13 @@ package com.hypixel.hytale.builtin.hytalegenerator.plugin; import com.hypixel.hytale.builtin.hytalegenerator.chunkgenerator.ChunkRequest; import com.hypixel.hytale.math.vector.Transform; +import com.hypixel.hytale.math.vector.Vector3d; 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.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.LongPredicate; import javax.annotation.Nonnull; @@ -16,15 +19,23 @@ 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; } + @Nonnull @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); @@ -35,9 +46,20 @@ public class Handle implements IWorldGen { return this.profile; } + @Nonnull @Override public Transform[] getSpawnPoints(int seed) { - return new Transform[]{new Transform(0.0, 140.0, 0.0)}; + ChunkRequest.GeneratorProfile seededProfile = this.profile.clone(); + seededProfile.setSeed(seed); + int MAX_SPAWN_POINTS = 1000000; + List positions = this.plugin.getSpawnPositions(seededProfile, 1000000); + Transform[] positionsArray = new Transform[positions.size()]; + + for (int i = 0; i < positions.size(); i++) { + positionsArray[i] = new Transform(positions.get(i)); + } + + return positions.isEmpty() ? new Transform[]{new Transform(0.0, 140.0, 0.0)} : positionsArray; } @Nonnull diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HandleProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HandleProvider.java index 9983db0a..0656623c 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HandleProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HandleProvider.java @@ -8,28 +8,44 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class HandleProvider implements IWorldGenProvider { + @Nonnull public static final String ID = "HytaleGenerator"; + @Nonnull public static final String DEFAULT_WORLD_STRUCTURE_NAME = "Default"; @Nonnull 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; + } + + @Nonnull @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..ef14bc91 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HytaleGenerator.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/plugin/HytaleGenerator.java @@ -1,18 +1,18 @@ 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.positionproviders.PositionProviderAsset; 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; @@ -27,11 +27,15 @@ import com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages.NPropStage; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages.NStage; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages.NTerrainStage; import com.hypixel.hytale.builtin.hytalegenerator.newsystem.stages.NTintStage; +import com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; +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.worldstructure.WorldStructure; 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.Vector3d; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; import com.hypixel.hytale.server.core.universe.world.events.RemoveWorldEvent; @@ -56,11 +60,16 @@ import javax.annotation.Nonnull; public class HytaleGenerator extends JavaPlugin { private AssetManager assetManager; private Runnable assetReloadListener; + @Nonnull private final Map generators = new HashMap<>(); + @Nonnull private final Semaphore chunkGenerationSemaphore = new Semaphore(1); private int concurrency; private ExecutorService mainExecutor; private ThreadPoolExecutor concurrentExecutor; + private int worldCounter; + @Nonnull + public static Vector3d DEFAULT_SPAWN_POSITION = new Vector3d(0.0, 140.0, 0.0); @Override protected void start() { @@ -75,6 +84,39 @@ public class HytaleGenerator extends JavaPlugin { } } + @Nonnull + public List getSpawnPositions(@Nonnull ChunkRequest.GeneratorProfile profile, int maxPositionsCount) { + assert maxPositionsCount >= 0; + + if (profile.worldStructureName() == null) { + LoggerUtil.getLogger().warning("World Structure asset not loaded."); + return List.of(DEFAULT_SPAWN_POSITION); + } else { + WorldStructureAsset worldStructureAsset = this.assetManager.getWorldStructureAsset(profile.worldStructureName()); + if (worldStructureAsset == null) { + LoggerUtil.getLogger().warning("World Structure asset not found: " + profile.worldStructureName()); + return List.of(DEFAULT_SPAWN_POSITION); + } else { + SeedBox seed = new SeedBox(profile.seed()); + PositionProvider spawnPositionProvider = worldStructureAsset.getSpawnPositionsAsset() + .build(new PositionProviderAsset.Argument(seed, new ReferenceBundle(), WorkerIndexer.Id.MAIN)); + List positions = new ArrayList<>(maxPositionsCount); + PositionProvider.Context context = new PositionProvider.Context( + new Vector3d(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY), + new Vector3d(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY), + position -> { + if (positions.size() < maxPositionsCount) { + positions.add(position); + } + }, + null + ); + spawnPositionProvider.positionsIn(context); + return positions; + } + } + } + @Nonnull public CompletableFuture submitChunkRequest(@Nonnull ChunkRequest request) { return CompletableFuture.supplyAsync(() -> { @@ -101,11 +143,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 +168,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, workerId)); + 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 +209,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 +228,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 +263,7 @@ public class HytaleGenerator extends JavaPlugin { materialOutput_bufferType, entityOutput_bufferType, materialCache, - allBiomes, + worldStructure_workerData, runtime ); generatorBuilder.appendStage(propStage); @@ -211,15 +284,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()); @@ -229,14 +304,15 @@ public class HytaleGenerator extends JavaPlugin { .withMaterialCache(materialCache) .withConcurrentExecutor(this.concurrentExecutor, workerIndexer) .withBufferCapacity(bufferCapacityFactor, targetViewDistance, targetPlayerCount) + .withSpawnPositions(worldStructure_worker0.getSpawnPositions()) .build(); } @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/BaseHeightPositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/BaseHeightPositionProvider.java index 73b7c1a5..390bbb09 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/BaseHeightPositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/BaseHeightPositionProvider.java @@ -1,23 +1,20 @@ package com.hypixel.hytale.builtin.hytalegenerator.positionproviders; import com.hypixel.hytale.builtin.hytalegenerator.VectorUtil; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; import com.hypixel.hytale.math.vector.Vector3d; import javax.annotation.Nonnull; public class BaseHeightPositionProvider extends PositionProvider { @Nonnull - private final BiDouble2DoubleFunction baseHeightFunction; + private final double baseHeight; private final double maxYInput; private final double minYInput; @Nonnull private final PositionProvider positionProvider; - public BaseHeightPositionProvider( - @Nonnull BiDouble2DoubleFunction baseHeightFunction, @Nonnull PositionProvider positionProvider, double minYInput, double maxYInput - ) { + public BaseHeightPositionProvider(double baseHeight, @Nonnull PositionProvider positionProvider, double minYInput, double maxYInput) { maxYInput = Math.max(minYInput, maxYInput); - this.baseHeightFunction = baseHeightFunction; + this.baseHeight = baseHeight; this.positionProvider = positionProvider; this.maxYInput = maxYInput; this.minYInput = minYInput; @@ -28,7 +25,7 @@ public class BaseHeightPositionProvider extends PositionProvider { PositionProvider.Context childContext = new PositionProvider.Context(context); childContext.consumer = position -> { Vector3d offsetP = position.clone(); - offsetP.y = offsetP.y + this.baseHeightFunction.apply(position.x, position.z); + offsetP.y = offsetP.y + this.baseHeight; if (VectorUtil.isInside(offsetP, context.minInclusive, context.maxExclusive)) { context.consumer.accept(offsetP); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/BoundPositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/BoundPositionProvider.java new file mode 100644 index 00000000..3ce37b28 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/BoundPositionProvider.java @@ -0,0 +1,23 @@ +package com.hypixel.hytale.builtin.hytalegenerator.positionproviders; + +import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3d; +import javax.annotation.Nonnull; + +public class BoundPositionProvider extends PositionProvider { + @Nonnull + private final PositionProvider positionProvider; + private final Bounds3d bounds; + + public BoundPositionProvider(@Nonnull PositionProvider positionProvider, @Nonnull Bounds3d bounds) { + this.positionProvider = positionProvider; + this.bounds = bounds; + } + + @Override + public void positionsIn(@Nonnull PositionProvider.Context context) { + PositionProvider.Context childContext = new PositionProvider.Context(context); + childContext.minInclusive = this.bounds.min; + childContext.maxExclusive = this.bounds.max; + 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..8eb8d2b9 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionPositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/FieldFunctionPositionProvider.java @@ -33,12 +33,12 @@ 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) { if (d.isInside(value)) { context.consumer.accept(p); + return; } } }; 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..c60f344a 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; @@ -19,34 +18,26 @@ public abstract class PositionProvider { } public static class Context { + @Nonnull public static final Consumer EMPTY_CONSUMER = p -> {}; public Vector3d minInclusive; public Vector3d maxExclusive; 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 +45,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/SimpleHorizontalPositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/SimpleHorizontalPositionProvider.java index 306f11a6..2623bfc6 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/SimpleHorizontalPositionProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/SimpleHorizontalPositionProvider.java @@ -4,6 +4,7 @@ import com.hypixel.hytale.builtin.hytalegenerator.delimiters.RangeDouble; import javax.annotation.Nonnull; public class SimpleHorizontalPositionProvider extends PositionProvider { + @Nonnull private final RangeDouble rangeY; @Nonnull private final PositionProvider positionProvider; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/SpherePositionProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/SpherePositionProvider.java deleted file mode 100644 index f16b33c1..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/positionproviders/SpherePositionProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.positionproviders; - -import com.hypixel.hytale.builtin.hytalegenerator.VectorUtil; -import javax.annotation.Nonnull; - -public class SpherePositionProvider extends PositionProvider { - @Nonnull - private final PositionProvider positionProvider; - private final double range; - - public SpherePositionProvider(@Nonnull PositionProvider positionProvider, double range) { - this.positionProvider = positionProvider; - this.range = range; - } - - @Override - public void positionsIn(@Nonnull PositionProvider.Context context) { - PositionProvider.Context childContext = new PositionProvider.Context(context); - childContext.consumer = position -> { - double distance = position.length(); - if (VectorUtil.isInside(position, context.minInclusive, context.maxExclusive) && distance <= this.range) { - context.consumer.accept(position); - } - }; - this.positionProvider.positionsIn(childContext); - } -} 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/BoxProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/BoxProp.java index 997c84b5..397cd3d2 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/BoxProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/BoxProp.java @@ -16,16 +16,24 @@ import javax.annotation.Nonnull; import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class BoxProp extends Prop { + @Nonnull private final Vector3i range; + @Nonnull private final Material material; + @Nonnull private final Scanner scanner; + @Nonnull private final Pattern pattern; + @Nonnull private final ContextDependency contextDependency; + @Nonnull private final Bounds3i readBounds_voxelGrid; + @Nonnull private final Bounds3i writeBounds_voxelGrid; + @Nonnull private final Bounds3i boxBounds_voxelGrid; - public BoxProp(Vector3i range, @Nonnull Material material, @Nonnull Scanner scanner, @Nonnull Pattern pattern) { + public BoxProp(@Nonnull Vector3i range, @Nonnull Material material, @Nonnull Scanner scanner, @Nonnull Pattern pattern) { if (VectorUtil.isAnySmaller(range, new Vector3i())) { throw new IllegalArgumentException("negative range"); } else { @@ -44,6 +52,7 @@ public class BoxProp extends Prop { } } + @Nonnull public PositionListScanResult scan(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { Scanner.Context scannerContext = new Scanner.Context(position, this.pattern, materialSpace, id); List validPositions = this.scanner.scan(scannerContext); @@ -80,6 +89,7 @@ public class BoxProp extends Prop { } } + @Nonnull @Override public ContextDependency getContextDependency() { return this.contextDependency.clone(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/ClusterProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/ClusterProp.java index 72715fd5..5f6da4d5 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/ClusterProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/ClusterProp.java @@ -20,14 +20,22 @@ import javax.annotation.Nonnull; import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class ClusterProp extends Prop { + @Nonnull private final Double2DoubleFunction weightCurve; + @Nonnull private final SeedGenerator seedGenerator; + @Nonnull private final WeightedMap propWeightedMap; private final int range; + @Nonnull private final ContextDependency contextDependency; + @Nonnull private final Pattern pattern; + @Nonnull private final Scanner scanner; + @Nonnull private final Bounds3i readBounds_voxelGrid; + @Nonnull private final Bounds3i writeBounds_voxelGrid; public ClusterProp( @@ -63,6 +71,7 @@ public class ClusterProp extends Prop { } } + @Nonnull public PositionListScanResult scan(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { Scanner.Context scannerContext = new Scanner.Context(position, this.pattern, materialSpace, id); List validPositions = this.scanner.scan(scannerContext); @@ -106,6 +115,7 @@ public class ClusterProp extends Prop { } } + @Nonnull @Override public ContextDependency getContextDependency() { return this.contextDependency.clone(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/ColumnProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/ColumnProp.java index 67422642..5acc4a38 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/ColumnProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/ColumnProp.java @@ -22,14 +22,23 @@ import javax.annotation.Nonnull; import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class ColumnProp extends Prop { + @Nonnull private final int[] yPositions; + @Nonnull private final Material[] blocks0; + @Nonnull private final Material[] blocks90; + @Nonnull private final Material[] blocks180; + @Nonnull private final Material[] blocks270; + @Nonnull private final BlockMask blockMask; + @Nonnull private final Scanner scanner; + @Nonnull private final ContextDependency contextDependency; + @Nonnull private final Directionality directionality; @Nonnull private final Bounds3i readBounds_voxelGrid; @@ -74,12 +83,13 @@ public class ColumnProp extends Prop { } } + @Nonnull @Override public ScanResult scan(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { 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) { @@ -126,6 +136,7 @@ public class ColumnProp extends Prop { } } + @Nonnull @Override public ContextDependency getContextDependency() { return this.contextDependency.clone(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/DensityProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/DensityProp.java index fee96095..9782c98a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/DensityProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/DensityProp.java @@ -18,15 +18,25 @@ import javax.annotation.Nonnull; import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class DensityProp extends Prop { + @Nonnull private final Vector3i range; + @Nonnull private final Density density; + @Nonnull private final MaterialProvider materialProvider; + @Nonnull private final Scanner scanner; + @Nonnull private final Pattern pattern; + @Nonnull private final ContextDependency contextDependency; + @Nonnull private final BlockMask placementMask; + @Nonnull private final Material defaultMaterial; + @Nonnull private final Bounds3i readBounds_voxelGrid; + @Nonnull private final Bounds3i writeBounds_voxelGrid; public DensityProp( @@ -54,6 +64,7 @@ public class DensityProp extends Prop { this.writeBounds_voxelGrid = this.contextDependency.getWriteBounds_voxelGrid(); } + @Nonnull public PositionListScanResult scan(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { Scanner.Context scannerContext = new Scanner.Context(position, this.pattern, materialSpace, id); List validPositions = this.scanner.scan(scannerContext); @@ -70,7 +81,7 @@ public class DensityProp extends Prop { } } - private void place(Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { + private void place(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { Vector3i min = position.clone().add(-this.range.x, -this.range.y, -this.range.z); Vector3i max = position.clone().add(this.range.x, this.range.y, this.range.z); Vector3i writeMin = Vector3i.max(min, new Vector3i(materialSpace.minX(), materialSpace.minY(), materialSpace.minZ())); @@ -82,7 +93,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 +173,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 @@ -186,6 +196,7 @@ public class DensityProp extends Prop { } } + @Nonnull @Override public ContextDependency getContextDependency() { return this.contextDependency.clone(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/OffsetProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/OffsetProp.java index ef87ac2a..9d3bb033 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/OffsetProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/OffsetProp.java @@ -10,10 +10,15 @@ import javax.annotation.Nonnull; import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class OffsetProp extends Prop { + @Nonnull private final Vector3i offset_voxelGrid; + @Nonnull private final Prop childProp; + @Nonnull private final Bounds3i readBounds_voxelGrid; + @Nonnull private final Bounds3i writeBounds_voxelGrid; + @Nonnull private final ContextDependency contextDependency; public OffsetProp(@Nonnull Vector3i offset_voxelGrid, @Nonnull Prop childProp) { @@ -35,6 +40,7 @@ public class OffsetProp extends Prop { this.childProp.place(context); } + @Nonnull @Override public ContextDependency getContextDependency() { return this.contextDependency; diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/QueueProp.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/QueueProp.java index 9277ec43..0fd43d1b 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/QueueProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/QueueProp.java @@ -59,7 +59,9 @@ public class QueueProp extends Prop { public void place(@Nonnull Prop.Context context) { QueueProp.QueueScanResult conditionalScanResult = QueueProp.QueueScanResult.cast(context.scanResult); if (!conditionalScanResult.isNegative()) { - conditionalScanResult.prop.place(context); + Prop.Context childContext = new Prop.Context(context); + childContext.scanResult = conditionalScanResult.propScanResult; + conditionalScanResult.prop.place(childContext); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/ScanResult.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/ScanResult.java index 97a63466..622f969a 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/ScanResult.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/ScanResult.java @@ -3,6 +3,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.props; import javax.annotation.Nonnull; public interface ScanResult { + @Nonnull ScanResult NONE = new ScanResult() { @Override public boolean isNegative() { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/directionality/OrthogonalDirection.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/directionality/OrthogonalDirection.java index d4632f0e..f3dd0e18 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/directionality/OrthogonalDirection.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/directionality/OrthogonalDirection.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.props.directionality; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.codecs.EnumCodec; +import javax.annotation.Nonnull; public enum OrthogonalDirection { N, @@ -11,5 +12,6 @@ public enum OrthogonalDirection { U, D; + @Nonnull public static final Codec CODEC = new EnumCodec<>(OrthogonalDirection.class, EnumCodec.EnumStyle.LEGACY); } 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..d05ef307 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/filler/PondFillerProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/filler/PondFillerProp.java @@ -24,14 +24,23 @@ public class PondFillerProp extends Prop { private static final int LEAKS = 16; private static final int SOLID = 256; private static final int STACKED = 4096; + @Nonnull private final Vector3i boundingMin; + @Nonnull private final Vector3i boundingMax; + @Nonnull private final MaterialProvider filledMaterialProvider; + @Nonnull private final MaterialSet solidSet; + @Nonnull private final Scanner scanner; + @Nonnull private final Pattern pattern; + @Nonnull private final ContextDependency contextDependency; + @Nonnull private final Bounds3i readBounds_voxelGrid; + @Nonnull private final Bounds3i writeBounds_voxelGrid; public PondFillerProp( @@ -57,6 +66,7 @@ public class PondFillerProp extends Prop { this.writeBounds_voxelGrid = this.contextDependency.getWriteBounds_voxelGrid(); } + @Nonnull public FillerPropScanResult scan(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { Scanner.Context scannerContext = new Scanner.Context(position, this.pattern, materialSpace, id); List scanResults = this.scanner.scan(scannerContext); @@ -75,6 +85,7 @@ public class PondFillerProp extends Prop { } } + @Nonnull private List renderFluidBlocks(@Nonnull Vector3i origin, @Nonnull VoxelSpace materialSpace) { Vector3i min = this.boundingMin.clone().add(origin); Vector3i max = this.boundingMax.clone().add(origin); @@ -207,9 +218,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); @@ -219,6 +228,7 @@ public class PondFillerProp extends Prop { } } + @Nonnull @Override public ContextDependency getContextDependency() { return this.contextDependency.clone(); diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/MoldingDirection.java b/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/MoldingDirection.java index d197d469..ae1de3e4 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/MoldingDirection.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/MoldingDirection.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.builtin.hytalegenerator.props.prefab; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.codecs.EnumCodec; +import javax.annotation.Nonnull; public enum MoldingDirection { NONE, @@ -12,5 +13,6 @@ public enum MoldingDirection { EAST, WEST; + @Nonnull public static final Codec CODEC = new EnumCodec<>(MoldingDirection.class, EnumCodec.EnumStyle.LEGACY); } 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..56a554cd 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/PrefabProp.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/props/prefab/PrefabProp.java @@ -46,18 +46,30 @@ import javax.annotation.Nullable; import org.checkerframework.checker.nullness.compatqual.NonNullDecl; public class PrefabProp extends Prop { + @Nonnull private final WeightedMap> prefabPool; + @Nonnull private final Scanner scanner; private ContextDependency contextDependency; + @Nonnull private final MaterialCache materialCache; + @Nonnull private final SeedGenerator seedGenerator; + @Nonnull private final BlockMask materialMask; + @Nonnull private final Directionality directionality; + @Nonnull private final Bounds3i readBounds_voxelGrid; + @Nonnull private final Bounds3i writeBounds_voxelGrid; + @Nonnull private final Bounds3i prefabBounds_voxelGrid; + @Nonnull private final List childProps; + @Nonnull private final List childPositions; + @Nonnull private final Function> childPrefabLoader; private final Scanner moldingScanner; private final Pattern moldingPattern; @@ -157,7 +169,8 @@ public class PrefabProp extends Prop { this.prefabBounds_voxelGrid.max.assign(this.contextDependency.getWriteRange()).add(Vector3i.ALL_ONES); } - private Vector3i getWriteRange(PrefabBuffer.PrefabBufferAccessor prefabAccess) { + @Nonnull + private Vector3i getWriteRange(@Nonnull PrefabBuffer.PrefabBufferAccessor prefabAccess) { SpaceSize space = new SpaceSize(); for (PrefabRotation rotation : this.directionality.getPossibleRotations()) { @@ -171,12 +184,13 @@ public class PrefabProp extends Prop { return space.getRange(); } + @Nonnull @Override public ScanResult scan(@Nonnull Vector3i position, @Nonnull VoxelSpace materialSpace, @Nonnull WorkerIndexer.Id id) { 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) { @@ -207,14 +221,14 @@ public class PrefabProp extends Prop { } } - private PrefabBuffer pickPrefab(Random rand) { + private PrefabBuffer pickPrefab(@Nonnull Random rand) { List list = this.prefabPool.pick(rand); int randomIndex = rand.nextInt(list.size()); return list.get(randomIndex); } private void place( - RotatedPosition position, @Nonnull VoxelSpace materialSpace, @Nonnull EntityContainer entityBuffer, @Nonnull WorkerIndexer.Id id + @Nonnull RotatedPosition position, @Nonnull VoxelSpace materialSpace, @Nonnull EntityContainer entityBuffer, @Nonnull WorkerIndexer.Id id ) { Random random = new Random(this.seedGenerator.seedAt((long)position.x, (long)position.y, (long)position.z)); PrefabBufferCall callInstance = new PrefabBufferCall(random, position.rotation); @@ -279,7 +293,9 @@ public class PrefabProp extends Prop { Material worldMaterial = materialSpace.getContent(worldX, worldY, worldZ); int worldMaterialHash = worldMaterial.hashMaterialIds(); if (this.materialMask.canReplace(materialHash, worldMaterialHash)) { - materialSpace.set(material, worldX, worldY, worldZ); + if (filler == 0) { + materialSpace.set(material, worldX, worldY, worldZ); + } } } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/BaseHeightReference.java b/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/BaseHeightReference.java deleted file mode 100644 index 0b851311..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/BaseHeightReference.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.referencebundle; - -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; -import javax.annotation.Nonnull; - -public class BaseHeightReference extends Reference { - @Nonnull - private final BiDouble2DoubleFunction heightFunction; - - public BaseHeightReference(@Nonnull BiDouble2DoubleFunction heightFunction) { - this.heightFunction = heightFunction; - } - - @Nonnull - public BiDouble2DoubleFunction getHeightFunction() { - return this.heightFunction; - } -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/Reference.java b/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/Reference.java deleted file mode 100644 index f3c6ba4e..00000000 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/Reference.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.hypixel.hytale.builtin.hytalegenerator.referencebundle; - -public class Reference { -} diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/ReferenceBundle.java b/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/ReferenceBundle.java index 22a8cc8a..34d144cb 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/ReferenceBundle.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/referencebundle/ReferenceBundle.java @@ -7,27 +7,23 @@ import javax.annotation.Nullable; public class ReferenceBundle { @Nonnull - private final Map dataLayerMap = new HashMap<>(); + private final Map dataLayerMap = new HashMap<>(); @Nonnull - private final Map layerTypeMap = new HashMap<>(); + private final Map> layerTypeMap = new HashMap<>(); - public void put(@Nonnull String name, @Nonnull Reference reference, @Nonnull Class type) { + public void put(@Nonnull String name, @Nonnull T reference, @Nonnull Class type) { this.dataLayerMap.put(name, reference); - this.layerTypeMap.put(name, type.getName()); + this.layerTypeMap.put(name, type); } @Nullable - public Reference getLayerWithName(@Nonnull String name) { - return this.dataLayerMap.get(name); - } + public T get(@Nonnull String name, @Nonnull Class type) { + Class storedType = this.layerTypeMap.get(name); - @Nullable - public T getLayerWithName(@Nonnull String name, @Nonnull Class type) { - String storedType = this.layerTypeMap.get(name); - if (storedType == null) { - return null; - } else { - return (T)(!storedType.equals(type.getName()) ? null : this.dataLayerMap.get(name)); - } + assert storedType != null; + + assert type.isAssignableFrom(storedType); + + return (T)this.dataLayerMap.get(name); } } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/AreaScanner.java b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/AreaScanner.java index 5aef4a10..ba1f004e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/AreaScanner.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/AreaScanner.java @@ -81,6 +81,7 @@ public class AreaScanner extends Scanner { CIRCLE, SQUARE; + @Nonnull public static final Codec CODEC = new EnumCodec<>(AreaScanner.ScanShape.class, EnumCodec.EnumStyle.LEGACY); } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnLinearScanner.java b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnLinearScanner.java index b3037a5c..d25209e6 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnLinearScanner.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnLinearScanner.java @@ -1,32 +1,27 @@ package com.hypixel.hytale.builtin.hytalegenerator.scanners; import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; import com.hypixel.hytale.builtin.hytalegenerator.patterns.Pattern; import com.hypixel.hytale.math.vector.Vector3i; import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class ColumnLinearScanner extends Scanner { private final int minY; private final int maxY; private final boolean isRelativeToPosition; - @Nullable - private final BiDouble2DoubleFunction baseHeightFunction; + private final double baseHeight; private final int resultsCap; private final boolean topDownOrder; @Nonnull private final SpaceSize scanSpaceSize; - public ColumnLinearScanner( - int minY, int maxY, int resultsCap, boolean topDownOrder, boolean isRelativeToPosition, @Nullable BiDouble2DoubleFunction baseHeightFunction - ) { + public ColumnLinearScanner(int minY, int maxY, int resultsCap, boolean topDownOrder, boolean isRelativeToPosition, double baseHeight) { if (resultsCap < 0) { throw new IllegalArgumentException(); } else { - this.baseHeightFunction = baseHeightFunction; + this.baseHeight = baseHeight; this.minY = minY; this.maxY = maxY; this.isRelativeToPosition = isRelativeToPosition; @@ -45,17 +40,14 @@ public class ColumnLinearScanner extends Scanner { if (this.isRelativeToPosition) { scanMinY = Math.max(context.position.y + this.minY, context.materialSpace.minY()); scanMaxY = Math.min(context.position.y + this.maxY, context.materialSpace.maxY()); - } else if (this.baseHeightFunction != null) { - int bedY = (int)this.baseHeightFunction.apply(context.position.x, context.position.z); + } else { + int bedY = (int)this.baseHeight; scanMinY = Math.max(bedY + this.minY, context.materialSpace.minY()); scanMaxY = Math.min(bedY + this.maxY, context.materialSpace.maxY()); - } else { - scanMinY = Math.max(this.minY, context.materialSpace.minY()); - scanMaxY = Math.min(this.maxY, context.materialSpace.maxY()); } 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..592b968e 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnRandomScanner.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/ColumnRandomScanner.java @@ -1,7 +1,6 @@ package com.hypixel.hytale.builtin.hytalegenerator.scanners; import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize; -import com.hypixel.hytale.builtin.hytalegenerator.framework.interfaces.functions.BiDouble2DoubleFunction; import com.hypixel.hytale.builtin.hytalegenerator.framework.math.SeedGenerator; import com.hypixel.hytale.builtin.hytalegenerator.patterns.Pattern; import com.hypixel.hytale.math.util.FastRandom; @@ -10,14 +9,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class ColumnRandomScanner extends Scanner { private final int minY; private final int maxY; private final boolean isRelativeToPosition; - @Nullable - private final BiDouble2DoubleFunction bedFunction; + private final double baseHeight; private final int resultsCap; @Nonnull private final SeedGenerator seedGenerator; @@ -27,18 +24,12 @@ public class ColumnRandomScanner extends Scanner { private final SpaceSize scanSpaceSize; public ColumnRandomScanner( - int minY, - int maxY, - int resultsCap, - int seed, - @Nonnull ColumnRandomScanner.Strategy strategy, - boolean isRelativeToPosition, - @Nullable BiDouble2DoubleFunction bedFunction + int minY, int maxY, int resultsCap, int seed, @Nonnull ColumnRandomScanner.Strategy strategy, boolean isRelativeToPosition, double baseHeight ) { if (resultsCap < 0) { throw new IllegalArgumentException(); } else { - this.bedFunction = bedFunction; + this.baseHeight = baseHeight; this.minY = minY; this.maxY = maxY; this.isRelativeToPosition = isRelativeToPosition; @@ -68,19 +59,16 @@ public class ColumnRandomScanner extends Scanner { if (this.isRelativeToPosition) { scanMinY = Math.max(context.position.y + this.minY, context.materialSpace.minY()); scanMaxY = Math.min(context.position.y + this.maxY, context.materialSpace.maxY()); - } else if (this.bedFunction != null) { - int bedY = (int)this.bedFunction.apply(context.position.x, context.position.z); + } else { + int bedY = (int)this.baseHeight; scanMinY = Math.max(bedY + this.minY, context.materialSpace.minY()); scanMaxY = Math.min(bedY + this.maxY, context.materialSpace.maxY()); - } else { - scanMinY = Math.max(this.minY, context.materialSpace.minY()); - scanMaxY = Math.min(this.maxY, context.materialSpace.maxY()); } 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 +122,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..ba9475e8 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/OriginScanner.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/scanners/OriginScanner.java @@ -8,7 +8,9 @@ import java.util.List; import javax.annotation.Nonnull; public class OriginScanner extends Scanner { + @Nonnull private static final OriginScanner instance = new OriginScanner(); + @Nonnull private static final SpaceSize SCAN_SPACE_SIZE = new SpaceSize(new Vector3i(0, 0, 0), new Vector3i(1, 0, 1)); private OriginScanner() { @@ -17,7 +19,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(); } @@ -27,6 +29,7 @@ public class OriginScanner extends Scanner { return SCAN_SPACE_SIZE.clone(); } + @Nonnull public static OriginScanner getInstance() { return instance; } diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/threadindexer/WorkerIndexer.java b/src/com/hypixel/hytale/builtin/hytalegenerator/threadindexer/WorkerIndexer.java index e817fb29..1f77facb 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,30 @@ 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 int MAIN_THREAD_ID = 0; + @Nonnull public static final WorkerIndexer.Id UNKNOWN = new WorkerIndexer.Id(-1); + @Nonnull + public static final WorkerIndexer.Id MAIN = new WorkerIndexer.Id(0); public final int id; private Id(int id) { diff --git a/src/com/hypixel/hytale/builtin/hytalegenerator/tintproviders/TintProvider.java b/src/com/hypixel/hytale/builtin/hytalegenerator/tintproviders/TintProvider.java index cb976044..ebca3db7 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/tintproviders/TintProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/tintproviders/TintProvider.java @@ -32,6 +32,7 @@ public abstract class TintProvider { } public static class Result { + @Nonnull public static final TintProvider.Result WITHOUT_VALUE = new TintProvider.Result(); public final int tint; public final boolean hasValue; 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..fec45e17 100644 --- a/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/DensityGradientVectorProvider.java +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/vectorproviders/DensityGradientVectorProvider.java @@ -8,28 +8,35 @@ public class DensityGradientVectorProvider extends VectorProvider { @Nonnull private final Density density; private final double sampleDistance; + @Nonnull + private final Density.Context rChildContext; + @Nonnull + 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..5c549bfa --- /dev/null +++ b/src/com/hypixel/hytale/builtin/hytalegenerator/worldstructure/WorldStructure.java @@ -0,0 +1,55 @@ +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 com.hypixel.hytale.builtin.hytalegenerator.positionproviders.PositionProvider; +import javax.annotation.Nonnull; + +public class WorldStructure { + @Nonnull + private final BiCarta biomeMap; + @Nonnull + private final Registry biomeRegistry; + private final int biomeTransitionDistance; + private final int maxBiomeEdgeDistance; + @Nonnull + private final PositionProvider spawnPositions; + + public WorldStructure( + @Nonnull BiCarta biomeMap, + @Nonnull Registry biomeRegistry, + int biomeTransitionDistance, + int maxBiomeEdgeDistance, + @Nonnull PositionProvider spawnPositions + ) { + this.biomeMap = biomeMap; + this.biomeRegistry = biomeRegistry; + this.biomeTransitionDistance = biomeTransitionDistance; + this.maxBiomeEdgeDistance = maxBiomeEdgeDistance; + this.spawnPositions = spawnPositions; + } + + @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; + } + + @Nonnull + public PositionProvider getSpawnPositions() { + return this.spawnPositions; + } +} diff --git a/src/com/hypixel/hytale/builtin/instances/InstanceValidator.java b/src/com/hypixel/hytale/builtin/instances/InstanceValidator.java index bb81cf6f..031ae5c1 100644 --- a/src/com/hypixel/hytale/builtin/instances/InstanceValidator.java +++ b/src/com/hypixel/hytale/builtin/instances/InstanceValidator.java @@ -7,7 +7,10 @@ import com.hypixel.hytale.codec.validation.Validator; import javax.annotation.Nonnull; public class InstanceValidator implements Validator { + @Nonnull public static final InstanceValidator INSTANCE = new InstanceValidator(); + @Nonnull + public static final String CUSTOM_ASSET_NAME = "Instance"; public void accept(@Nonnull String s, @Nonnull ValidationResults results) { if (!InstancesPlugin.doesInstanceAssetExist(s)) { diff --git a/src/com/hypixel/hytale/builtin/instances/InstancesPlugin.java b/src/com/hypixel/hytale/builtin/instances/InstancesPlugin.java index 64a5eabe..b083c6e6 100644 --- a/src/com/hypixel/hytale/builtin/instances/InstancesPlugin.java +++ b/src/com/hypixel/hytale/builtin/instances/InstancesPlugin.java @@ -25,6 +25,7 @@ import com.hypixel.hytale.codec.schema.config.ObjectSchema; import com.hypixel.hytale.codec.schema.config.Schema; import com.hypixel.hytale.codec.schema.config.StringSchema; import com.hypixel.hytale.common.util.FormatUtil; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; @@ -171,14 +172,17 @@ public class InstancesPlugin extends JavaPlugin { worldKey = "instance-" + safeName(name) + "-" + uuid; } - Path worldPath = path.resolve("worlds").resolve(worldKey); + Path worldPath = universe.validateWorldPath(worldKey); String finalWorldKey = worldKey; return WorldConfig.load(assetPath.resolve("instance.bson")) .thenApplyAsync( SneakyThrow.sneakyFunction( config -> { config.setUuid(uuid); - config.setDisplayName(WorldConfig.formatDisplayName(name)); + if (config.getDisplayName() == null) { + config.setDisplayName(WorldConfig.formatDisplayName(name)); + } + InstanceWorldConfig instanceConfig = InstanceWorldConfig.ensureAndGet(config); instanceConfig.setReturnPoint( new WorldReturnPoint(forWorld.getWorldConfig().getUuid(), returnPoint, instanceConfig.shouldPreventReconnection()) @@ -302,7 +306,7 @@ public class InstancesPlugin extends JavaPlugin { } } - public static void exitInstance(@Nonnull Ref targetRef, @Nonnull ComponentAccessor componentAccessor) { + public static CompletableFuture exitInstance(@Nonnull Ref targetRef, @Nonnull ComponentAccessor componentAccessor) { World world = componentAccessor.getExternalData().getWorld(); InstanceEntityConfig entityConfig = componentAccessor.getComponent(targetRef, InstanceEntityConfig.getComponentType()); WorldReturnPoint returnPoint = entityConfig != null ? entityConfig.getReturnPoint() : null; @@ -321,7 +325,10 @@ public class InstancesPlugin extends JavaPlugin { throw new IllegalArgumentException("Missing return world"); } else { Teleport teleportComponent = Teleport.createForPlayer(targetWorld, returnPoint.getReturnPoint()); + CompletableFuture future = new CompletableFuture<>(); + teleportComponent.setOnComplete(future); componentAccessor.addComponent(targetRef, Teleport.getComponentType(), teleportComponent); + return future; } } @@ -350,13 +357,24 @@ public class InstancesPlugin extends JavaPlugin { @Nonnull public static Path getInstanceAssetPath(@Nonnull String name) { for (AssetPack pack : AssetModule.get().getAssetPacks()) { - Path path = pack.getRoot().resolve("Server").resolve("Instances").resolve(name); + Path instancesDir = pack.getRoot().resolve("Server").resolve("Instances"); + Path path = PathUtil.resolvePathWithinDir(instancesDir, name); + if (path == null) { + throw new IllegalArgumentException("Invalid instance name"); + } + if (Files.exists(path)) { return path; } } - return AssetModule.get().getBaseAssetPack().getRoot().resolve("Server").resolve("Instances").resolve(name); + Path instancesDirx = AssetModule.get().getBaseAssetPack().getRoot().resolve("Server").resolve("Instances"); + Path pathx = PathUtil.resolvePathWithinDir(instancesDirx, name); + if (pathx == null) { + throw new IllegalArgumentException("Invalid instance name"); + } else { + return pathx; + } } public static boolean doesInstanceAssetExist(@Nonnull String name) { @@ -561,7 +579,7 @@ public class InstancesPlugin extends JavaPlugin { Path instancePath = getInstanceAssetPath(name); Universe universe = Universe.get(); WorldConfig config = WorldConfig.load(instancePath.resolve("instance.bson")).join(); - IChunkStorageProvider storage = config.getChunkStorageProvider(); + IChunkStorageProvider storage = config.getChunkStorageProvider(); config.setChunkStorageProvider(new MigrationChunkStorageProvider(new IChunkStorageProvider[]{storage}, EmptyChunkStorageProvider.INSTANCE)); config.setResourceStorageProvider(EmptyResourceStorageProvider.INSTANCE); config.setUuid(UUID.randomUUID()); diff --git a/src/com/hypixel/hytale/builtin/instances/blocks/ConfigurableInstanceBlock.java b/src/com/hypixel/hytale/builtin/instances/blocks/ConfigurableInstanceBlock.java index b9cf14b0..55076203 100644 --- a/src/com/hypixel/hytale/builtin/instances/blocks/ConfigurableInstanceBlock.java +++ b/src/com/hypixel/hytale/builtin/instances/blocks/ConfigurableInstanceBlock.java @@ -76,6 +76,7 @@ public class ConfigurableInstanceBlock implements Component { private boolean personalReturnPoint = false; private double removeBlockAfter = -1.0; + @Nonnull public static ComponentType getComponentType() { return InstancesPlugin.get().getConfigurableInstanceBlockComponentType(); } diff --git a/src/com/hypixel/hytale/builtin/instances/blocks/InstanceBlock.java b/src/com/hypixel/hytale/builtin/instances/blocks/InstanceBlock.java index 546b5569..48e852b7 100644 --- a/src/com/hypixel/hytale/builtin/instances/blocks/InstanceBlock.java +++ b/src/com/hypixel/hytale/builtin/instances/blocks/InstanceBlock.java @@ -21,6 +21,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class InstanceBlock implements Component { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(InstanceBlock.class, InstanceBlock::new) .appendInherited(new KeyedCodec<>("WorldName", Codec.UUID_BINARY), (o, i) -> o.worldUUID = i, o -> o.worldUUID, (o, p) -> o.worldUUID = p.worldUUID) .add() @@ -36,6 +37,7 @@ public class InstanceBlock implements Component { protected CompletableFuture worldFuture; protected boolean closeOnRemove = true; + @Nonnull public static ComponentType getComponentType() { return InstancesPlugin.get().getInstanceBlockComponentType(); } diff --git a/src/com/hypixel/hytale/builtin/instances/command/InstanceEditCopyCommand.java b/src/com/hypixel/hytale/builtin/instances/command/InstanceEditCopyCommand.java index a118f857..7fffee97 100644 --- a/src/com/hypixel/hytale/builtin/instances/command/InstanceEditCopyCommand.java +++ b/src/com/hypixel/hytale/builtin/instances/command/InstanceEditCopyCommand.java @@ -1,6 +1,7 @@ package com.hypixel.hytale.builtin.instances.command; import com.hypixel.hytale.builtin.instances.InstancesPlugin; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.command.system.CommandContext; @@ -17,7 +18,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 ); @@ -39,9 +42,11 @@ public class InstanceEditCopyCommand extends AbstractAsyncCommand { context.sendMessage(Message.translation("server.commands.instances.edit.copy.originNotFound").param("path", originPath.toAbsolutePath().toString())); return CompletableFuture.completedFuture(null); } else { - String destinationName = this.destinationNameArg.get(context); - Path destinationPath = originPath.getParent().resolve(destinationName); - if (Files.exists(destinationPath)) { + Path destinationPath = PathUtil.resolveName(originPath.getParent(), this.destinationNameArg.get(context)); + if (destinationPath == null) { + context.sendMessage(Message.translation("server.commands.instances.edit.copy.invalidPath")); + return CompletableFuture.completedFuture(null); + } else if (Files.exists(destinationPath)) { context.sendMessage( Message.translation("server.commands.instances.edit.copy.destinationExists").param("path", destinationPath.toAbsolutePath().toString()) ); @@ -50,9 +55,9 @@ public class InstanceEditCopyCommand extends AbstractAsyncCommand { WorldConfig worldConfig; try { worldConfig = WorldConfig.load(originPath.resolve("instance.bson")).join(); - } catch (Throwable var10) { + } catch (Throwable var9) { context.sendMessage(Message.translation("server.commands.instances.edit.copy.errorLoading")); - InstancesPlugin.get().getLogger().at(Level.SEVERE).log("Error loading origin instance config for copy", var10); + InstancesPlugin.get().getLogger().at(Level.SEVERE).log("Error loading origin instance config for copy", var9); return CompletableFuture.completedFuture(null); } @@ -62,9 +67,9 @@ public class InstanceEditCopyCommand extends AbstractAsyncCommand { try { FileUtil.copyDirectory(originPath, destinationPath); Files.deleteIfExists(destinationConfigFile); - } catch (Throwable var9) { + } catch (Throwable var8) { context.sendMessage(Message.translation("server.commands.instances.edit.copy.errorCopying")); - InstancesPlugin.get().getLogger().at(Level.SEVERE).log("Error copying instance folder for copy", var9); + InstancesPlugin.get().getLogger().at(Level.SEVERE).log("Error copying instance folder for copy", var8); return CompletableFuture.completedFuture(null); } @@ -73,7 +78,7 @@ public class InstanceEditCopyCommand extends AbstractAsyncCommand { () -> context.sendMessage( Message.translation("server.commands.instances.copiedInstanceAssetConfig") .param("origin", instanceToCopy) - .param("destination", destinationName) + .param("destination", destinationPath.getFileName().toString()) ) ); } 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/instances/command/InstanceEditNewCommand.java b/src/com/hypixel/hytale/builtin/instances/command/InstanceEditNewCommand.java index a107f81a..de72c2d3 100644 --- a/src/com/hypixel/hytale/builtin/instances/command/InstanceEditNewCommand.java +++ b/src/com/hypixel/hytale/builtin/instances/command/InstanceEditNewCommand.java @@ -1,6 +1,7 @@ package com.hypixel.hytale.builtin.instances.command; import com.hypixel.hytale.assetstore.AssetPack; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.command.system.CommandContext; @@ -16,7 +17,11 @@ import java.util.concurrent.CompletableFuture; import javax.annotation.Nonnull; public class InstanceEditNewCommand extends AbstractAsyncCommand { + @Nonnull + private static final Message MESSAGE_SERVER_COMMANDS_INSTANCES_EDIT_ASSETS_IMMUTABLE = Message.translation("server.commands.instances.edit.assetsImmutable"); + @Nonnull private final RequiredArg instanceNameArg = this.withRequiredArg("instanceName", "server.commands.instances.edit.arg.name", ArgTypes.STRING); + @Nonnull private final OptionalArg packName = this.withOptionalArg("pack", "server.commands.instances.edit.arg.packName", ArgTypes.STRING); public InstanceEditNewCommand() { @@ -27,7 +32,7 @@ public class InstanceEditNewCommand extends AbstractAsyncCommand { @Override public CompletableFuture executeAsync(@Nonnull CommandContext context) { if (AssetModule.get().getBaseAssetPack().isImmutable()) { - context.sendMessage(Message.translation("server.commands.instances.edit.assetsImmutable")); + context.sendMessage(MESSAGE_SERVER_COMMANDS_INSTANCES_EDIT_ASSETS_IMMUTABLE); return CompletableFuture.completedFuture(null); } else { String packId = this.packName.get(context); @@ -41,19 +46,25 @@ public class InstanceEditNewCommand extends AbstractAsyncCommand { pack = AssetModule.get().getBaseAssetPack(); } - String name = this.instanceNameArg.get(context); - Path path = pack.getRoot().resolve("Server").resolve("Instances").resolve(name); - WorldConfig defaultConfig = new WorldConfig(); - - try { - Files.createDirectories(path); - } catch (IOException var8) { - context.sendMessage(Message.translation("server.commands.instances.createDirectory.failed").param("errormsg", var8.getMessage())); + Path path = PathUtil.resolveName(pack.getRoot().resolve("Server").resolve("Instances"), this.instanceNameArg.get(context)); + if (path == null) { + context.sendMessage(Message.translation("server.commands.instances.edit.new.invalidPath")); return CompletableFuture.completedFuture(null); - } + } else { + try { + Files.createDirectories(path); + } catch (IOException var6) { + context.sendMessage(Message.translation("server.commands.instances.createDirectory.failed").param("errormsg", var6.getMessage())); + return CompletableFuture.completedFuture(null); + } - return WorldConfig.save(path.resolve("instance.bson"), defaultConfig) - .thenRun(() -> context.sendMessage(Message.translation("server.commands.instances.createdInstanceAssetConfig").param("name", name))); + return WorldConfig.save(path.resolve("instance.bson"), new WorldConfig()) + .thenRun( + () -> context.sendMessage( + Message.translation("server.commands.instances.createdInstanceAssetConfig").param("name", path.getFileName().toString()) + ) + ); + } } } } diff --git a/src/com/hypixel/hytale/builtin/instances/command/InstanceMigrateCommand.java b/src/com/hypixel/hytale/builtin/instances/command/InstanceMigrateCommand.java index 667f23de..e1885b7f 100644 --- a/src/com/hypixel/hytale/builtin/instances/command/InstanceMigrateCommand.java +++ b/src/com/hypixel/hytale/builtin/instances/command/InstanceMigrateCommand.java @@ -45,7 +45,7 @@ public class InstanceMigrateCommand extends AbstractAsyncCommand { private static final long CHUNK_UPDATE_INTERVAL = 100L; public InstanceMigrateCommand() { - super("migrate", ""); + super("migrate", "server.commands.instances.migrate.desc"); } @Nonnull diff --git a/src/com/hypixel/hytale/builtin/instances/config/ExitInstance.java b/src/com/hypixel/hytale/builtin/instances/config/ExitInstance.java index b9e46d35..81b7d717 100644 --- a/src/com/hypixel/hytale/builtin/instances/config/ExitInstance.java +++ b/src/com/hypixel/hytale/builtin/instances/config/ExitInstance.java @@ -30,8 +30,7 @@ public class ExitInstance implements RespawnController { @Nonnull World world, @Nonnull Ref playerReference, @Nonnull ComponentAccessor commandBuffer ) { try { - InstancesPlugin.exitInstance(playerReference, commandBuffer); - return CompletableFuture.completedFuture(null); + return InstancesPlugin.exitInstance(playerReference, commandBuffer); } catch (Exception var6) { PlayerRef playerRefComponent = commandBuffer.getComponent(playerReference, PlayerRef.getComponentType()); diff --git a/src/com/hypixel/hytale/builtin/instances/config/InstanceEntityConfig.java b/src/com/hypixel/hytale/builtin/instances/config/InstanceEntityConfig.java index b17e38c2..8f6d1b86 100644 --- a/src/com/hypixel/hytale/builtin/instances/config/InstanceEntityConfig.java +++ b/src/com/hypixel/hytale/builtin/instances/config/InstanceEntityConfig.java @@ -11,7 +11,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class InstanceEntityConfig implements Component { + @Nonnull public static final String ID = "Instance"; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(InstanceEntityConfig.class, InstanceEntityConfig::new) .appendInherited( new KeyedCodec<>("ReturnPoint", WorldReturnPoint.CODEC), (o, i) -> o.returnPoint = i, o -> o.returnPoint, (o, p) -> o.returnPoint = p.returnPoint @@ -58,9 +60,9 @@ public class InstanceEntityConfig implements Component { @Nonnull public InstanceEntityConfig clone() { - InstanceEntityConfig v = new InstanceEntityConfig(); - v.returnPoint = v.returnPoint.clone(); - v.returnPointOverride = v.returnPointOverride.clone(); - return v; + InstanceEntityConfig config = new InstanceEntityConfig(); + config.returnPoint = config.returnPoint.clone(); + config.returnPointOverride = config.returnPointOverride.clone(); + return config; } } diff --git a/src/com/hypixel/hytale/builtin/instances/config/InstanceWorldConfig.java b/src/com/hypixel/hytale/builtin/instances/config/InstanceWorldConfig.java index f6a26c1a..e9cfdd14 100644 --- a/src/com/hypixel/hytale/builtin/instances/config/InstanceWorldConfig.java +++ b/src/com/hypixel/hytale/builtin/instances/config/InstanceWorldConfig.java @@ -11,6 +11,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class InstanceWorldConfig { + @Nonnull public static final String ID = "Instance"; @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(InstanceWorldConfig.class, InstanceWorldConfig::new) @@ -40,7 +41,7 @@ public class InstanceWorldConfig { private RemovalCondition[] removalConditions = RemovalCondition.EMPTY; @Nullable private WorldReturnPoint returnPoint; - private boolean preventReconnection = false; + private boolean preventReconnection; @Nullable private InstanceDiscoveryConfig discovery; diff --git a/src/com/hypixel/hytale/builtin/instances/config/WorldReturnPoint.java b/src/com/hypixel/hytale/builtin/instances/config/WorldReturnPoint.java index 93fe8079..3036cdb6 100644 --- a/src/com/hypixel/hytale/builtin/instances/config/WorldReturnPoint.java +++ b/src/com/hypixel/hytale/builtin/instances/config/WorldReturnPoint.java @@ -9,6 +9,7 @@ import java.util.UUID; import javax.annotation.Nonnull; public class WorldReturnPoint { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(WorldReturnPoint.class, WorldReturnPoint::new) .documentation("A world/location pair that is used as a place to return players to.") .append(new KeyedCodec<>("World", Codec.UUID_BINARY), (o, i) -> o.world = i, o -> o.world) diff --git a/src/com/hypixel/hytale/builtin/instances/interactions/ExitInstanceInteraction.java b/src/com/hypixel/hytale/builtin/instances/interactions/ExitInstanceInteraction.java index 022e4a98..97c091c8 100644 --- a/src/com/hypixel/hytale/builtin/instances/interactions/ExitInstanceInteraction.java +++ b/src/com/hypixel/hytale/builtin/instances/interactions/ExitInstanceInteraction.java @@ -17,6 +17,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; public class ExitInstanceInteraction extends SimpleInstantInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( ExitInstanceInteraction.class, ExitInstanceInteraction::new, SimpleInstantInteraction.CODEC ) @@ -31,8 +32,11 @@ public class ExitInstanceInteraction extends SimpleInstantInteraction { @Override protected void firstRun(@Nonnull InteractionType type, @Nonnull InteractionContext context, @Nonnull CooldownHandler cooldownHandler) { - Ref ref = context.getEntity(); CommandBuffer commandBuffer = context.getCommandBuffer(); + + assert commandBuffer != null; + + Ref ref = context.getEntity(); Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType()); if (playerComponent == null || !playerComponent.isWaitingForClientReady()) { Archetype archetype = commandBuffer.getArchetype(ref); diff --git a/src/com/hypixel/hytale/builtin/instances/interactions/TeleportConfigInstanceInteraction.java b/src/com/hypixel/hytale/builtin/instances/interactions/TeleportConfigInstanceInteraction.java index 7831124e..6af985f7 100644 --- a/src/com/hypixel/hytale/builtin/instances/interactions/TeleportConfigInstanceInteraction.java +++ b/src/com/hypixel/hytale/builtin/instances/interactions/TeleportConfigInstanceInteraction.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.Axis; import com.hypixel.hytale.math.shape.Box; import com.hypixel.hytale.math.util.ChunkUtil; @@ -45,6 +46,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class TeleportConfigInstanceInteraction extends SimpleBlockInteraction { + @Nonnull + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); @Nonnull private static final Message MESSAGE_GENERAL_INTERACTION_CONFIGURE_INSTANCE_NO_INSTANCE_NAME = Message.translation( "server.general.interaction.configureInstance.noInstanceName" @@ -139,16 +142,31 @@ public class TeleportConfigInstanceInteraction extends SimpleBlockInteraction { if (removeBlockAfter == 0.0) { long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); WorldChunk worldChunk = world.getChunk(chunkIndex); - worldChunk.setBlock(targetBlock.x, targetBlock.y, targetBlock.z, 0, 256); + if (worldChunk != null) { + worldChunk.setBlock(targetBlock.x, targetBlock.y, targetBlock.z, 0, 256); + } else { + LOGGER.atWarning() + .log("Failed to remove block at %s,%s,%s as chunk is not loaded", targetBlock.x, targetBlock.y, targetBlock.z); + } } else { int block = world.getBlock(targetBlock); - new CompletableFuture().completeOnTimeout(null, (long)(removeBlockAfter * 1.0E9), TimeUnit.NANOSECONDS).thenRunAsync(() -> { - if (world.getBlock(targetBlock) == block) { - long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); - WorldChunk worldChunkx = world.getChunk(chunkIndex); - worldChunkx.setBlock(targetBlock.x, targetBlock.y, targetBlock.z, 0, 256); - } - }, world); + new CompletableFuture() + .completeOnTimeout(null, (long)(removeBlockAfter * 1.0E9), TimeUnit.NANOSECONDS) + .thenRunAsync( + () -> { + if (world.getBlock(targetBlock) == block) { + long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); + WorldChunk worldChunkx = world.getChunk(chunkIndex); + if (worldChunkx != null) { + worldChunkx.setBlock(targetBlock.x, targetBlock.y, targetBlock.z, 0, 256); + } else { + LOGGER.atWarning() + .log("Failed to remove block at %s,%s,%s as chunk is not loaded", targetBlock.x, targetBlock.y, targetBlock.z); + } + } + }, + world + ); } } } @@ -194,34 +212,41 @@ public class TeleportConfigInstanceInteraction extends SimpleBlockInteraction { Ref chunkRef = chunkStore.getChunkReference(chunkIndex); if (chunkRef != null && chunkRef.isValid()) { BlockChunk blockChunkComponent = chunkComponentStore.getComponent(chunkRef, BlockChunk.getComponentType()); - - assert blockChunkComponent != null; - - WorldChunk worldChunkComponent = chunkComponentStore.getComponent(chunkRef, WorldChunk.getComponentType()); - - assert worldChunkComponent != null; - - BlockType blockType = worldChunkComponent.getBlockType(targetBlock.x, targetBlock.y, targetBlock.z); - if (blockType == null) { - throw new IllegalArgumentException("Block type not found"); + if (blockChunkComponent == null) { + throw new IllegalArgumentException("Block chunk component not found"); } else { - IndexedLookupTableAssetMap hitboxAssetMap = BlockBoundingBoxes.getAssetMap(); - BlockSection section = blockChunkComponent.getSectionAtBlockY(targetBlock.y); - int rotationIndex = section.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z); - RotationTuple rotation = RotationTuple.get(rotationIndex); - Box hitbox = hitboxAssetMap.getAsset(blockType.getHitboxTypeIndex()).get(rotationIndex).getBoundingBox(); - Vector3d position = state.getPositionOffset() != null ? rotation.rotate(state.getPositionOffset()) : new Vector3d(); - position.x = position.x + (hitbox.middleX() + targetBlock.x); - position.y = position.y + (hitbox.middleY() + targetBlock.y); - position.z = position.z + (hitbox.middleZ() + targetBlock.z); - Vector3f rotationOutput = Vector3f.NaN; - if (state.getRotation() != null) { - rotationOutput = state.getRotation().clone(); - rotationOutput.addRotationOnAxis(Axis.Y, rotation.yaw().getDegrees()); - rotationOutput.addRotationOnAxis(Axis.X, rotation.pitch().getDegrees()); - } + WorldChunk worldChunkComponent = chunkComponentStore.getComponent(chunkRef, WorldChunk.getComponentType()); + if (worldChunkComponent == null) { + throw new IllegalArgumentException("World chunk component not found"); + } else { + BlockType blockType = worldChunkComponent.getBlockType(targetBlock.x, targetBlock.y, targetBlock.z); + if (blockType == null) { + throw new IllegalArgumentException("Block type not found"); + } else { + IndexedLookupTableAssetMap hitboxAssetMap = BlockBoundingBoxes.getAssetMap(); + BlockSection section = blockChunkComponent.getSectionAtBlockY(targetBlock.y); + int rotationIndex = section.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z); + RotationTuple rotation = RotationTuple.get(rotationIndex); + BlockBoundingBoxes hitboxAsset = hitboxAssetMap.getAsset(blockType.getHitboxTypeIndex()); + if (hitboxAsset == null) { + throw new IllegalArgumentException("Hitbox asset not found for block type: " + blockType.getId()); + } else { + Box hitbox = hitboxAsset.get(rotationIndex).getBoundingBox(); + Vector3d position = state.getPositionOffset() != null ? rotation.rotate(state.getPositionOffset()) : new Vector3d(); + position.x = position.x + (hitbox.middleX() + targetBlock.x); + position.y = position.y + (hitbox.middleY() + targetBlock.y); + position.z = position.z + (hitbox.middleZ() + targetBlock.z); + Vector3f rotationOutput = Vector3f.NaN; + if (state.getRotation() != null) { + rotationOutput = state.getRotation().clone(); + rotationOutput.addRotationOnAxis(Axis.Y, rotation.yaw().getDegrees()); + rotationOutput.addRotationOnAxis(Axis.X, rotation.pitch().getDegrees()); + } - return new Transform(position, rotationOutput); + return new Transform(position, rotationOutput); + } + } + } } } else { throw new IllegalArgumentException("Chunk not loaded"); diff --git a/src/com/hypixel/hytale/builtin/instances/interactions/TeleportInstanceInteraction.java b/src/com/hypixel/hytale/builtin/instances/interactions/TeleportInstanceInteraction.java index a16b7509..8607b6fe 100644 --- a/src/com/hypixel/hytale/builtin/instances/interactions/TeleportInstanceInteraction.java +++ b/src/com/hypixel/hytale/builtin/instances/interactions/TeleportInstanceInteraction.java @@ -48,6 +48,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class TeleportInstanceInteraction extends SimpleInstantInteraction { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TeleportInstanceInteraction.class, TeleportInstanceInteraction::new, SimpleInstantInteraction.CODEC ) diff --git a/src/com/hypixel/hytale/builtin/instances/page/ConfigureInstanceBlockPage.java b/src/com/hypixel/hytale/builtin/instances/page/ConfigureInstanceBlockPage.java index b7fe4274..7025dbf9 100644 --- a/src/com/hypixel/hytale/builtin/instances/page/ConfigureInstanceBlockPage.java +++ b/src/com/hypixel/hytale/builtin/instances/page/ConfigureInstanceBlockPage.java @@ -204,18 +204,31 @@ public class ConfigureInstanceBlockPage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder( ConfigureInstanceBlockPage.PageData.class, ConfigureInstanceBlockPage.PageData::new diff --git a/src/com/hypixel/hytale/builtin/instances/page/InstanceListPage.java b/src/com/hypixel/hytale/builtin/instances/page/InstanceListPage.java index 5df6f8b7..456251f6 100644 --- a/src/com/hypixel/hytale/builtin/instances/page/InstanceListPage.java +++ b/src/com/hypixel/hytale/builtin/instances/page/InstanceListPage.java @@ -16,7 +16,6 @@ import com.hypixel.hytale.server.core.entity.entities.player.pages.InteractiveCu import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport; -import com.hypixel.hytale.server.core.ui.Value; import com.hypixel.hytale.server.core.ui.browser.FileBrowserConfig; import com.hypixel.hytale.server.core.ui.browser.FileBrowserEventData; import com.hypixel.hytale.server.core.ui.browser.ServerFileBrowser; @@ -33,9 +32,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class InstanceListPage extends InteractiveCustomUIPage { - private static final String COMMON_TEXT_BUTTON_DOCUMENT = "Pages/BasicTextButton.ui"; - private static final Value BUTTON_LABEL_STYLE = Value.ref("Pages/BasicTextButton.ui", "LabelStyle"); - private static final Value BUTTON_LABEL_STYLE_SELECTED = Value.ref("Pages/BasicTextButton.ui", "SelectedLabelStyle"); + @Nonnull private static final String ASSET_PACK_SUB_PATH = "Server/Instances"; @Nullable private String selectedInstance; @@ -211,8 +208,11 @@ public class InstanceListPage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder(InstanceListPage.PageData.class, InstanceListPage.PageData::new) .addField(new KeyedCodec<>("Instance", BuilderCodec.STRING), (o, i) -> o.instance = i, o -> o.instance) .addField(new KeyedCodec<>("Action", new EnumCodec<>(InstanceListPage.Action.class)), (o, i) -> o.action = i, o -> o.action) diff --git a/src/com/hypixel/hytale/builtin/instances/removal/IdleTimeoutCondition.java b/src/com/hypixel/hytale/builtin/instances/removal/IdleTimeoutCondition.java index 2983cd33..dd4b79b1 100644 --- a/src/com/hypixel/hytale/builtin/instances/removal/IdleTimeoutCondition.java +++ b/src/com/hypixel/hytale/builtin/instances/removal/IdleTimeoutCondition.java @@ -12,6 +12,7 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; public class IdleTimeoutCondition implements RemovalCondition { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(IdleTimeoutCondition.class, IdleTimeoutCondition::new) .documentation("A condition that triggers after the world has be idle (without players) for a set time.") .append(new KeyedCodec<>("TimeoutSeconds", Codec.DOUBLE), (o, i) -> o.timeoutSeconds = i, o -> o.timeoutSeconds) diff --git a/src/com/hypixel/hytale/builtin/instances/removal/InstanceDataResource.java b/src/com/hypixel/hytale/builtin/instances/removal/InstanceDataResource.java index 50890ce3..589915a8 100644 --- a/src/com/hypixel/hytale/builtin/instances/removal/InstanceDataResource.java +++ b/src/com/hypixel/hytale/builtin/instances/removal/InstanceDataResource.java @@ -9,8 +9,10 @@ import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import java.time.Instant; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class InstanceDataResource implements Resource { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(InstanceDataResource.class, InstanceDataResource::new) .append(new KeyedCodec<>("TimeoutTimer", Codec.INSTANT), (o, i) -> o.timeoutTimer = i, o -> o.timeoutTimer) .add() @@ -25,6 +27,7 @@ public class InstanceDataResource implements Resource { private Instant timeoutTimer; private Instant idleTimeoutTimer; private boolean hadPlayer; + @Nullable private Instant worldTimeoutTimer; @Nonnull @@ -64,11 +67,12 @@ public class InstanceDataResource implements Resource { this.hadPlayer = hadPlayer; } + @Nullable public Instant getWorldTimeoutTimer() { return this.worldTimeoutTimer; } - public void setWorldTimeoutTimer(Instant worldTimeoutTimer) { + public void setWorldTimeoutTimer(@Nullable Instant worldTimeoutTimer) { this.worldTimeoutTimer = worldTimeoutTimer; } diff --git a/src/com/hypixel/hytale/builtin/instances/removal/RemovalCondition.java b/src/com/hypixel/hytale/builtin/instances/removal/RemovalCondition.java index caffb3e7..99aee605 100644 --- a/src/com/hypixel/hytale/builtin/instances/removal/RemovalCondition.java +++ b/src/com/hypixel/hytale/builtin/instances/removal/RemovalCondition.java @@ -8,6 +8,7 @@ import javax.annotation.Nonnull; public interface RemovalCondition { @Nonnull CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull RemovalCondition[] EMPTY = new RemovalCondition[0]; boolean shouldRemoveWorld(@Nonnull Store var1); diff --git a/src/com/hypixel/hytale/builtin/instances/removal/RemovalSystem.java b/src/com/hypixel/hytale/builtin/instances/removal/RemovalSystem.java index 366a4f5e..e9bf97d0 100644 --- a/src/com/hypixel/hytale/builtin/instances/removal/RemovalSystem.java +++ b/src/com/hypixel/hytale/builtin/instances/removal/RemovalSystem.java @@ -1,6 +1,7 @@ package com.hypixel.hytale.builtin.instances.removal; import com.hypixel.hytale.builtin.instances.config.InstanceWorldConfig; +import com.hypixel.hytale.common.util.CompletableFutureUtil; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.system.tick.RunWhenPausedSystem; import com.hypixel.hytale.component.system.tick.TickingSystem; @@ -13,10 +14,10 @@ import javax.annotation.Nonnull; public class RemovalSystem extends TickingSystem implements RunWhenPausedSystem { @Override public void tick(float dt, int systemIndex, @Nonnull Store store) { - InstanceDataResource data = store.getResource(InstanceDataResource.getResourceType()); - if (!data.isRemoving() && shouldRemoveWorld(store)) { - data.setRemoving(true); - CompletableFuture.runAsync(() -> Universe.get().removeWorld(store.getExternalData().getWorld().getName())); + InstanceDataResource instanceDataResource = store.getResource(InstanceDataResource.getResourceType()); + if (!instanceDataResource.isRemoving() && shouldRemoveWorld(store)) { + instanceDataResource.setRemoving(true); + CompletableFutureUtil._catch(CompletableFuture.runAsync(() -> Universe.get().removeWorld(store.getExternalData().getWorld().getName()))); } } diff --git a/src/com/hypixel/hytale/builtin/instances/removal/TimeoutCondition.java b/src/com/hypixel/hytale/builtin/instances/removal/TimeoutCondition.java index 01a96db6..b1b866eb 100644 --- a/src/com/hypixel/hytale/builtin/instances/removal/TimeoutCondition.java +++ b/src/com/hypixel/hytale/builtin/instances/removal/TimeoutCondition.java @@ -11,6 +11,7 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; public class TimeoutCondition implements RemovalCondition { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(TimeoutCondition.class, TimeoutCondition::new) .documentation("A condition that triggers after a set time limit.") .append(new KeyedCodec<>("TimeoutSeconds", Codec.DOUBLE), (o, i) -> o.timeoutSeconds = i, o -> o.timeoutSeconds) diff --git a/src/com/hypixel/hytale/builtin/instances/removal/WorldEmptyCondition.java b/src/com/hypixel/hytale/builtin/instances/removal/WorldEmptyCondition.java index 7bf9bd71..c0e70436 100644 --- a/src/com/hypixel/hytale/builtin/instances/removal/WorldEmptyCondition.java +++ b/src/com/hypixel/hytale/builtin/instances/removal/WorldEmptyCondition.java @@ -11,8 +11,11 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; public class WorldEmptyCondition implements RemovalCondition { + @Nonnull public static final WorldEmptyCondition INSTANCE = new WorldEmptyCondition(); + @Nonnull public static final RemovalCondition[] REMOVE_WHEN_EMPTY = new RemovalCondition[]{INSTANCE}; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(WorldEmptyCondition.class, WorldEmptyCondition::new) .documentation( "A condition that triggers when the world is empty.\n\nIt will only trigger after at least one player has joined. As a safety measure it provides a timeout for waiting for a player to join in case the player disconnected before entering the world." diff --git a/src/com/hypixel/hytale/builtin/landiscovery/LANDiscoveryCommand.java b/src/com/hypixel/hytale/builtin/landiscovery/LANDiscoveryCommand.java index fc89d3a5..6a680344 100644 --- a/src/com/hypixel/hytale/builtin/landiscovery/LANDiscoveryCommand.java +++ b/src/com/hypixel/hytale/builtin/landiscovery/LANDiscoveryCommand.java @@ -5,7 +5,6 @@ import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg; import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase; -import com.hypixel.hytale.server.core.util.message.MessageFormat; import javax.annotation.Nonnull; public class LANDiscoveryCommand extends CommandBase { @@ -32,7 +31,7 @@ public class LANDiscoveryCommand extends CommandBase { context.sendMessage(MESSAGE_IO_LAN_DISCOVERY_DISABLED); } } else { - boolean enabled = this.enabledArg.get(context); + Boolean enabled = this.enabledArg.get(context); LANDiscoveryPlugin plugin = LANDiscoveryPlugin.get(); if (!enabled && plugin.getLanDiscoveryThread() != null) { plugin.setLANDiscoveryEnabled(false); @@ -41,7 +40,7 @@ public class LANDiscoveryCommand extends CommandBase { plugin.setLANDiscoveryEnabled(true); context.sendMessage(MESSAGE_IO_LAN_DISCOVERY_ENABLED); } else { - context.sendMessage(Message.translation("server.io.landiscovery.alreadyToggled").param("status", MessageFormat.enabled(enabled))); + context.sendMessage(Message.translation("server.io.landiscovery.alreadyToggled").param("enabled", enabled.toString())); } } } diff --git a/src/com/hypixel/hytale/builtin/model/pages/ChangeModelPage.java b/src/com/hypixel/hytale/builtin/model/pages/ChangeModelPage.java index e46684ad..02469289 100644 --- a/src/com/hypixel/hytale/builtin/model/pages/ChangeModelPage.java +++ b/src/com/hypixel/hytale/builtin/model/pages/ChangeModelPage.java @@ -44,8 +44,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ChangeModelPage extends InteractiveCustomUIPage { + @Nonnull private static final String COMMON_TEXT_BUTTON_DOCUMENT = "Common/TextButton.ui"; + @Nonnull private static final Value BUTTON_LABEL_STYLE = Value.ref("Common/TextButton.ui", "LabelStyle"); + @Nonnull private static final Value BUTTON_LABEL_STYLE_SELECTED = Value.ref("Common/TextButton.ui", "SelectedLabelStyle"); @Nonnull private String searchQuery = ""; @@ -227,10 +230,15 @@ public class ChangeModelPage extends InteractiveCustomUIPage CODEC = BuilderCodec.builder( ChangeModelPage.PageEventData.class, ChangeModelPage.PageEventData::new ) diff --git a/src/com/hypixel/hytale/builtin/mounts/BlockMountAPI.java b/src/com/hypixel/hytale/builtin/mounts/BlockMountAPI.java index 6ea982e4..6677b984 100644 --- a/src/com/hypixel/hytale/builtin/mounts/BlockMountAPI.java +++ b/src/com/hypixel/hytale/builtin/mounts/BlockMountAPI.java @@ -17,13 +17,15 @@ import com.hypixel.hytale.server.core.universe.world.chunk.BlockComponentChunk; 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.storage.EntityStore; +import javax.annotation.Nonnull; public final class BlockMountAPI { private BlockMountAPI() { } + @Nonnull public static BlockMountAPI.BlockMountResult mountOnBlock( - Ref entity, CommandBuffer commandBuffer, Vector3i targetBlock, Vector3f interactPos + @Nonnull Ref entity, @Nonnull CommandBuffer commandBuffer, @Nonnull Vector3i targetBlock, @Nonnull Vector3f interactPos ) { MountedComponent existingMounted = commandBuffer.getComponent(entity, MountedComponent.getComponentType()); if (existingMounted != null) { 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..61fafe88 100644 --- a/src/com/hypixel/hytale/builtin/mounts/MountPlugin.java +++ b/src/com/hypixel/hytale/builtin/mounts/MountPlugin.java @@ -7,19 +7,28 @@ import com.hypixel.hytale.builtin.mounts.interactions.SpawnMinecartInteraction; import com.hypixel.hytale.builtin.mounts.minecart.MinecartComponent; import com.hypixel.hytale.builtin.mounts.npc.builders.BuilderActionMount; import com.hypixel.hytale.component.ComponentAccessor; +import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; -import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.component.ResourceType; 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.entity.movement.MovementStatesComponent; import com.hypixel.hytale.server.core.io.ServerManager; +import com.hypixel.hytale.server.core.modules.entity.component.Interactable; +import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; +import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent; +import com.hypixel.hytale.server.core.modules.entity.player.PlayerInput; +import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport; +import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; +import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction; +import com.hypixel.hytale.server.core.modules.time.TimeResource; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; +import com.hypixel.hytale.server.core.prefab.PrefabCopyableComponent; 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; @@ -61,32 +70,52 @@ public class MountPlugin extends JavaPlugin { @Override protected void setup() { + ComponentRegistryProxy entityStoreRegistry = this.getEntityStoreRegistry(); instance = this; this.blockMountComponentType = this.getChunkStoreRegistry().registerComponent(BlockMountComponent.class, BlockMountComponent::new); NPCPlugin.get().registerCoreComponentType("Mount", BuilderActionMount::new); - this.mountComponentType = this.getEntityStoreRegistry().registerComponent(NPCMountComponent.class, "Mount", NPCMountComponent.CODEC); - this.mountedComponentType = this.getEntityStoreRegistry().registerComponent(MountedComponent.class, () -> { + this.mountComponentType = entityStoreRegistry.registerComponent(NPCMountComponent.class, "Mount", NPCMountComponent.CODEC); + this.mountedComponentType = entityStoreRegistry.registerComponent(MountedComponent.class, () -> { throw new UnsupportedOperationException("Mounted component cannot be default constructed"); }); - this.mountedByComponentType = this.getEntityStoreRegistry().registerComponent(MountedByComponent.class, MountedByComponent::new); - this.minecartComponentType = this.getEntityStoreRegistry().registerComponent(MinecartComponent.class, "Minecart", MinecartComponent.CODEC); - this.getEntityStoreRegistry().registerSystem(new NPCMountSystems.OnAdd(this.mountComponentType)); - this.getEntityStoreRegistry().registerSystem(new NPCMountSystems.DismountOnPlayerDeath()); - this.getEntityStoreRegistry().registerSystem(new NPCMountSystems.DismountOnMountDeath()); - 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.TeleportMountedEntity()); - this.getEntityStoreRegistry().registerSystem(new MountSystems.MountedEntityDeath()); - this.getEntityStoreRegistry().registerSystem(new MountSystems.PlayerMount()); - this.getEntityStoreRegistry().registerSystem(new MountSystems.HandleMountInput()); - this.getEntityStoreRegistry().registerSystem(new MountSystems.TrackedMounted()); - this.getEntityStoreRegistry().registerSystem(new MountSystems.EnsureMinecartComponents()); - this.getEntityStoreRegistry().registerSystem(new MountSystems.OnMinecartHit()); - this.getChunkStoreRegistry().registerSystem(new MountSystems.RemoveBlockSeat()); + this.mountedByComponentType = entityStoreRegistry.registerComponent(MountedByComponent.class, MountedByComponent::new); + this.minecartComponentType = entityStoreRegistry.registerComponent(MinecartComponent.class, "Minecart", MinecartComponent.CODEC); + ComponentType npcEntityComponentType = NPCEntity.getComponentType(); + ComponentType networkIdComponentType = NetworkId.getComponentType(); + ComponentType playerComponentType = Player.getComponentType(); + ComponentType visibleComponentType = EntityTrackerSystems.Visible.getComponentType(); + ComponentType playerInputComponentType = PlayerInput.getComponentType(); + ComponentType movementStatesComponentType = MovementStatesComponent.getComponentType(); + ComponentType transformComponentType = TransformComponent.getComponentType(); + ComponentType teleportComponentType = Teleport.getComponentType(); + ComponentType deathComponentType = DeathComponent.getComponentType(); + ComponentType interactableComponentType = Interactable.getComponentType(); + ComponentType prefabCopyableComponentType = PrefabCopyableComponent.getComponentType(); + ResourceType timeResourceType = TimeResource.getResourceType(); + entityStoreRegistry.registerSystem(new NPCMountSystems.OnAdd(this.mountComponentType, npcEntityComponentType, networkIdComponentType)); + entityStoreRegistry.registerSystem(new NPCMountSystems.DismountOnPlayerDeath(playerComponentType)); + entityStoreRegistry.registerSystem(new NPCMountSystems.DismountOnMountDeath(this.mountComponentType)); + entityStoreRegistry.registerSystem(new NPCMountSystems.OnPlayerRemove(playerComponentType)); + entityStoreRegistry.registerSystem(new MountSystems.TrackerUpdate(visibleComponentType, this.mountedComponentType)); + entityStoreRegistry.registerSystem(new MountSystems.TrackerRemove(this.mountedComponentType, visibleComponentType)); + entityStoreRegistry.registerSystem(new MountSystems.RemoveMountedBy(this.mountedByComponentType, this.mountedComponentType)); + entityStoreRegistry.registerSystem(new MountSystems.RemoveMounted(this.mountedComponentType)); + entityStoreRegistry.registerSystem(new MountSystems.RemoveMountedHolder(this.mountedComponentType)); + entityStoreRegistry.registerSystem(new MountSystems.TeleportMountedEntity(this.mountedComponentType, teleportComponentType)); + entityStoreRegistry.registerSystem(new MountSystems.MountedEntityDeath(this.mountedComponentType, deathComponentType)); + entityStoreRegistry.registerSystem(new MountSystems.PlayerMount(this.mountedComponentType, playerInputComponentType, networkIdComponentType)); + entityStoreRegistry.registerSystem( + new MountSystems.HandleMountInput(this.mountedComponentType, playerInputComponentType, movementStatesComponentType, transformComponentType) + ); + entityStoreRegistry.registerSystem(new MountSystems.TrackedMounted(this.mountedComponentType, this.mountedByComponentType)); + entityStoreRegistry.registerSystem( + new MountSystems.EnsureMinecartComponents(this.minecartComponentType, interactableComponentType, networkIdComponentType, prefabCopyableComponentType) + ); + entityStoreRegistry.registerSystem( + new MountSystems.OnMinecartHit(this.minecartComponentType, transformComponentType, playerComponentType, timeResourceType) + ); + this.getChunkStoreRegistry().registerSystem(new MountSystems.RemoveBlockSeat(this.blockMountComponentType, this.mountedComponentType)); 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 +126,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 +142,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 +157,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..0f76d43d 100644 --- a/src/com/hypixel/hytale/builtin/mounts/MountSystems.java +++ b/src/com/hypixel/hytale/builtin/mounts/MountSystems.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.RemoveReason; +import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.SystemGroup; import com.hypixel.hytale.component.dependency.Dependency; @@ -25,7 +26,6 @@ import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.math.vector.Vector3f; import com.hypixel.hytale.protocol.AnimationSlot; import com.hypixel.hytale.protocol.BlockMount; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.GameMode; import com.hypixel.hytale.protocol.MountController; @@ -65,7 +65,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class MountSystems { - private static void handleMountedRemoval(Ref ref, @Nonnull CommandBuffer commandBuffer, @Nonnull MountedComponent component) { + private static void handleMountedRemoval( + @Nonnull Ref ref, @Nonnull CommandBuffer commandBuffer, @Nonnull MountedComponent component + ) { Ref mountedToEntity = component.getMountedToEntity(); if (mountedToEntity != null && mountedToEntity.isValid()) { MountedByComponent mountedBy = commandBuffer.getComponent(mountedToEntity, MountedByComponent.getComponentType()); @@ -88,20 +90,42 @@ public class MountSystems { } public static class EnsureMinecartComponents extends HolderSystem { + @Nonnull + private final ComponentType minecartComponentType; + @Nonnull + private final ComponentType interactableComponentType; + @Nonnull + private final ComponentType networkIdComponentType; + @Nonnull + private final ComponentType prefabCopyableComponentType; + + public EnsureMinecartComponents( + @Nonnull ComponentType minecartComponentType, + @Nonnull ComponentType interactableComponentType, + @Nonnull ComponentType networkIdComponentType, + @Nonnull ComponentType prefabCopyableComponentType + ) { + this.minecartComponentType = minecartComponentType; + this.interactableComponentType = interactableComponentType; + this.networkIdComponentType = networkIdComponentType; + this.prefabCopyableComponentType = prefabCopyableComponentType; + } + @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - holder.ensureComponent(Interactable.getComponentType()); - holder.putComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId())); - holder.ensureComponent(PrefabCopyableComponent.getComponentType()); + holder.ensureComponent(this.interactableComponentType); + holder.putComponent(this.networkIdComponentType, new NetworkId(store.getExternalData().takeNextNetworkId())); + holder.ensureComponent(this.prefabCopyableComponentType); } @Override public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { } + @Nonnull @Override public Query getQuery() { - return MinecartComponent.getComponentType(); + return this.minecartComponentType; } @Nonnull @@ -112,9 +136,32 @@ public class MountSystems { } public static class HandleMountInput extends EntityTickingSystem { - private final Query query = Query.and(MountedComponent.getComponentType(), PlayerInput.getComponentType()); + @Nonnull + private final ComponentType mountedComponentType; + @Nonnull + private final ComponentType playerInputComponentType; + @Nonnull + private final ComponentType movementStatesComponentType; + @Nonnull + private final ComponentType transformComponentType; + @Nonnull + private final Query query; + @Nonnull private final Set> deps = Set.of(new SystemDependency<>(Order.BEFORE, PlayerSystems.ProcessPlayerInput.class)); + public HandleMountInput( + @Nonnull ComponentType mountedComponentType, + @Nonnull ComponentType playerInputComponentType, + @Nonnull ComponentType movementStatesComponentType, + @Nonnull ComponentType transformComponentType + ) { + this.mountedComponentType = mountedComponentType; + this.playerInputComponentType = playerInputComponentType; + this.movementStatesComponentType = movementStatesComponentType; + this.transformComponentType = transformComponentType; + this.query = Query.and(mountedComponentType, playerInputComponentType); + } + @Override public void tick( float dt, @@ -123,55 +170,62 @@ public class MountSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - MountedComponent mounted = archetypeChunk.getComponent(index, MountedComponent.getComponentType()); + MountedComponent mountedComponent = archetypeChunk.getComponent(index, this.mountedComponentType); - assert mounted != null; + assert mountedComponent != null; - PlayerInput input = archetypeChunk.getComponent(index, PlayerInput.getComponentType()); + PlayerInput playerInputComponent = archetypeChunk.getComponent(index, this.playerInputComponentType); - assert input != null; + assert playerInputComponent != null; - MountController controller = mounted.getControllerType(); - Ref targetRef = controller == MountController.BlockMount ? archetypeChunk.getReferenceTo(index) : mounted.getMountedToEntity(); - List queue = input.getMovementUpdateQueue(); + MountController controller = mountedComponent.getControllerType(); + Ref targetRef = controller == MountController.BlockMount ? archetypeChunk.getReferenceTo(index) : mountedComponent.getMountedToEntity(); + List queue = playerInputComponent.getMovementUpdateQueue(); for (int i = 0; i < queue.size(); i++) { - PlayerInput.InputUpdate q = queue.get(i); - if (controller == MountController.BlockMount && (q instanceof PlayerInput.RelativeMovement || q instanceof PlayerInput.AbsoluteMovement)) { - if (mounted.getMountedDurationMs() < 600L) { + PlayerInput.InputUpdate inputUpdate = queue.get(i); + if (controller == MountController.BlockMount + && (inputUpdate instanceof PlayerInput.RelativeMovement || inputUpdate instanceof PlayerInput.AbsoluteMovement)) { + if (mountedComponent.getMountedDurationMs() < 600L) { continue; } Ref ref = archetypeChunk.getReferenceTo(index); - commandBuffer.removeComponent(ref, MountedComponent.getComponentType()); + commandBuffer.tryRemoveComponent(ref, this.mountedComponentType); } - if (q instanceof PlayerInput.SetRiderMovementStates s) { + if (inputUpdate instanceof PlayerInput.SetRiderMovementStates s) { MovementStates states = s.movementStates(); - MovementStatesComponent movementStatesComponent = archetypeChunk.getComponent(index, MovementStatesComponent.getComponentType()); + MovementStatesComponent movementStatesComponent = archetypeChunk.getComponent(index, this.movementStatesComponentType); if (movementStatesComponent != null) { movementStatesComponent.setMovementStates(states); } - } else if (!(q instanceof PlayerInput.WishMovement)) { - if (q instanceof PlayerInput.RelativeMovement relative) { + } else if (!(inputUpdate instanceof PlayerInput.WishMovement)) { + if (inputUpdate 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()); - } else if (q instanceof PlayerInput.AbsoluteMovement absolute) { + TransformComponent transform = commandBuffer.getComponent(targetRef, this.transformComponentType); + if (transform != null) { + transform.getPosition().add(relative.getX(), relative.getY(), relative.getZ()); + } + } else if (inputUpdate 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()); - } else if (q instanceof PlayerInput.SetMovementStates sx) { + TransformComponent transform = commandBuffer.getComponent(targetRef, this.transformComponentType); + if (transform != null) { + transform.getPosition().assign(absolute.getX(), absolute.getY(), absolute.getZ()); + } + } else if (inputUpdate instanceof PlayerInput.SetMovementStates sx) { MovementStates states = sx.movementStates(); - MovementStatesComponent movementStatesComponent = commandBuffer.getComponent(targetRef, MovementStatesComponent.getComponentType()); + MovementStatesComponent movementStatesComponent = commandBuffer.getComponent(targetRef, this.movementStatesComponentType); if (movementStatesComponent != null) { movementStatesComponent.setMovementStates(states); } - } else if (q instanceof PlayerInput.SetBody body) { + } else if (inputUpdate 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); - } else if (q instanceof PlayerInput.SetHead head) { + TransformComponent transform = commandBuffer.getComponent(targetRef, this.transformComponentType); + if (transform != null) { + transform.getRotation().assign(body.direction().pitch, body.direction().yaw, body.direction().roll); + } + } else if (inputUpdate instanceof PlayerInput.SetHead head) { head.apply(commandBuffer, archetypeChunk, index); } } @@ -194,21 +248,34 @@ public class MountSystems { } public static class MountedEntityDeath extends RefChangeSystem { + @Nonnull + private final ComponentType mountedComponentType; + @Nonnull + private final ComponentType deathComponentType; + + public MountedEntityDeath( + @Nonnull ComponentType mountedComponentType, @Nonnull ComponentType deathComponentType + ) { + this.mountedComponentType = mountedComponentType; + this.deathComponentType = deathComponentType; + } + + @Nonnull @Override public Query getQuery() { - return MountedComponent.getComponentType(); + return this.mountedComponentType; } @Nonnull @Override public ComponentType componentType() { - return DeathComponent.getComponentType(); + return this.deathComponentType; } public void onComponentAdded( @Nonnull Ref ref, @Nonnull DeathComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - commandBuffer.removeComponent(ref, MountedComponent.getComponentType()); + commandBuffer.removeComponent(ref, this.mountedComponentType); } public void onComponentSet( @@ -230,23 +297,45 @@ public class MountSystems { private static final Duration HIT_RESET_TIME = Duration.ofSeconds(10L); private static final int NUMBER_OF_HITS = 3; @Nonnull - private static final Query QUERY = Archetype.of(MinecartComponent.getComponentType(), TransformComponent.getComponentType()); + private final ComponentType minecartComponentType; @Nonnull - private static final Set> DEPENDENCIES = Set.of( + private final ComponentType transformComponentType; + @Nonnull + private final ComponentType playerComponentType; + @Nonnull + private final ResourceType timeResourceType; + @Nonnull + private final Query query; + @Nonnull + private final Set> dependencies = Set.of( new SystemGroupDependency<>(Order.AFTER, DamageModule.get().getGatherDamageGroup()), new SystemGroupDependency<>(Order.AFTER, DamageModule.get().getFilterDamageGroup()), new SystemGroupDependency<>(Order.BEFORE, DamageModule.get().getInspectDamageGroup()) ); + public OnMinecartHit( + @Nonnull ComponentType minecartComponentType, + @Nonnull ComponentType transformComponentType, + @Nonnull ComponentType playerComponentType, + @Nonnull ResourceType timeResourceType + ) { + this.minecartComponentType = minecartComponentType; + this.transformComponentType = transformComponentType; + this.playerComponentType = playerComponentType; + this.timeResourceType = timeResourceType; + this.query = Archetype.of(minecartComponentType, transformComponentType); + } + + @Nonnull @Override public Query getQuery() { - return QUERY; + return this.query; } @Nonnull @Override public Set> getDependencies() { - return DEPENDENCIES; + return this.dependencies; } public void handle( @@ -256,11 +345,11 @@ public class MountSystems { @Nonnull CommandBuffer commandBuffer, @Nonnull Damage damage ) { - MinecartComponent minecartComponent = archetypeChunk.getComponent(index, MinecartComponent.getComponentType()); + MinecartComponent minecartComponent = archetypeChunk.getComponent(index, this.minecartComponentType); assert minecartComponent != null; - Instant currentTime = commandBuffer.getResource(TimeResource.getResourceType()).getNow(); + Instant currentTime = commandBuffer.getResource(this.timeResourceType).getNow(); if (minecartComponent.getLastHit() != null && currentTime.isAfter(minecartComponent.getLastHit().plus(HIT_RESET_TIME))) { minecartComponent.setLastHit(null); minecartComponent.setNumberOfHits(0); @@ -273,14 +362,14 @@ public class MountSystems { commandBuffer.removeEntity(archetypeChunk.getReferenceTo(index), RemoveReason.REMOVE); boolean shouldDropItem = true; if (damage.getSource() instanceof Damage.EntitySource source) { - Player playerComponent = source.getRef().isValid() ? commandBuffer.getComponent(source.getRef(), Player.getComponentType()) : null; + Player playerComponent = source.getRef().isValid() ? commandBuffer.getComponent(source.getRef(), this.playerComponentType) : null; if (playerComponent != null) { shouldDropItem = playerComponent.getGameMode() != GameMode.Creative; } } if (shouldDropItem && minecartComponent.getSourceItem() != null) { - TransformComponent transform = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + TransformComponent transform = archetypeChunk.getComponent(index, this.transformComponentType); assert transform != null; @@ -297,8 +386,27 @@ public class MountSystems { } public static class PlayerMount extends RefChangeSystem { - private final Query query = PlayerInput.getComponentType(); + @Nonnull + private final ComponentType mountedComponentType; + @Nonnull + private final ComponentType playerInputComponentType; + @Nonnull + private final ComponentType networkIdComponentType; + @Nonnull + private final Query query; + public PlayerMount( + @Nonnull ComponentType mountedComponentType, + @Nonnull ComponentType playerInputComponentType, + @Nonnull ComponentType networkIdComponentType + ) { + this.mountedComponentType = mountedComponentType; + this.playerInputComponentType = playerInputComponentType; + this.networkIdComponentType = networkIdComponentType; + this.query = playerInputComponentType; + } + + @Nonnull @Override public Query getQuery() { return this.query; @@ -307,7 +415,7 @@ public class MountSystems { @Nonnull @Override public ComponentType componentType() { - return MountedComponent.getComponentType(); + return this.mountedComponentType; } public void onComponentAdded( @@ -316,19 +424,22 @@ public class MountSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - MountedComponent mounted = commandBuffer.getComponent(ref, MountedComponent.getComponentType()); + MountedComponent mountedComponent = commandBuffer.getComponent(ref, this.mountedComponentType); - assert mounted != null; + assert mountedComponent != null; - PlayerInput input = commandBuffer.getComponent(ref, PlayerInput.getComponentType()); + PlayerInput playerInputComponent = commandBuffer.getComponent(ref, this.playerInputComponentType); - assert input != null; + assert playerInputComponent != null; - Ref mountRef = mounted.getMountedToEntity(); + Ref mountRef = mountedComponent.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, this.networkIdComponentType); + if (mountNetworkIdComponent != null) { + int mountNetworkId = mountNetworkIdComponent.getId(); + playerInputComponent.setMountId(mountNetworkId); + playerInputComponent.getMovementUpdateQueue().clear(); + } } } @@ -347,15 +458,28 @@ public class MountSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - PlayerInput input = commandBuffer.getComponent(ref, PlayerInput.getComponentType()); + PlayerInput playerInputComponent = commandBuffer.getComponent(ref, this.playerInputComponentType); - assert input != null; + assert playerInputComponent != null; - input.setMountId(0); + playerInputComponent.setMountId(0); } } public static class RemoveBlockSeat extends RefSystem { + @Nonnull + private final ComponentType blockMountComponentType; + @Nonnull + private final ComponentType mountedComponentType; + + public RemoveBlockSeat( + @Nonnull ComponentType blockMountComponentType, + @Nonnull ComponentType mountedComponentType + ) { + this.blockMountComponentType = blockMountComponentType; + this.mountedComponentType = mountedComponentType; + } + @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer @@ -366,7 +490,7 @@ public class MountSystems { public void onEntityRemove( @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - BlockMountComponent blockSeatComponent = commandBuffer.getComponent(ref, BlockMountComponent.getComponentType()); + BlockMountComponent blockSeatComponent = commandBuffer.getComponent(ref, this.blockMountComponentType); assert blockSeatComponent != null; @@ -377,19 +501,27 @@ public class MountSystems { blockSeatComponent.removeSeatedEntity(seated); world.execute(() -> { if (seated.isValid()) { - seated.getStore().tryRemoveComponent(seated, MountedComponent.getComponentType()); + seated.getStore().tryRemoveComponent(seated, this.mountedComponentType); } }); } } + @Nonnull @Override public Query getQuery() { - return BlockMountComponent.getComponentType(); + return this.blockMountComponentType; } } public static class RemoveMounted extends RefSystem { + @Nonnull + private final ComponentType mountedComponentType; + + public RemoveMounted(@Nonnull ComponentType mountedComponentType) { + this.mountedComponentType = mountedComponentType; + } + @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer @@ -400,18 +532,31 @@ public class MountSystems { public void onEntityRemove( @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - MountedComponent mounted = commandBuffer.getComponent(ref, MountedComponent.getComponentType()); - commandBuffer.removeComponent(ref, MountedComponent.getComponentType()); + MountedComponent mounted = commandBuffer.getComponent(ref, this.mountedComponentType); MountSystems.handleMountedRemoval(ref, commandBuffer, mounted); } + @Nonnull @Override public Query getQuery() { - return MountedComponent.getComponentType(); + return this.mountedComponentType; } } public static class RemoveMountedBy extends RefSystem { + @Nonnull + private final ComponentType mountedByComponentType; + @Nonnull + private final ComponentType mountedComponentType; + + public RemoveMountedBy( + @Nonnull ComponentType mountedByComponentType, + @Nonnull ComponentType mountedComponentType + ) { + this.mountedByComponentType = mountedByComponentType; + this.mountedComponentType = mountedComponentType; + } + @Override public void onEntityAdded( @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer @@ -422,48 +567,88 @@ public class MountSystems { public void onEntityRemove( @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - MountedByComponent by = commandBuffer.getComponent(ref, MountedByComponent.getComponentType()); + MountedByComponent mountedByComponent = commandBuffer.getComponent(ref, this.mountedByComponentType); - for (Ref p : by.getPassengers()) { + assert mountedByComponent != null; + + for (Ref p : mountedByComponent.getPassengers()) { if (p.isValid()) { - MountedComponent mounted = commandBuffer.getComponent(p, MountedComponent.getComponentType()); - if (mounted != null) { - Ref target = mounted.getMountedToEntity(); - if (!target.isValid() || target.equals(ref)) { - commandBuffer.removeComponent(p, MountedComponent.getComponentType()); + MountedComponent mountedComponent = commandBuffer.getComponent(p, this.mountedComponentType); + if (mountedComponent != null) { + Ref targetRef = mountedComponent.getMountedToEntity(); + if (targetRef != null && (!targetRef.isValid() || targetRef.equals(ref))) { + commandBuffer.removeComponent(p, this.mountedComponentType); } } } } } + @Nonnull @Override public Query getQuery() { - return MountedByComponent.getComponentType(); + return this.mountedByComponentType; + } + } + + public static class RemoveMountedHolder extends HolderSystem { + @Nonnull + private final ComponentType mountedComponentType; + + public RemoveMountedHolder(@Nonnull ComponentType mountedComponentType) { + this.mountedComponentType = mountedComponentType; + } + + @Nonnull + @Override + public Query getQuery() { + return this.mountedComponentType; + } + + @Override + public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { + } + + @Override + public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { + holder.removeComponent(this.mountedComponentType); } } public static class TeleportMountedEntity extends RefChangeSystem { - private static final Set> DEPENDENCIES = Set.of( + @Nonnull + private final ComponentType mountedComponentType; + @Nonnull + private final ComponentType teleportComponentType; + @Nonnull + private final Set> dependencies = Set.of( new SystemDependency<>(Order.BEFORE, TeleportSystems.MoveSystem.class, OrderPriority.CLOSEST), new SystemDependency<>(Order.BEFORE, TeleportSystems.PlayerMoveSystem.class, OrderPriority.CLOSEST) ); + public TeleportMountedEntity( + @Nonnull ComponentType mountedComponentType, @Nonnull ComponentType teleportComponentType + ) { + this.mountedComponentType = mountedComponentType; + this.teleportComponentType = teleportComponentType; + } + + @Nonnull @Override public Query getQuery() { - return MountedComponent.getComponentType(); + return this.mountedComponentType; } @Nonnull @Override public ComponentType componentType() { - return Teleport.getComponentType(); + return this.teleportComponentType; } public void onComponentAdded( @Nonnull Ref ref, @Nonnull Teleport component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - commandBuffer.removeComponent(ref, MountedComponent.getComponentType()); + commandBuffer.removeComponent(ref, this.mountedComponentType); } public void onComponentSet( @@ -483,20 +668,34 @@ public class MountSystems { @Nonnull @Override public Set> getDependencies() { - return DEPENDENCIES; + return this.dependencies; } } public static class TrackedMounted extends RefChangeSystem { + @Nonnull + private final ComponentType mountedComponentType; + @Nonnull + private final ComponentType mountedByComponentType; + + public TrackedMounted( + @Nonnull ComponentType mountedComponentType, + @Nonnull ComponentType mountedByComponentType + ) { + this.mountedComponentType = mountedComponentType; + this.mountedByComponentType = mountedByComponentType; + } + + @Nonnull @Override public Query getQuery() { - return MountedComponent.getComponentType(); + return this.mountedComponentType; } @Nonnull @Override public ComponentType componentType() { - return MountedComponent.getComponentType(); + return this.mountedComponentType; } public void onComponentAdded( @@ -507,7 +706,7 @@ public class MountSystems { ) { Ref target = component.getMountedToEntity(); if (target != null && target.isValid()) { - MountedByComponent mountedBy = commandBuffer.ensureAndGetComponent(target, MountedByComponent.getComponentType()); + MountedByComponent mountedBy = commandBuffer.ensureAndGetComponent(target, this.mountedByComponentType); mountedBy.addPassenger(ref); } } @@ -532,15 +731,29 @@ public class MountSystems { } public static class TrackerRemove extends RefChangeSystem { + @Nonnull + private final ComponentType mountedComponentType; + @Nonnull + private final ComponentType visibleComponentType; + + public TrackerRemove( + @Nonnull ComponentType mountedComponentType, + @Nonnull ComponentType visibleComponentType + ) { + this.mountedComponentType = mountedComponentType; + this.visibleComponentType = visibleComponentType; + } + + @Nonnull @Override public Query getQuery() { - return EntityTrackerSystems.Visible.getComponentType(); + return this.visibleComponentType; } @Nonnull @Override public ComponentType componentType() { - return MountedComponent.getComponentType(); + return this.mountedComponentType; } public void onComponentAdded( @@ -570,7 +783,7 @@ public class MountSystems { AnimationUtils.stopAnimation(ref, AnimationSlot.Movement, true, commandBuffer); } - EntityTrackerSystems.Visible visibleComponent = store.getComponent(ref, EntityTrackerSystems.Visible.getComponentType()); + EntityTrackerSystems.Visible visibleComponent = store.getComponent(ref, this.visibleComponentType); assert visibleComponent != null; @@ -581,9 +794,21 @@ public class MountSystems { } public static class TrackerUpdate extends EntityTickingSystem { - private final ComponentType componentType = EntityTrackerSystems.Visible.getComponentType(); @Nonnull - private final Query query = Query.and(this.componentType, MountedComponent.getComponentType()); + private final ComponentType visibleComponentType; + @Nonnull + private final ComponentType mountedComponentType; + @Nonnull + private final Query query; + + public TrackerUpdate( + @Nonnull ComponentType visibleComponentType, + @Nonnull ComponentType mountedComponentType + ) { + this.visibleComponentType = visibleComponentType; + this.mountedComponentType = mountedComponentType; + this.query = Query.and(visibleComponentType, mountedComponentType); + } @Nullable @Override @@ -610,28 +835,37 @@ public class MountSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - EntityTrackerSystems.Visible visible = archetypeChunk.getComponent(index, this.componentType); - MountedComponent mounted = archetypeChunk.getComponent(index, MountedComponent.getComponentType()); + EntityTrackerSystems.Visible visibleComponent = archetypeChunk.getComponent(index, this.visibleComponentType); + + assert visibleComponent != null; + + MountedComponent mountedComponent = archetypeChunk.getComponent(index, this.mountedComponentType); + + assert mountedComponent != null; + Ref ref = archetypeChunk.getReferenceTo(index); - if (mounted.consumeNetworkOutdated()) { - queueUpdatesFor(ref, visible.visibleTo, mounted); - } else if (!visible.newlyVisibleTo.isEmpty()) { - queueUpdatesFor(ref, visible.newlyVisibleTo, mounted); + if (mountedComponent.consumeNetworkOutdated()) { + queueUpdatesFor(ref, visibleComponent.visibleTo, mountedComponent); + } else if (!visibleComponent.newlyVisibleTo.isEmpty()) { + queueUpdatesFor(ref, visibleComponent.newlyVisibleTo, mountedComponent); } } private static void queueUpdatesFor( @Nonnull Ref ref, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo, @Nonnull MountedComponent component ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Mounted; Ref mountedToEntity = component.getMountedToEntity(); Ref mountedToBlock = component.getMountedToBlock(); Vector3f offset = component.getAttachmentOffset(); 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) { @@ -660,10 +894,8 @@ public class MountSystems { mountedUpdate = new MountedUpdate(0, netOffset, component.getControllerType(), blockMount); } - update.mounted = mountedUpdate; - for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { - viewer.queueUpdate(ref, update); + viewer.queueUpdate(ref, mountedUpdate); } } } diff --git a/src/com/hypixel/hytale/builtin/mounts/NPCMountSystems.java b/src/com/hypixel/hytale/builtin/mounts/NPCMountSystems.java index 3d8ff16f..48c6e473 100644 --- a/src/com/hypixel/hytale/builtin/mounts/NPCMountSystems.java +++ b/src/com/hypixel/hytale/builtin/mounts/NPCMountSystems.java @@ -10,6 +10,7 @@ import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefSystem; import com.hypixel.hytale.protocol.packets.interaction.MountNPC; import com.hypixel.hytale.server.core.entity.entities.Player; +import com.hypixel.hytale.server.core.modules.entity.component.Interactable; 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.modules.entity.tracker.NetworkId; @@ -21,54 +22,86 @@ import javax.annotation.Nonnull; public class NPCMountSystems { public static class DismountOnMountDeath extends DeathSystems.OnDeathSystem { + @Nonnull + private final ComponentType npcMountComponentType; + + public DismountOnMountDeath(@Nonnull ComponentType npcMountComponentType) { + this.npcMountComponentType = npcMountComponentType; + } + + @Nonnull @Override public Query getQuery() { - return NPCMountComponent.getComponentType(); + return this.npcMountComponentType; } public void onComponentAdded( @Nonnull Ref ref, @Nonnull DeathComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - NPCMountComponent mountComponent = store.getComponent(ref, NPCMountComponent.getComponentType()); + NPCMountComponent mountComponent = store.getComponent(ref, this.npcMountComponentType); assert mountComponent != null; PlayerRef playerRef = mountComponent.getOwnerPlayerRef(); if (playerRef != null) { - MountPlugin.resetOriginalPlayerMovementSettings(playerRef, store); + Ref playerEntityRef = playerRef.getReference(); + if (playerEntityRef != null && playerEntityRef.isValid()) { + MountPlugin.resetOriginalPlayerMovementSettings(playerEntityRef, store); + } } } } public static class DismountOnPlayerDeath extends DeathSystems.OnDeathSystem { + @Nonnull + private final ComponentType playerComponentType; + + public DismountOnPlayerDeath(@Nonnull ComponentType playerComponentType) { + this.playerComponentType = playerComponentType; + } + @Nonnull @Override public Query getQuery() { - return Player.getComponentType(); + return this.playerComponentType; } public void onComponentAdded( @Nonnull Ref ref, @Nonnull DeathComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); + Player playerComponent = store.getComponent(ref, this.playerComponentType); assert playerComponent != null; - MountPlugin.checkDismountNpc(commandBuffer, playerComponent); + MountPlugin.checkDismountNpc(commandBuffer, ref, playerComponent); } } public static class OnAdd extends RefSystem { @Nonnull private final ComponentType mountComponentType; + @Nonnull + private final ComponentType npcEntityComponentType; + @Nonnull + private final ComponentType networkIdComponentType; + @Nonnull + private final Query query; - public OnAdd(@Nonnull ComponentType mountRoleChangeComponentType) { - this.mountComponentType = mountRoleChangeComponentType; + public OnAdd( + @Nonnull ComponentType mountComponentType, + @Nonnull ComponentType npcEntityComponentType, + @Nonnull ComponentType networkIdComponentType + ) { + this.mountComponentType = mountComponentType; + this.npcEntityComponentType = npcEntityComponentType; + this.networkIdComponentType = networkIdComponentType; + this.query = Query.and(mountComponentType, npcEntityComponentType, networkIdComponentType); } + @Nonnull @Override public Query getQuery() { - return this.mountComponentType; + return this.query; } @Override @@ -81,39 +114,40 @@ public class NPCMountSystems { PlayerRef playerRef = mountComponent.getOwnerPlayerRef(); if (playerRef == null) { - resetOriginalRoleMount(ref, store, commandBuffer, mountComponent); + this.resetOriginalRoleMount(ref, store, commandBuffer, mountComponent); } else { - NPCEntity npcComponent = store.getComponent(ref, NPCEntity.getComponentType()); + NPCEntity npcComponent = store.getComponent(ref, this.npcEntityComponentType); assert npcComponent != null; - NetworkId networkIdComponent = store.getComponent(ref, NetworkId.getComponentType()); + NetworkId networkIdComponent = store.getComponent(ref, this.networkIdComponentType); 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 (playerComponent != null) { + playerComponent.setMountEntityId(networkId); + playerRef.getPacketHandler().write(packet); + commandBuffer.removeComponent(ref, Interactable.getComponentType()); + } } } - private static void resetOriginalRoleMount( + private void resetOriginalRoleMount( @Nonnull Ref ref, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer, @Nonnull NPCMountComponent mountComponent ) { - NPCEntity npcComponent = store.getComponent(ref, NPCEntity.getComponentType()); + NPCEntity npcComponent = store.getComponent(ref, this.npcEntityComponentType); assert npcComponent != null; RoleChangeSystem.requestRoleChange(ref, npcComponent.getRole(), mountComponent.getOriginalRoleIndex(), false, "Idle", null, store); - commandBuffer.removeComponent(ref, NPCMountComponent.getComponentType()); + commandBuffer.removeComponent(ref, this.mountComponentType); + commandBuffer.ensureComponent(ref, Interactable.getComponentType()); } @Override @@ -122,4 +156,36 @@ public class NPCMountSystems { ) { } } + + public static class OnPlayerRemove extends RefSystem { + @Nonnull + private final ComponentType playerComponentType; + + public OnPlayerRemove(@Nonnull ComponentType playerComponentType) { + this.playerComponentType = playerComponentType; + } + + @Override + public void onEntityAdded( + @Nonnull Ref ref, @Nonnull AddReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { + } + + @Override + public void onEntityRemove( + @Nonnull Ref ref, @Nonnull RemoveReason reason, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { + Player player = commandBuffer.getComponent(ref, this.playerComponentType); + + assert player != null; + + MountPlugin.checkDismountNpc(commandBuffer, ref, player); + } + + @Nonnull + @Override + public Query getQuery() { + return this.playerComponentType; + } + } } diff --git a/src/com/hypixel/hytale/builtin/mounts/minecart/MinecartComponent.java b/src/com/hypixel/hytale/builtin/mounts/minecart/MinecartComponent.java index 818f55d6..0adccb73 100644 --- a/src/com/hypixel/hytale/builtin/mounts/minecart/MinecartComponent.java +++ b/src/com/hypixel/hytale/builtin/mounts/minecart/MinecartComponent.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.time.Instant; +import javax.annotation.Nullable; public class MinecartComponent implements Component { public static final BuilderCodec CODEC = BuilderCodec.builder(MinecartComponent.class, MinecartComponent::new) @@ -15,6 +16,7 @@ public class MinecartComponent implements Component { .add() .build(); private int numberOfHits = 0; + @Nullable private Instant lastHit; private String sourceItem = "Rail_Kart"; @@ -37,11 +39,12 @@ public class MinecartComponent implements Component { this.numberOfHits = numberOfHits; } + @Nullable public Instant getLastHit() { return this.lastHit; } - public void setLastHit(Instant lastHit) { + public void setLastHit(@Nullable Instant lastHit) { this.lastHit = lastHit; } diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/CombatActionEvaluatorSystems.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/CombatActionEvaluatorSystems.java index 65d03b6f..c96ad1f4 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/CombatActionEvaluatorSystems.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/CombatActionEvaluatorSystems.java @@ -50,6 +50,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CombatActionEvaluatorSystems { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static class CombatConstructionData implements Component { @@ -129,6 +130,7 @@ public class CombatActionEvaluatorSystems { @Nonnull private final ComponentType playerComponentType; private final ComponentType valueStoreComponentType; + @Nonnull private final ComponentType transformComponentType; private final Query query; @Nonnull @@ -362,7 +364,7 @@ public class CombatActionEvaluatorSystems { public static class OnAdded extends HolderSystem { @Nullable - private final ComponentType componentType = NPCEntity.getComponentType(); + private final ComponentType npcComponentType = NPCEntity.getComponentType(); private final ComponentType combatConstructionDataComponentType; @Nonnull private final Set> dependencies; @@ -377,8 +379,12 @@ public class CombatActionEvaluatorSystems { @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - Role role = holder.getComponent(this.componentType).getRole(); - if (role.getBalanceAsset() != null) { + NPCEntity npcComponent = holder.getComponent(this.npcComponentType); + + assert npcComponent != null; + + Role role = npcComponent.getRole(); + if (role != null && role.getBalanceAsset() != null) { BalanceAsset balancingAsset = BalanceAsset.getAssetMap().getAsset(role.getBalanceAsset()); if (balancingAsset instanceof CombatBalanceAsset combatBalance) { CombatActionEvaluatorSystems.CombatConstructionData constructionData = holder.getComponent(this.combatConstructionDataComponentType); diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/NPCCombatActionEvaluatorPlugin.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/NPCCombatActionEvaluatorPlugin.java index bda41a7f..1687d8c8 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/NPCCombatActionEvaluatorPlugin.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/NPCCombatActionEvaluatorPlugin.java @@ -30,9 +30,13 @@ import com.hypixel.hytale.server.npc.decisionmaker.core.conditions.base.Conditio import javax.annotation.Nonnull; public class NPCCombatActionEvaluatorPlugin extends JavaPlugin { + @Nonnull public static final String CAE_MARKED_TARGET_SLOT = "CAETargetSlot"; + @Nonnull public static final String CAE_MIN_RANGE_PARAMETER = "CAEMinRange"; + @Nonnull public static final String CAE_MAX_RANGE_PARAMETER = "CAEMaxRange"; + @Nonnull public static final String CAE_POSITIONING_ANGLE_PARAMETER = "CAEPositioningAngle"; private static NPCCombatActionEvaluatorPlugin instance; private ComponentType targetMemoryComponentType; diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/RecentSustainedDamageCondition.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/RecentSustainedDamageCondition.java index 01155ea7..58806210 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/RecentSustainedDamageCondition.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/RecentSustainedDamageCondition.java @@ -13,11 +13,13 @@ import com.hypixel.hytale.server.npc.decisionmaker.core.conditions.base.ScaledCu import javax.annotation.Nonnull; public class RecentSustainedDamageCondition extends ScaledCurveCondition { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( RecentSustainedDamageCondition.class, RecentSustainedDamageCondition::new, ScaledCurveCondition.ABSTRACT_CODEC ) .documentation("A scaled curve condition that returns a utility value based on damage taken since the combat action evaluator was last run.") .build(); + @Nonnull protected static final ComponentType DAMAGE_MEMORY_COMPONENT_TYPE = DamageMemory.getComponentType(); @Override @@ -28,8 +30,8 @@ public class RecentSustainedDamageCondition extends ScaledCurveCondition { CommandBuffer commandBuffer, EvaluationContext context ) { - DamageMemory memory = archetypeChunk.getComponent(selfIndex, DAMAGE_MEMORY_COMPONENT_TYPE); - return memory.getRecentDamage(); + DamageMemory damageMemoryComponent = archetypeChunk.getComponent(selfIndex, DAMAGE_MEMORY_COMPONENT_TYPE); + return damageMemoryComponent == null ? Double.MAX_VALUE : damageMemoryComponent.getRecentDamage(); } @Override diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/TargetMemoryCountCondition.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/TargetMemoryCountCondition.java index 11a244f4..bc984e0e 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/TargetMemoryCountCondition.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/TargetMemoryCountCondition.java @@ -14,10 +14,12 @@ import com.hypixel.hytale.server.npc.decisionmaker.core.conditions.base.ScaledCu import javax.annotation.Nonnull; public class TargetMemoryCountCondition extends ScaledCurveCondition { + @Nonnull public static final EnumCodec TARGET_TYPE_CODEC = new EnumCodec<>(TargetMemoryCountCondition.TargetType.class) .documentKey(TargetMemoryCountCondition.TargetType.All, "All known targets.") .documentKey(TargetMemoryCountCondition.TargetType.Friendly, "Known friendly targets.") .documentKey(TargetMemoryCountCondition.TargetType.Hostile, "Known hostile targets."); + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TargetMemoryCountCondition.class, TargetMemoryCountCondition::new, ScaledCurveCondition.ABSTRACT_CODEC ) @@ -31,6 +33,7 @@ public class TargetMemoryCountCondition extends ScaledCurveCondition { .documentation("The type of targets to count.") .add() .build(); + @Nonnull protected static final ComponentType TARGET_MEMORY_COMPONENT_TYPE = TargetMemory.getComponentType(); protected TargetMemoryCountCondition.TargetType targetType = TargetMemoryCountCondition.TargetType.Hostile; @@ -42,12 +45,14 @@ public class TargetMemoryCountCondition extends ScaledCurveCondition { CommandBuffer commandBuffer, EvaluationContext context ) { - TargetMemory memory = archetypeChunk.getComponent(selfIndex, TARGET_MEMORY_COMPONENT_TYPE); + TargetMemory targetMemoryComponent = archetypeChunk.getComponent(selfIndex, TARGET_MEMORY_COMPONENT_TYPE); + + assert targetMemoryComponent != null; return switch (this.targetType) { - case Hostile -> memory.getKnownHostiles().size(); - case Friendly -> memory.getKnownFriendlies().size(); - case All -> memory.getKnownFriendlies().size() + memory.getKnownHostiles().size(); + case Hostile -> targetMemoryComponent.getKnownHostiles().size(); + case Friendly -> targetMemoryComponent.getKnownFriendlies().size(); + case All -> targetMemoryComponent.getKnownFriendlies().size() + targetMemoryComponent.getKnownHostiles().size(); }; } diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/TotalSustainedDamageCondition.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/TotalSustainedDamageCondition.java index 4155b44f..ac4b1f8c 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/TotalSustainedDamageCondition.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/conditions/TotalSustainedDamageCondition.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.server.npc.decisionmaker.core.conditions.base.ScaledCu import javax.annotation.Nonnull; public class TotalSustainedDamageCondition extends ScaledCurveCondition { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( TotalSustainedDamageCondition.class, TotalSustainedDamageCondition::new, ScaledCurveCondition.ABSTRACT_CODEC ) @@ -28,8 +29,8 @@ public class TotalSustainedDamageCondition extends ScaledCurveCondition { CommandBuffer commandBuffer, EvaluationContext context ) { - DamageMemory memory = archetypeChunk.getComponent(selfIndex, DAMAGE_MEMORY_COMPONENT_TYPE); - return memory.getTotalCombatDamage(); + DamageMemory damageMemoryComponent = archetypeChunk.getComponent(selfIndex, DAMAGE_MEMORY_COMPONENT_TYPE); + return damageMemoryComponent == null ? Double.MAX_VALUE : damageMemoryComponent.getTotalCombatDamage(); } @Override diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/config/CombatBalanceAsset.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/config/CombatBalanceAsset.java index 4bd5e75f..2f0ba141 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/config/CombatBalanceAsset.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/config/CombatBalanceAsset.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.server.npc.config.balancing.BalanceAsset; import javax.annotation.Nonnull; public class CombatBalanceAsset extends BalanceAsset { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder(CombatBalanceAsset.class, CombatBalanceAsset::new, BASE_CODEC) .documentation("A balance asset which also configures a combat action evaluator.") .appendInherited( diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/ActionAddToTargetMemory.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/ActionAddToTargetMemory.java index a1c6503b..5a39b6fd 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/ActionAddToTargetMemory.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/ActionAddToTargetMemory.java @@ -8,12 +8,14 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.corecomponents.ActionBase; import com.hypixel.hytale.server.npc.role.Role; +import com.hypixel.hytale.server.npc.sensorinfo.IPositionProvider; import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ActionAddToTargetMemory extends ActionBase { + @Nonnull private static final ComponentType TARGET_MEMORY = TargetMemory.getComponentType(); public ActionAddToTargetMemory(@Nonnull BuilderActionAddToTargetMemory builder) { @@ -28,17 +30,26 @@ public class ActionAddToTargetMemory extends ActionBase { @Override public boolean execute(@Nonnull Ref ref, @Nonnull Role role, @Nonnull InfoProvider sensorInfo, double dt, @Nonnull Store store) { super.execute(ref, role, sensorInfo, dt, store); - TargetMemory targetMemory = ref.getStore().getComponent(ref, TARGET_MEMORY); - if (targetMemory == null) { + TargetMemory targetMemoryComponent = ref.getStore().getComponent(ref, TARGET_MEMORY); + if (targetMemoryComponent == null) { return true; } else { - Ref target = sensorInfo.getPositionProvider().getTarget(); - Int2FloatOpenHashMap hostiles = targetMemory.getKnownHostiles(); - if (hostiles.put(target.getIndex(), targetMemory.getRememberFor()) <= 0.0F) { - targetMemory.getKnownHostilesList().add(target); - } + IPositionProvider positionProvider = sensorInfo.getPositionProvider(); + if (positionProvider == null) { + return true; + } else { + Ref targetRef = positionProvider.getTarget(); + if (targetRef != null && targetRef.isValid()) { + Int2FloatOpenHashMap hostiles = targetMemoryComponent.getKnownHostiles(); + if (hostiles.put(targetRef.getIndex(), targetMemoryComponent.getRememberFor()) <= 0.0F) { + targetMemoryComponent.getKnownHostilesList().add(targetRef); + } - return true; + return true; + } else { + return true; + } + } } } } diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/ActionCombatAbility.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/ActionCombatAbility.java index 65319fc3..3b389b9c 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/ActionCombatAbility.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/ActionCombatAbility.java @@ -34,6 +34,7 @@ import javax.annotation.Nullable; public class ActionCombatAbility extends ActionBase { protected static final ComponentType COMPONENT_TYPE = CombatActionEvaluator.getComponentType(); + @Nonnull protected static final ComponentType TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType(); protected static final float POSITIONING_ANGLE_THRESHOLD = 0.08726646F; protected final int id; diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/CombatTargetCollector.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/CombatTargetCollector.java index 1d9f0471..8ec1d152 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/CombatTargetCollector.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/CombatTargetCollector.java @@ -18,6 +18,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class CombatTargetCollector implements ISensorEntityCollector { + @Nonnull private static final ComponentType TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType(); @Nullable private Role role; diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/SensorCombatActionEvaluator.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/SensorCombatActionEvaluator.java index 809687b0..be66a365 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/SensorCombatActionEvaluator.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/SensorCombatActionEvaluator.java @@ -20,6 +20,7 @@ import com.hypixel.hytale.server.npc.valuestore.ValueStore; import javax.annotation.Nonnull; public class SensorCombatActionEvaluator extends SensorBase { + @Nonnull protected static final ComponentType TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType(); protected final boolean targetInRange; protected final double allowableDeviation; @@ -33,7 +34,9 @@ public class SensorCombatActionEvaluator extends SensorBase { protected final SingleDoubleParameterProvider maxRangeParameterProvider; @Nonnull protected final SingleDoubleParameterProvider positioningAngleParameterProvider; + @Nonnull protected final MultipleParameterProvider parameterProvider = new MultipleParameterProvider(); + @Nonnull protected final EntityPositionProvider positionProvider = new EntityPositionProvider(this.parameterProvider); protected final ComponentType valueStoreComponentType; diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/builders/BuilderSensorCombatActionEvaluator.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/builders/BuilderSensorCombatActionEvaluator.java index 534331b2..db9e7783 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/builders/BuilderSensorCombatActionEvaluator.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/corecomponents/builders/BuilderSensorCombatActionEvaluator.java @@ -19,7 +19,9 @@ import java.util.function.ToIntFunction; import javax.annotation.Nonnull; public class BuilderSensorCombatActionEvaluator extends BuilderSensorBase { + @Nonnull protected final BooleanHolder targetInRange = new BooleanHolder(); + @Nonnull protected final DoubleHolder allowableDeviation = new DoubleHolder(); protected ToIntFunction minRangeStoreSlot; protected ToIntFunction maxRangeStoreSlot; diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/CombatActionEvaluator.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/CombatActionEvaluator.java index e80a9a10..28cc7556 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/CombatActionEvaluator.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/CombatActionEvaluator.java @@ -42,7 +42,9 @@ public class CombatActionEvaluator extends Evaluator impleme protected int runInState; protected float predictability; protected double minActionUtility; + @Nonnull protected final Int2ObjectMap.OptionHolder>> optionsBySubState = new Int2ObjectOpenHashMap<>(); + @Nonnull protected final Int2ObjectMap basicAttacksBySubState = new Int2ObjectOpenHashMap<>(); protected int currentBasicAttackSubState = Integer.MIN_VALUE; protected CombatActionEvaluatorConfig.BasicAttacks currentBasicAttackSet; @@ -77,6 +79,7 @@ public class CombatActionEvaluator extends Evaluator impleme protected boolean positionFirst; protected double chargeDistance; protected float timeout; + @Nonnull protected final EvaluationContext evaluationContext = new EvaluationContext(); public static ComponentType getComponentType() { @@ -356,13 +359,13 @@ public class CombatActionEvaluator extends Evaluator impleme index, archetypeChunk, commandBuffer, this.evaluationContext ); if (option != null) { - Ref target = option.getOptionTarget(); - if (target != null) { + Ref targetRef = option.getOptionTarget(); + if (targetRef != null && targetRef.isValid()) { if (((CombatActionOption)option.getOption()).getActionTarget() == CombatActionOption.Target.Friendly) { this.previousTarget = this.primaryTarget; } - this.primaryTarget = target; + this.primaryTarget = targetRef; role.getMarkedEntitySupport().setMarkedEntity(this.markedTargetSlot, this.primaryTarget); } @@ -377,7 +380,7 @@ public class CombatActionEvaluator extends Evaluator impleme public void completeCurrentAction(boolean forceClearAbility, boolean clearBasicAttack) { if (forceClearAbility || this.currentBasicAttack == null) { this.terminateCurrentAction(); - this.setLastRunNanos(System.nanoTime()); + this.lastRunNanos = System.nanoTime(); } if (clearBasicAttack) { @@ -486,6 +489,7 @@ public class CombatActionEvaluator extends Evaluator impleme public class MultipleTargetCombatOptionHolder extends CombatActionEvaluator.CombatOptionHolder { protected List> targets; + @Nonnull protected final DoubleList targetUtilities = new DoubleArrayList(); @Nullable protected Ref pickedTarget; diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/CombatActionEvaluatorConfig.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/CombatActionEvaluatorConfig.java index ab699d60..e26f6d55 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/CombatActionEvaluatorConfig.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/CombatActionEvaluatorConfig.java @@ -17,6 +17,7 @@ import java.util.Map; import javax.annotation.Nonnull; public class CombatActionEvaluatorConfig { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CombatActionEvaluatorConfig.class, CombatActionEvaluatorConfig::new ) @@ -79,6 +80,7 @@ public class CombatActionEvaluatorConfig { .documentation("A random range from which to pick the NPC's predictability factor.") .add() .build(); + @Nonnull private static final double[] DEFAULT_PREDICTABILITY_RANGE = new double[]{1.0, 1.0}; protected Map availableActions = Collections.emptyMap(); protected Map actionSets; @@ -130,6 +132,7 @@ public class CombatActionEvaluatorConfig { } public static class ActionSet { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CombatActionEvaluatorConfig.ActionSet.class, CombatActionEvaluatorConfig.ActionSet::new ) @@ -170,6 +173,7 @@ public class CombatActionEvaluatorConfig { } public static class BasicAttacks { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( CombatActionEvaluatorConfig.BasicAttacks.class, CombatActionEvaluatorConfig.BasicAttacks::new ) diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/AbilityCombatAction.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/AbilityCombatAction.java index 1148a945..ea2ee20e 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/AbilityCombatAction.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/AbilityCombatAction.java @@ -37,14 +37,17 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class AbilityCombatAction extends CombatActionOption { + @Nonnull public static final EnumCodec MODE_CODEC = new EnumCodec<>(AbilityCombatAction.AbilityType.class) .documentKey(AbilityCombatAction.AbilityType.Primary, "Use primary attack.") .documentKey(AbilityCombatAction.AbilityType.Secondary, "Use secondary attack."); + @Nonnull public static final EnumCodec POSITIONING_CODEC = new EnumCodec<>(Positioning.class) .documentKey(Positioning.Any, "Don't care about positioning.") .documentKey(Positioning.Front, "Try to be in front of the target.") .documentKey(Positioning.Behind, "Try to be behind the target.") .documentKey(Positioning.Flank, "Try to be on the target's flank."); + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( AbilityCombatAction.class, AbilityCombatAction::new, CombatActionOption.BASE_CODEC ) @@ -170,6 +173,7 @@ public class AbilityCombatAction extends CombatActionOption { .addValidator(Validators.greaterThanOrEqual(0.0)) .add() .build(); + @Nonnull protected static final ComponentType TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType(); protected String ability; protected AbilityCombatAction.AbilityType abilityType = AbilityCombatAction.AbilityType.Primary; diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/BasicAttackTargetCombatAction.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/BasicAttackTargetCombatAction.java index 958545f4..d723cf55 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/BasicAttackTargetCombatAction.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/BasicAttackTargetCombatAction.java @@ -19,6 +19,7 @@ import javax.annotation.Nonnull; public class BasicAttackTargetCombatAction extends CombatActionOption { private static final double BASIC_ATTACK_DISTANCE_OFFSET = 0.1; + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( BasicAttackTargetCombatAction.class, BasicAttackTargetCombatAction::new, Option.ABSTRACT_CODEC ) diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/CombatActionOption.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/CombatActionOption.java index 5dfa7929..9697510f 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/CombatActionOption.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/CombatActionOption.java @@ -27,9 +27,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class CombatActionOption extends Option implements JsonAssetWithMap> { + @Nonnull public static final AssetCodecMapCodec CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.extraData = data, t -> t.extraData ); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(CombatActionOption.class, Option.ABSTRACT_CODEC) .appendInherited( new KeyedCodec<>("Target", CombatActionOption.Target.CODEC), @@ -51,8 +53,11 @@ public abstract class CombatActionOption extends Option implements JsonAssetWith .documentation("An optional range the NPC will try to maintain from the target after executing the combat action.") .add() .build(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(CombatActionOption.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final ValidatorCache VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(CombatActionOption::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data extraData; @@ -60,6 +65,7 @@ public abstract class CombatActionOption extends Option implements JsonAssetWith protected CombatActionOption.Target actionTarget; protected double[] postExecuteDistanceRange; + @Nonnull public static AssetStore> getAssetStore() { if (ASSET_STORE == null) { ASSET_STORE = AssetRegistry.getAssetStore(CombatActionOption.class); @@ -161,6 +167,7 @@ public abstract class CombatActionOption extends Option implements JsonAssetWith Hostile, Friendly; + @Nonnull public static final EnumCodec CODEC = new EnumCodec<>(CombatActionOption.Target.class) .documentKey(Self, "Action targets self.") .documentKey(Hostile, "Action targets any hostile target.") diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/StateCombatAction.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/StateCombatAction.java index c78bb166..f984650b 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/StateCombatAction.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/evaluator/combatactions/StateCombatAction.java @@ -16,6 +16,7 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class StateCombatAction extends CombatActionOption { + @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( StateCombatAction.class, StateCombatAction::new, CombatActionOption.BASE_CODEC ) @@ -46,7 +47,7 @@ public class StateCombatAction extends CombatActionOption { public void execute( int index, @Nonnull ArchetypeChunk archetypeChunk, - CommandBuffer commandBuffer, + @Nonnull CommandBuffer commandBuffer, @Nonnull Role role, @Nonnull CombatActionEvaluator evaluator, ValueStore valueStore diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/memory/DamageMemorySystems.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/memory/DamageMemorySystems.java index a3775041..d3a069a3 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/memory/DamageMemorySystems.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/memory/DamageMemorySystems.java @@ -15,11 +15,12 @@ import javax.annotation.Nullable; public class DamageMemorySystems { public static class CollectDamage extends DamageEventSystem { + @Nonnull private final ComponentType damageMemoryComponentType; @Nonnull private final Query query; - public CollectDamage(ComponentType damageMemoryComponentType) { + public CollectDamage(@Nonnull ComponentType damageMemoryComponentType) { this.damageMemoryComponentType = damageMemoryComponentType; this.query = damageMemoryComponentType; } @@ -37,8 +38,11 @@ public class DamageMemorySystems { @Nonnull CommandBuffer commandBuffer, @Nonnull Damage damage ) { - DamageMemory memory = archetypeChunk.getComponent(index, this.damageMemoryComponentType); - memory.addDamage(damage.getAmount()); + DamageMemory damageMemoryComponent = archetypeChunk.getComponent(index, this.damageMemoryComponentType); + + assert damageMemoryComponent != null; + + damageMemoryComponent.addDamage(damage.getAmount()); } @Nullable diff --git a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/memory/TargetMemory.java b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/memory/TargetMemory.java index 1ec7f716..15eeced1 100644 --- a/src/com/hypixel/hytale/builtin/npccombatactionevaluator/memory/TargetMemory.java +++ b/src/com/hypixel/hytale/builtin/npccombatactionevaluator/memory/TargetMemory.java @@ -9,13 +9,19 @@ import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.List; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class TargetMemory implements Component { + @Nonnull private final Int2FloatOpenHashMap knownFriendlies = new Int2FloatOpenHashMap(); + @Nonnull private final List> knownFriendliesList = new ObjectArrayList<>(); + @Nonnull private final Int2FloatOpenHashMap knownHostiles = new Int2FloatOpenHashMap(); + @Nonnull private final List> knownHostilesList = new ObjectArrayList<>(); private final float rememberFor; + @Nullable private Ref closestHostile; public static ComponentType getComponentType() { @@ -52,11 +58,12 @@ public class TargetMemory implements Component { return this.rememberFor; } + @Nullable public Ref getClosestHostile() { return this.closestHostile; } - public void setClosestHostile(Ref ref) { + public void setClosestHostile(@Nullable Ref ref) { this.closestHostile = ref; } diff --git a/src/com/hypixel/hytale/builtin/path/path/PatrolPath.java b/src/com/hypixel/hytale/builtin/path/path/PatrolPath.java index 4106906a..fdc69ab8 100644 --- a/src/com/hypixel/hytale/builtin/path/path/PatrolPath.java +++ b/src/com/hypixel/hytale/builtin/path/path/PatrolPath.java @@ -83,7 +83,9 @@ public class PatrolPath implements IPrefabPath { for (int i = 0; i < index; i++) { PatrolPathMarkerEntity wp = (PatrolPathMarkerEntity)this.waypoints.get(i); - wp.markNeedsSave(); + if (wp != null) { + wp.markNeedsSave(); + } } this.pathChanged.set(true); @@ -94,13 +96,19 @@ public class PatrolPath implements IPrefabPath { public void registerNewWaypointAt(int index, @Nonnull IPrefabPathWaypoint waypoint, int worldGenId) { for (int i = 0; i < index; i++) { PatrolPathMarkerEntity wp = (PatrolPathMarkerEntity)this.waypoints.get(i); - wp.markNeedsSave(); + if (wp != null) { + wp.markNeedsSave(); + } } - for (int i = this.waypoints.size() - 1; i >= index; i--) { - PatrolPathMarkerEntity wp = (PatrolPathMarkerEntity)this.waypoints.remove(i); - wp.setOrder((short)(i + 1)); - this.waypoints.put(i + 1, wp); + for (int ix = this.waypoints.size() - 1; ix >= index; ix--) { + PatrolPathMarkerEntity wp = (PatrolPathMarkerEntity)this.waypoints.remove(ix); + if (wp == null) { + this.waypoints.remove(ix + 1); + } else { + wp.setOrder((short)(ix + 1)); + this.waypoints.put(ix + 1, wp); + } } this.length.getAndIncrement(); @@ -130,13 +138,19 @@ public class PatrolPath implements IPrefabPath { for (int i = 0; i < index; i++) { PatrolPathMarkerEntity wp = (PatrolPathMarkerEntity)this.waypoints.get(i); - wp.markNeedsSave(); + if (wp != null) { + wp.markNeedsSave(); + } } - for (int i = index; i < this.waypoints.size(); i++) { - PatrolPathMarkerEntity wp = (PatrolPathMarkerEntity)this.waypoints.remove(i + 1); - wp.setOrder(i); - this.waypoints.put(i, wp); + for (int ix = index; ix < this.waypoints.size(); ix++) { + PatrolPathMarkerEntity wp = (PatrolPathMarkerEntity)this.waypoints.remove(ix + 1); + if (wp == null) { + this.waypoints.remove(ix); + } else { + wp.setOrder(ix); + this.waypoints.put(ix, wp); + } } this.pathChanged.set(true); 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..1e2fc6cd 100644 --- a/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceSummonPage.java +++ b/src/com/hypixel/hytale/builtin/portals/ui/PortalDeviceSummonPage.java @@ -30,7 +30,6 @@ import com.hypixel.hytale.server.core.asset.type.item.config.Item; import com.hypixel.hytale.server.core.asset.type.item.config.PortalKey; import com.hypixel.hytale.server.core.asset.type.portalworld.PillTag; import com.hypixel.hytale.server.core.asset.type.portalworld.PortalDescription; -import com.hypixel.hytale.server.core.asset.type.portalworld.PortalSpawn; import com.hypixel.hytale.server.core.asset.type.portalworld.PortalType; import com.hypixel.hytale.server.core.asset.util.ColorParseUtil; import com.hypixel.hytale.server.core.entity.UUIDComponent; @@ -52,6 +51,8 @@ import com.hypixel.hytale.server.core.universe.world.spawn.ISpawnProvider; import com.hypixel.hytale.server.core.universe.world.spawn.IndividualSpawnProvider; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -63,10 +64,10 @@ import javax.annotation.Nullable; public class PortalDeviceSummonPage extends InteractiveCustomUIPage { private final PortalDeviceConfig config; private final Ref blockRef; + @Nullable private final ItemStack offeredItemStack; - 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 +147,7 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage pills = portalType.getDescription().getPillTags(); for (int i = 0; i < pills.size(); i++) { @@ -158,7 +159,7 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage spawnReturnPortal(World world, PortalWorld portalWorld, UUID sampleUuid, String portalBlockType) { - PortalSpawn portalSpawn = portalWorld.getPortalType().getPortalSpawn(); - return getSpawnTransform(world, sampleUuid, portalSpawn) + @Nonnull + private static CompletableFuture spawnReturnPortal( + @Nonnull World world, @Nonnull PortalWorld portalWorld, @Nonnull UUID sampleUuid, @Nonnull String portalBlockType + ) { + return getSpawnTransform(world, sampleUuid) .thenCompose( spawnTransform -> { Vector3d spawnPoint = spawnTransform.getPosition(); @@ -306,25 +311,30 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage getSpawnTransform(World world, UUID sampleUuid, @Nullable PortalSpawn portalSpawn) { + @Nonnull + private static CompletableFuture getSpawnTransform(@Nonnull World world, @Nonnull UUID sampleUuid) { + return CompletableFuture.supplyAsync(() -> { + List hintedSpawns = fetchHintedSpawns(world, sampleUuid); + return PortalSpawnFinder.computeSpawnTransform(world, hintedSpawns); + }, world); + } + + private static List fetchHintedSpawns(World world, UUID sampleUuid) { ISpawnProvider spawnProvider = world.getWorldConfig().getSpawnProvider(); if (spawnProvider == null) { - return CompletableFuture.completedFuture(null); + return Collections.emptyList(); } else { - Transform worldSpawnPoint = spawnProvider.getSpawnPoint(world, sampleUuid); - if (DEFAULT_WORLDGEN_SPAWN.equals(worldSpawnPoint) && portalSpawn != null) { - return CompletableFuture.supplyAsync(() -> { - Transform computedSpawn = PortalSpawnFinder.computeSpawnTransform(world, portalSpawn); - return computedSpawn == null ? worldSpawnPoint : computedSpawn; - }, world); + Transform[] spawnTransforms = spawnProvider.getSpawnPoints(); + if (spawnTransforms != null && spawnTransforms.length > 0) { + return Arrays.stream(spawnTransforms).map(Transform::getPosition).toList(); } else { - Transform uppedSpawnPoint = worldSpawnPoint.clone(); - uppedSpawnPoint.getPosition().add(0.0, 0.5, 0.0); - return CompletableFuture.completedFuture(uppedSpawnPoint); + Transform spawnPoint = spawnProvider.getSpawnPoint(world, sampleUuid); + return spawnPoint != null ? Collections.singletonList(spawnPoint.getPosition()) : Collections.emptyList(); } } } + @Nonnull private PortalDeviceSummonPage.State computeState(@Nonnull Player player, @Nonnull ComponentAccessor componentAccessor) { if (!this.blockRef.isValid()) { return PortalDeviceSummonPage.Error.INVALID_BLOCK; @@ -338,7 +348,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 +402,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..feb736b8 100644 --- a/src/com/hypixel/hytale/builtin/portals/ui/PortalSpawnFinder.java +++ b/src/com/hypixel/hytale/builtin/portals/ui/PortalSpawnFinder.java @@ -1,6 +1,5 @@ package com.hypixel.hytale.builtin.portals.ui; -import com.hypixel.hytale.builtin.portals.utils.posqueries.generators.SearchCircular; import com.hypixel.hytale.builtin.portals.utils.posqueries.predicates.FitsAPortal; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; @@ -10,10 +9,7 @@ import com.hypixel.hytale.math.util.ChunkUtil; 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.BlockMaterial; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; -import com.hypixel.hytale.server.core.asset.type.portalworld.PortalSpawn; import com.hypixel.hytale.server.core.modules.collision.WorldUtil; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk; @@ -21,22 +17,27 @@ 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 java.util.List; import java.util.concurrent.ThreadLocalRandom; -import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; public final class PortalSpawnFinder { + private static final int MAX_ATTEMPTS_PER_WORLD = 10; + private static final int QUALITY_ATTEMPTS = 2; + private static final int CHECKS_PER_CHUNK = 8; + private static final Vector3d FALLBACK_POSITION = Vector3d.ZERO; + @Nullable - public static Transform computeSpawnTransform(World world, PortalSpawn config) { - Vector3d spawn = findSpawnByThrowingDarts(world, config); + public static Transform computeSpawnTransform(@Nonnull World world, @Nonnull List hintedSpawns) { + Vector3d spawn = guesstimateFromHints(world, hintedSpawns); if (spawn == null) { - spawn = findFallbackPositionOnGround(world, config); - HytaleLogger.getLogger().at(Level.INFO).log("Had to use fallback spawn for portal spawn"); + spawn = findFallbackPositionOnGround(world); + HytaleLogger.getLogger().atWarning().log("Had to use fallback spawn for portal spawn (10 attempts)"); } if (spawn == null) { - HytaleLogger.getLogger().at(Level.INFO).log("Both dart and fallback spawn finder failed for portal spawn"); + HytaleLogger.getLogger().atWarning().log("Both dart and fallback spawn finder failed for portal spawn"); return null; } else { Vector3f direction = Vector3f.lookAt(spawn).scale(-1.0F); @@ -47,27 +48,17 @@ public final class PortalSpawnFinder { } @Nullable - private static Vector3d findSpawnByThrowingDarts(World world, PortalSpawn config) { - Vector3d center = config.getCenter().toVector3d(); - center.setY(config.getCheckSpawnY()); - int halfwayThrows = config.getChunkDartThrows() / 2; - - for (int chunkDart = 0; chunkDart < config.getChunkDartThrows(); chunkDart++) { - Vector3d pointd = new SearchCircular(config.getMinRadius(), config.getMaxRadius(), 1).execute(world, center).orElse(null); - if (pointd != null) { - Vector3i point = pointd.toVector3i(); - WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(point.x, point.z)); - BlockType firstBlock = chunk.getBlockType(point.x, point.y, point.z); - if (firstBlock != null) { - BlockMaterial firstBlockMat = firstBlock.getMaterial(); - if (firstBlockMat != BlockMaterial.Solid) { - boolean checkIfPortalFitsNice = chunkDart < halfwayThrows; - Vector3d spawn = findGroundWithinChunk(chunk, config, checkIfPortalFitsNice); - if (spawn != null) { - HytaleLogger.getLogger().at(Level.INFO).log("Found fragment spawn at " + spawn + " after " + (chunkDart + 1) + " chunk scan(s)"); - return spawn; - } - } + private static Vector3d guesstimateFromHints(World world, List hintedSpawns) { + for (int i = 0; i < Math.min(hintedSpawns.size(), 10); i++) { + Vector3d hintedSpawn = hintedSpawns.get(i); + WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(hintedSpawn.x, hintedSpawn.z)); + if (chunk != null) { + boolean quality = i < 2; + int scanHeight = quality ? (int)hintedSpawn.y : 319; + Vector3d spawn = findGroundWithinChunk(chunk, scanHeight, quality); + if (spawn != null) { + HytaleLogger.getLogger().atInfo().log("Found portal spawn " + spawn + " on attempt #" + (i + 1) + " quality=" + quality); + return spawn; } } } @@ -76,15 +67,15 @@ public final class PortalSpawnFinder { } @Nullable - private static Vector3d findGroundWithinChunk(WorldChunk chunk, PortalSpawn config, boolean checkIfPortalFitsNice) { + private static Vector3d findGroundWithinChunk(@Nonnull WorldChunk chunk, int scanHeight, 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); - Vector3d point = findWithGroundBelow(chunk, x, config.getCheckSpawnY(), z, config.getScanHeight(), false); + for (int i = 0; i < 8; i++) { + int x = chunkBlockX + random.nextInt(2, 14); + int z = chunkBlockZ + random.nextInt(2, 14); + Vector3d point = findWithGroundBelow(chunk, x, scanHeight, z, scanHeight, false); if (point != null && (!checkIfPortalFitsNice || FitsAPortal.check(chunk.getWorld(), point))) { return point; } @@ -94,30 +85,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 +151,11 @@ public final class PortalSpawnFinder { } @Nullable - private static Vector3d findFallbackPositionOnGround(World world, PortalSpawn config) { - Vector3i center = config.getCenter(); - WorldChunk centerChunk = world.getChunk(ChunkUtil.indexChunkFromBlock(center.x, center.z)); - return findWithGroundBelow(centerChunk, 0, 319, 0, 319, true); + private static Vector3d findFallbackPositionOnGround(@Nonnull World world) { + Vector3d center = FALLBACK_POSITION.clone(); + 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/randomtick/RandomTick.java b/src/com/hypixel/hytale/builtin/randomtick/RandomTick.java new file mode 100644 index 00000000..90cc31a7 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/randomtick/RandomTick.java @@ -0,0 +1,35 @@ +package com.hypixel.hytale.builtin.randomtick; + +import com.hypixel.hytale.component.Resource; +import com.hypixel.hytale.component.ResourceType; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import java.util.Random; +import javax.annotation.Nullable; + +public class RandomTick implements Resource { + private int blocksPerSectionPerTickStable = 1; + private int blocksPerSectionPerTickUnstable = 3; + private Random random = new Random(); + + public static ResourceType getResourceType() { + return RandomTickPlugin.get().getRandomTickResourceType(); + } + + public int getBlocksPerSectionPerTickStable() { + return this.blocksPerSectionPerTickStable; + } + + public int getBlocksPerSectionPerTickUnstable() { + return this.blocksPerSectionPerTickUnstable; + } + + public Random getRandom() { + return this.random; + } + + @Nullable + @Override + public Resource clone() { + return new RandomTick(); + } +} diff --git a/src/com/hypixel/hytale/builtin/randomtick/RandomTickPlugin.java b/src/com/hypixel/hytale/builtin/randomtick/RandomTickPlugin.java new file mode 100644 index 00000000..3c4266dd --- /dev/null +++ b/src/com/hypixel/hytale/builtin/randomtick/RandomTickPlugin.java @@ -0,0 +1,36 @@ +package com.hypixel.hytale.builtin.randomtick; + +import com.hypixel.hytale.builtin.randomtick.procedures.ChangeIntoBlockProcedure; +import com.hypixel.hytale.builtin.randomtick.procedures.SpreadToProcedure; +import com.hypixel.hytale.component.ResourceType; +import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure; +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.ChunkStore; +import javax.annotation.Nonnull; + +public class RandomTickPlugin extends JavaPlugin { + private static RandomTickPlugin INSTANCE; + private ResourceType randomTickResourceType; + + public static RandomTickPlugin get() { + return INSTANCE; + } + + public RandomTickPlugin(@Nonnull JavaPluginInit init) { + super(init); + INSTANCE = this; + } + + @Override + protected void setup() { + this.randomTickResourceType = this.getChunkStoreRegistry().registerResource(RandomTick.class, RandomTick::new); + this.getChunkStoreRegistry().registerSystem(new RandomTickSystem()); + RandomTickProcedure.CODEC.register("ChangeIntoBlock", ChangeIntoBlockProcedure.class, ChangeIntoBlockProcedure.CODEC); + RandomTickProcedure.CODEC.register("SpreadTo", SpreadToProcedure.class, SpreadToProcedure.CODEC); + } + + public ResourceType getRandomTickResourceType() { + return this.randomTickResourceType; + } +} diff --git a/src/com/hypixel/hytale/builtin/randomtick/RandomTickSystem.java b/src/com/hypixel/hytale/builtin/randomtick/RandomTickSystem.java new file mode 100644 index 00000000..7adc4a26 --- /dev/null +++ b/src/com/hypixel/hytale/builtin/randomtick/RandomTickSystem.java @@ -0,0 +1,114 @@ +package com.hypixel.hytale.builtin.randomtick; + +import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap; +import com.hypixel.hytale.component.ArchetypeChunk; +import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.ComponentType; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.component.query.Query; +import com.hypixel.hytale.component.system.tick.EntityTickingSystem; +import com.hypixel.hytale.math.util.ChunkUtil; +import com.hypixel.hytale.math.util.HashUtil; +import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +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.ChunkSection; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import java.util.Random; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class RandomTickSystem extends EntityTickingSystem { + private final ComponentType blockSelectionComponentType = BlockSection.getComponentType(); + private final ComponentType chunkSectionComponentType = ChunkSection.getComponentType(); + private final Query query = Query.and(this.blockSelectionComponentType, this.chunkSectionComponentType); + + @Override + public void tick( + float dt, + int index, + @Nonnull ArchetypeChunk archetypeChunk, + @Nonnull Store store, + @Nonnull CommandBuffer commandBuffer + ) { + BlockSection blockSection = archetypeChunk.getComponent(index, this.blockSelectionComponentType); + + assert blockSection != null; + + if (!blockSection.isSolidAir()) { + ChunkSection chunkSection = archetypeChunk.getComponent(index, this.chunkSectionComponentType); + + assert chunkSection != null; + + RandomTick config = commandBuffer.getResource(RandomTick.getResourceType()); + World world = store.getExternalData().getWorld(); + int interval = 32768 / config.getBlocksPerSectionPerTickStable(); + long baseSeed = HashUtil.hash(world.getTick() / interval, chunkSection.getX(), chunkSection.getY(), chunkSection.getZ()); + long randomSeed = (baseSeed << 1 | 1L) & 32767L; + long randomSeed2 = baseSeed >> 16 & 32767L; + long startIndex = world.getTick() % interval * config.getBlocksPerSectionPerTickStable(); + BlockTypeAssetMap assetMap = BlockType.getAssetMap(); + + for (int i = 0; i < config.getBlocksPerSectionPerTickStable(); i++) { + int blockIndex = (int)((startIndex + i) * randomSeed + randomSeed2 & 32767L); + int localX = ChunkUtil.xFromIndex(blockIndex); + int localY = ChunkUtil.yFromIndex(blockIndex); + int localZ = ChunkUtil.zFromIndex(blockIndex); + int blockId = blockSection.get(blockIndex); + if (blockId != 0) { + BlockType blockType = assetMap.getAsset(blockId); + if (blockType != null) { + RandomTickProcedure randomTickProcedure = blockType.getRandomTickProcedure(); + if (randomTickProcedure != null) { + randomTickProcedure.onRandomTick( + store, + commandBuffer, + blockSection, + ChunkUtil.worldCoordFromLocalCoord(chunkSection.getX(), localX), + ChunkUtil.worldCoordFromLocalCoord(chunkSection.getY(), localY), + ChunkUtil.worldCoordFromLocalCoord(chunkSection.getZ(), localZ), + blockId, + blockType + ); + } + } + } + } + + Random rng = config.getRandom(); + + for (int ix = 0; ix < config.getBlocksPerSectionPerTickUnstable(); ix++) { + int blockIndex = rng.nextInt(32768); + int localX = ChunkUtil.xFromIndex(blockIndex); + int localY = ChunkUtil.yFromIndex(blockIndex); + int localZ = ChunkUtil.zFromIndex(blockIndex); + int blockId = blockSection.get(blockIndex); + if (blockId != 0) { + BlockType blockType = assetMap.getAsset(blockId); + if (blockType != null) { + RandomTickProcedure randomTickProcedure = blockType.getRandomTickProcedure(); + if (randomTickProcedure != null) { + randomTickProcedure.onRandomTick( + store, + commandBuffer, + blockSection, + ChunkUtil.worldCoordFromLocalCoord(chunkSection.getX(), localX), + ChunkUtil.worldCoordFromLocalCoord(chunkSection.getY(), localY), + ChunkUtil.worldCoordFromLocalCoord(chunkSection.getZ(), localZ), + blockId, + blockType + ); + } + } + } + } + } + } + + @Nullable + @Override + public Query getQuery() { + return this.query; + } +} diff --git a/src/com/hypixel/hytale/builtin/randomtick/procedures/ChangeIntoBlockProcedure.java b/src/com/hypixel/hytale/builtin/randomtick/procedures/ChangeIntoBlockProcedure.java new file mode 100644 index 00000000..43bd817f --- /dev/null +++ b/src/com/hypixel/hytale/builtin/randomtick/procedures/ChangeIntoBlockProcedure.java @@ -0,0 +1,38 @@ +package com.hypixel.hytale.builtin.randomtick.procedures; + +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.math.util.ChunkUtil; +import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; + +public class ChangeIntoBlockProcedure implements RandomTickProcedure { + public static final BuilderCodec CODEC = BuilderCodec.builder(ChangeIntoBlockProcedure.class, ChangeIntoBlockProcedure::new) + .appendInherited(new KeyedCodec<>("TargetBlock", Codec.STRING), (o, i) -> o.targetBlock = i, o -> o.targetBlock, (o, p) -> o.targetBlock = p.targetBlock) + .addValidatorLate(() -> BlockType.VALIDATOR_CACHE.getValidator().late()) + .add() + .build(); + private String targetBlock; + + @Override + public void onRandomTick( + Store store, + CommandBuffer commandBuffer, + BlockSection blockSection, + int worldX, + int worldY, + int worldZ, + int blockId, + BlockType blockType + ) { + int targetBlockId = BlockType.getAssetMap().getIndex(this.targetBlock); + if (targetBlockId != Integer.MIN_VALUE) { + blockSection.set(ChunkUtil.indexBlock(worldX, worldY, worldZ), targetBlockId, 0, 0); + } + } +} diff --git a/src/com/hypixel/hytale/builtin/randomtick/procedures/SpreadToProcedure.java b/src/com/hypixel/hytale/builtin/randomtick/procedures/SpreadToProcedure.java new file mode 100644 index 00000000..a2e1724a --- /dev/null +++ b/src/com/hypixel/hytale/builtin/randomtick/procedures/SpreadToProcedure.java @@ -0,0 +1,197 @@ +package com.hypixel.hytale.builtin.randomtick.procedures; + +import com.hypixel.hytale.assetstore.AssetRegistry; +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.component.CommandBuffer; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.math.util.ChunkUtil; +import com.hypixel.hytale.math.vector.Vector3i; +import com.hypixel.hytale.protocol.BlockMaterial; +import com.hypixel.hytale.protocol.DrawType; +import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +import com.hypixel.hytale.server.core.modules.time.WorldTimeResource; +import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import it.unimi.dsi.fastutil.ints.IntSet; + +public class SpreadToProcedure implements RandomTickProcedure { + public static final BuilderCodec CODEC = BuilderCodec.builder(SpreadToProcedure.class, SpreadToProcedure::new) + .appendInherited( + new KeyedCodec<>("SpreadDirections", new ArrayCodec<>(Vector3i.CODEC, Vector3i[]::new)), + (o, i) -> o.spreadDirections = i, + o -> o.spreadDirections, + (o, p) -> o.spreadDirections = p.spreadDirections + ) + .documentation("The directions this block can spread in.") + .addValidator(Validators.nonNull()) + .add() + .appendInherited(new KeyedCodec<>("MinY", Codec.INTEGER), (o, i) -> o.minY = i, o -> o.minY, (o, p) -> o.minY = p.minY) + .documentation( + "The minimum Y level this block can spread to, relative to the current block. For example, a value of -1 means the block can spread to blocks one level below it." + ) + .add() + .appendInherited(new KeyedCodec<>("MaxY", Codec.INTEGER), (o, i) -> o.maxY = i, o -> o.maxY, (o, p) -> o.maxY = p.maxY) + .documentation( + "The maximum Y level this block can spread to, relative to the current block. For example, a value of 1 means the block can spread to blocks one level above it." + ) + .add() + .appendInherited(new KeyedCodec<>("AllowedTag", Codec.STRING), (o, i) -> { + o.allowedTag = i; + o.allowedTagIndex = AssetRegistry.getOrCreateTagIndex(i); + }, o -> o.allowedTag, (o, p) -> { + o.allowedTag = p.allowedTag; + o.allowedTagIndex = p.allowedTagIndex; + }) + .documentation("The asset tag that the block can spread to.") + .addValidator(Validators.nonNull()) + .add() + .appendInherited( + new KeyedCodec<>("RequireEmptyAboveTarget", Codec.BOOLEAN), + (o, i) -> o.requireEmptyAboveTarget = i, + o -> o.requireEmptyAboveTarget, + (o, p) -> o.requireEmptyAboveTarget = p.requireEmptyAboveTarget + ) + .documentation("Whether the block requires an empty block above the target block to spread.") + .add() + .appendInherited( + new KeyedCodec<>("RequiredLightLevel", Codec.INTEGER), + (o, i) -> o.requiredLightLevel = i, + o -> o.requiredLightLevel, + (o, p) -> o.requiredLightLevel = p.requiredLightLevel + ) + .documentation("The minimum light level required for the block to spread.") + .addValidator(Validators.range(0, 15)) + .add() + .appendInherited( + new KeyedCodec<>("RevertBlock", Codec.STRING), (o, i) -> o.revertBlock = i, o -> o.revertBlock, (o, p) -> o.revertBlock = p.revertBlock + ) + .documentation("If specified, the block will revert to this block if it is covered by another block.") + .addValidatorLate(() -> BlockType.VALIDATOR_CACHE.getValidator().late()) + .add() + .build(); + private Vector3i[] spreadDirections; + private int minY = 0; + private int maxY = 0; + private String allowedTag; + private int allowedTagIndex = Integer.MIN_VALUE; + private boolean requireEmptyAboveTarget = true; + private int requiredLightLevel = 6; + private String revertBlock; + + @Override + public void onRandomTick( + Store store, + CommandBuffer commandBuffer, + BlockSection blockSection, + int worldX, + int worldY, + int worldZ, + int blockId, + BlockType blockType + ) { + IntSet validSpreadTargets = BlockType.getAssetMap().getIndexesForTag(this.allowedTagIndex); + WorldTimeResource worldTimeResource = commandBuffer.getExternalData() + .getWorld() + .getEntityStore() + .getStore() + .getResource(WorldTimeResource.getResourceType()); + double sunlightFactor = worldTimeResource.getSunlightFactor(); + BlockSection aboveSection = blockSection; + if (!ChunkUtil.isSameChunkSection(worldX, worldY, worldZ, worldX, worldY + 1, worldZ)) { + Ref aboveChunk = store.getExternalData() + .getChunkSectionReference( + commandBuffer, ChunkUtil.chunkCoordinate(worldX), ChunkUtil.chunkCoordinate(worldY + 1), ChunkUtil.chunkCoordinate(worldZ) + ); + if (aboveChunk == null) { + return; + } + + BlockSection aboveBlockSection = commandBuffer.getComponent(aboveChunk, BlockSection.getComponentType()); + if (aboveBlockSection == null) { + return; + } + + aboveSection = aboveBlockSection; + } + + int aboveIndex = ChunkUtil.indexBlock(worldX, worldY + 1, worldZ); + if (this.revertBlock != null) { + int blockAtAboveId = aboveSection.get(aboveIndex); + BlockType blockAtAbove = BlockType.getAssetMap().getAsset(blockAtAboveId); + if (blockAtAbove != null && (blockAtAbove.getDrawType() == DrawType.Cube || blockAtAbove.getDrawType() == DrawType.CubeWithModel)) { + int revert = BlockType.getAssetMap().getIndex(this.revertBlock); + if (revert != Integer.MIN_VALUE) { + blockSection.set(worldX, worldY, worldZ, revert, 0, 0); + return; + } + } + } + + int skyLight = (int)(aboveSection.getLocalLight().getSkyLight(aboveIndex) * sunlightFactor); + int blockLevel = aboveSection.getLocalLight().getBlockLightIntensity(aboveIndex); + int lightLevel = Math.max(skyLight, blockLevel); + if (lightLevel >= this.requiredLightLevel) { + for (int y = this.minY; y <= this.maxY; y++) { + for (Vector3i direction : this.spreadDirections) { + int targetX = worldX + direction.x; + int targetY = worldY + direction.y + y; + int targetZ = worldZ + direction.z; + BlockSection targetBlockSection = blockSection; + if (!ChunkUtil.isSameChunkSection(worldX, worldY, worldZ, targetX, targetY, targetZ)) { + Ref otherChunk = store.getExternalData() + .getChunkSectionReference( + commandBuffer, ChunkUtil.chunkCoordinate(targetX), ChunkUtil.chunkCoordinate(targetY), ChunkUtil.chunkCoordinate(targetZ) + ); + if (otherChunk == null) { + continue; + } + + targetBlockSection = commandBuffer.getComponent(otherChunk, BlockSection.getComponentType()); + if (targetBlockSection == null) { + continue; + } + } + + int targetIndex = ChunkUtil.indexBlock(targetX, targetY, targetZ); + int targetBlockId = targetBlockSection.get(targetIndex); + if (validSpreadTargets.contains(targetBlockId)) { + if (this.requireEmptyAboveTarget) { + int aboveTargetBlockId; + if (ChunkUtil.isSameChunkSection(targetX, targetY, targetZ, targetX, targetY + 1, targetZ)) { + aboveTargetBlockId = targetBlockSection.get(ChunkUtil.indexBlock(targetX, targetY + 1, targetZ)); + } else { + Ref aboveChunkx = store.getExternalData() + .getChunkSectionReference( + commandBuffer, ChunkUtil.chunkCoordinate(targetX), ChunkUtil.chunkCoordinate(targetY + 1), ChunkUtil.chunkCoordinate(targetZ) + ); + if (aboveChunkx == null) { + continue; + } + + BlockSection aboveBlockSection = commandBuffer.getComponent(aboveChunkx, BlockSection.getComponentType()); + if (aboveBlockSection == null) { + continue; + } + + aboveTargetBlockId = aboveBlockSection.get(ChunkUtil.indexBlock(targetX, targetY + 1, targetZ)); + } + + BlockType aboveBlockType = BlockType.getAssetMap().getAsset(aboveTargetBlockId); + if (aboveBlockType == null || aboveBlockType.getMaterial() != BlockMaterial.Empty) { + continue; + } + } + + targetBlockSection.set(targetIndex, blockId, 0, 0); + } + } + } + } + } +} 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/teleport/commands/teleport/variant/TeleportOtherToPlayerCommand.java b/src/com/hypixel/hytale/builtin/teleport/commands/teleport/variant/TeleportOtherToPlayerCommand.java index 608a13f9..1a0143eb 100644 --- a/src/com/hypixel/hytale/builtin/teleport/commands/teleport/variant/TeleportOtherToPlayerCommand.java +++ b/src/com/hypixel/hytale/builtin/teleport/commands/teleport/variant/TeleportOtherToPlayerCommand.java @@ -51,57 +51,69 @@ public class TeleportOtherToPlayerCommand extends CommandBase { World targetWorld = targetStore.getExternalData().getWorld(); sourceWorld.execute( () -> { - TransformComponent transformComponent = sourceStore.getComponent(sourceRef, TransformComponent.getComponentType()); + if (!sourceRef.isValid()) { + context.sendMessage(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_IN_WORLD); + } else if (!targetRef.isValid()) { + context.sendMessage(MESSAGE_COMMANDS_ERRORS_TARGET_NOT_IN_WORLD); + } else { + TransformComponent transformComponent = sourceStore.getComponent(sourceRef, TransformComponent.getComponentType()); - assert transformComponent != null; + assert transformComponent != null; - HeadRotation headRotationComponent = sourceStore.getComponent(sourceRef, HeadRotation.getComponentType()); + HeadRotation headRotationComponent = sourceStore.getComponent(sourceRef, HeadRotation.getComponentType()); - assert headRotationComponent != null; + assert headRotationComponent != null; - Vector3d pos = transformComponent.getPosition().clone(); - Vector3f rotation = headRotationComponent.getRotation().clone(); - targetWorld.execute( - () -> { - TransformComponent targetTransformComponent = targetStore.getComponent(targetRef, TransformComponent.getComponentType()); + Vector3d pos = transformComponent.getPosition().clone(); + Vector3f rotation = headRotationComponent.getRotation().clone(); + targetWorld.execute( + () -> { + TransformComponent targetTransformComponent = targetStore.getComponent(targetRef, TransformComponent.getComponentType()); - assert targetTransformComponent != null; + assert targetTransformComponent != null; - HeadRotation targetHeadRotationComponent = targetStore.getComponent(targetRef, HeadRotation.getComponentType()); + HeadRotation targetHeadRotationComponent = targetStore.getComponent(targetRef, HeadRotation.getComponentType()); - assert targetHeadRotationComponent != null; + assert targetHeadRotationComponent != null; - Vector3d targetPosition = targetTransformComponent.getPosition().clone(); - Vector3f targetHeadRotation = targetHeadRotationComponent.getRotation().clone(); - Transform targetTransform = new Transform(targetPosition, targetHeadRotation); - sourceWorld.execute( - () -> { - Teleport teleportComponent = Teleport.createForPlayer(targetWorld, targetTransform); - sourceStore.addComponent(sourceRef, Teleport.getComponentType(), teleportComponent); - PlayerRef sourcePlayerRefComponent = sourceStore.getComponent(sourceRef, PlayerRef.getComponentType()); + Vector3d targetPosition = targetTransformComponent.getPosition().clone(); + Vector3f targetHeadRotation = targetHeadRotationComponent.getRotation().clone(); + Transform targetTransform = new Transform(targetPosition, targetHeadRotation); + sourceWorld.execute( + () -> { + if (!sourceRef.isValid()) { + context.sendMessage(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_IN_WORLD); + } else if (!targetRef.isValid()) { + context.sendMessage(MESSAGE_COMMANDS_ERRORS_TARGET_NOT_IN_WORLD); + } else { + Teleport teleportComponent = Teleport.createForPlayer(targetWorld, targetTransform); + sourceStore.addComponent(sourceRef, Teleport.getComponentType(), teleportComponent); + PlayerRef sourcePlayerRefComponent = sourceStore.getComponent(sourceRef, PlayerRef.getComponentType()); - assert sourcePlayerRefComponent != null; + assert sourcePlayerRefComponent != null; - PlayerRef targetPlayerRefComponent = targetStore.getComponent(targetRef, PlayerRef.getComponentType()); + PlayerRef targetPlayerRefComponent = targetStore.getComponent(targetRef, PlayerRef.getComponentType()); - assert targetPlayerRefComponent != null; + assert targetPlayerRefComponent != null; - context.sendMessage( - Message.translation("server.commands.teleport.teleportedOtherToPlayer") - .param("targetName", sourcePlayerRefComponent.getUsername()) - .param("toName", targetPlayerRefComponent.getUsername()) - ); - sourceStore.ensureAndGetComponent(sourceRef, TeleportHistory.getComponentType()) - .append( - sourceWorld, - pos, - rotation, - "Teleport to " + targetPlayerRefComponent.getUsername() + " by " + context.sender().getDisplayName() - ); - } - ); - } - ); + context.sendMessage( + Message.translation("server.commands.teleport.teleportedOtherToPlayer") + .param("targetName", sourcePlayerRefComponent.getUsername()) + .param("toName", targetPlayerRefComponent.getUsername()) + ); + sourceStore.ensureAndGetComponent(sourceRef, TeleportHistory.getComponentType()) + .append( + sourceWorld, + pos, + rotation, + "Teleport to " + targetPlayerRefComponent.getUsername() + " by " + context.sender().getDisplayName() + ); + } + } + ); + } + ); + } } ); } else { diff --git a/src/com/hypixel/hytale/builtin/worldgen/WorldGenPlugin.java b/src/com/hypixel/hytale/builtin/worldgen/WorldGenPlugin.java index 956507f3..4fae40a9 100644 --- a/src/com/hypixel/hytale/builtin/worldgen/WorldGenPlugin.java +++ b/src/com/hypixel/hytale/builtin/worldgen/WorldGenPlugin.java @@ -1,14 +1,39 @@ 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.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; public static WorldGenPlugin get() { @@ -24,5 +49,162 @@ public class WorldGenPlugin extends JavaPlugin { instance = this; this.getEntityStoreRegistry().registerSystem(new BiomeDataSystem()); IWorldGenProvider.CODEC.register(Priority.DEFAULT.before(1), "Hytale", HytaleWorldGenProvider.class, HytaleWorldGenProvider.CODEC); + AssetModule assets = AssetModule.get(); + if (assets.getAssetPacks().isEmpty()) { + this.getLogger().at(Level.SEVERE).log("No asset packs loaded"); + } else { + FileIO.setDefaultRoot(assets.getBaseAssetPack().getRoot()); + List packs = loadVersionPacks(assets); + Object2ObjectOpenHashMap versions = new Object2ObjectOpenHashMap<>(); + + for (WorldGenPlugin.Version version : packs) { + validateVersion(version, packs); + assets.registerPack(version.getPackName(), version.path, version.manifest, false); + Semver latest = versions.get(version.name); + if (latest == null || version.manifest.getVersion().compareTo(latest) > 0) { + versions.put(version.name, version.manifest.getVersion()); + } + } + + HytaleWorldGenProvider.CODEC.setVersions(versions); + } + } + + 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/codec/builder/BuilderCodec.java b/src/com/hypixel/hytale/codec/builder/BuilderCodec.java index 66f75ea1..a3da8812 100644 --- a/src/com/hypixel/hytale/codec/builder/BuilderCodec.java +++ b/src/com/hypixel/hytale/codec/builder/BuilderCodec.java @@ -262,15 +262,16 @@ public class BuilderCodec implements Codec, DirectDecodeCodec, RawJsonC @Override public void decode(@Nonnull BsonValue bsonValue, T t, @Nonnull ExtraInfo extraInfo) { - this.decode0(bsonValue.asDocument(), t, extraInfo); - this.afterDecodeAndValidate(t, extraInfo); - } - - protected void decode0(@Nonnull BsonDocument document, T t, ExtraInfo extraInfo) { + BsonDocument document = bsonValue.asDocument(); if (this.versioned) { extraInfo = this.decodeVersion(document, extraInfo); } + this.decode0(document, t, extraInfo); + this.afterDecodeAndValidate(t, extraInfo); + } + + protected void decode0(@Nonnull BsonDocument document, T t, ExtraInfo extraInfo) { for (Entry entry : document.entrySet()) { String key = entry.getKey(); BuilderField field = findEntry(this, key, extraInfo); @@ -304,17 +305,17 @@ public class BuilderCodec implements Codec, DirectDecodeCodec, RawJsonC throw new CodecException("This BuilderCodec is for an abstract or direct codec. To use this codec you must specify an existing object to decode into."); } else { T t = this.supplier.get(); + if (this.versioned) { + extraInfo = this.decodeVersion(reader, extraInfo); + } + this.decodeJson0(reader, t, extraInfo); this.afterDecodeAndValidate(t, extraInfo); return t; } } - public void decodeJson0(@Nonnull RawJsonReader reader, T t, ExtraInfo extraInfo) throws IOException { - if (this.versioned) { - extraInfo = this.decodeVersion(reader, extraInfo); - } - + private void decodeJson0(@Nonnull RawJsonReader reader, T t, ExtraInfo extraInfo) throws IOException { reader.expect('{'); reader.consumeWhiteSpace(); if (!reader.tryConsume('}')) { @@ -409,6 +410,10 @@ public class BuilderCodec implements Codec, DirectDecodeCodec, RawJsonC } public void decodeJson(@Nonnull RawJsonReader reader, T t, @Nonnull ExtraInfo extraInfo) throws IOException { + if (this.versioned) { + extraInfo = this.decodeVersion(reader, extraInfo); + } + this.decodeJson0(reader, t, extraInfo); this.afterDecodeAndValidate(t, extraInfo); } diff --git a/src/com/hypixel/hytale/common/plugin/PluginIdentifier.java b/src/com/hypixel/hytale/common/plugin/PluginIdentifier.java index 3b1fbbda..4e8a1851 100644 --- a/src/com/hypixel/hytale/common/plugin/PluginIdentifier.java +++ b/src/com/hypixel/hytale/common/plugin/PluginIdentifier.java @@ -5,6 +5,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PluginIdentifier { + public static final String THIRD_PARTY_LOADER_NAME = "ThirdParty"; @Nonnull private final String group; @Nonnull @@ -19,6 +20,30 @@ public class PluginIdentifier { this(manifest.getGroup(), manifest.getName()); } + @Nullable + public static PluginIdentifier identifyThirdPartyPlugin(Throwable t) { + Throwable current = t; + String prefix = "ThirdParty("; + + PluginIdentifier possibleFailureCause; + for (possibleFailureCause = null; current != null; current = current.getCause()) { + StackTraceElement[] stack = current.getStackTrace(); + + for (StackTraceElement entry : stack) { + String loader = entry.getClassLoaderName(); + if (loader != null && loader.startsWith(prefix)) { + int end = loader.lastIndexOf(41); + if (end != -1) { + possibleFailureCause = fromString(loader.substring(prefix.length(), end)); + return possibleFailureCause; + } + } + } + } + + return possibleFailureCause; + } + @Nonnull public String getGroup() { return this.group; diff --git a/src/com/hypixel/hytale/common/plugin/PluginManifest.java b/src/com/hypixel/hytale/common/plugin/PluginManifest.java index b65d9c28..511f6cac 100644 --- a/src/com/hypixel/hytale/common/plugin/PluginManifest.java +++ b/src/com/hypixel/hytale/common/plugin/PluginManifest.java @@ -43,7 +43,7 @@ public class PluginManifest { .add() .append(new KeyedCodec<>("Main", Codec.STRING), (manifest, o) -> manifest.main = o, manifest -> manifest.main) .add() - .append(new KeyedCodec<>("ServerVersion", SemverRange.CODEC), (manifest, o) -> manifest.serverVersion = o, manifest -> manifest.serverVersion) + .append(new KeyedCodec<>("ServerVersion", Codec.STRING), (manifest, o) -> manifest.serverVersion = o, manifest -> manifest.serverVersion) .add() .append( new KeyedCodec<>( @@ -79,8 +79,8 @@ public class PluginManifest { .build(); @Nonnull public static final Codec ARRAY_CODEC = new ArrayCodec<>(CODEC, PluginManifest[]::new); - private static final String CORE_GROUP = "Hytale"; - private static final Semver CORE_VERSION = ManifestUtil.getVersion() == null ? Semver.fromString("0.0.0-dev") : ManifestUtil.getVersion(); + public static final String CORE_GROUP = "Hytale"; + private static final Semver CORE_VERSION = Semver.fromString(ManifestUtil.getVersion() == null ? "0.0.0-dev" : ManifestUtil.getVersion()); private String group; private String name; private Semver version; @@ -92,7 +92,8 @@ public class PluginManifest { private String website; @Nullable private String main; - private SemverRange serverVersion; + @Nullable + private String serverVersion; @Nonnull private Map dependencies = new Object2ObjectLinkedOpenHashMap<>(); @Nonnull @@ -115,7 +116,7 @@ public class PluginManifest { @Nonnull List authors, @Nullable String website, @Nullable String main, - @Nullable SemverRange serverVersion, + @Nonnull String serverVersion, @Nonnull Map dependencies, @Nonnull Map optionalDependencies, @Nonnull Map loadBefore, @@ -193,10 +194,14 @@ public class PluginManifest { return this.main; } - public SemverRange getServerVersion() { + public String getServerVersion() { return this.serverVersion; } + public void setServerVersion(@Nullable String serverVersion) { + this.serverVersion = serverVersion; + } + @Nonnull public Map getDependencies() { return Collections.unmodifiableMap(this.dependencies); @@ -300,8 +305,6 @@ public class PluginManifest { } public static class CoreBuilder { - private static final String CORE_GROUP = "Hytale"; - private static final Semver CORE_VERSION = ManifestUtil.getVersion() == null ? Semver.fromString("0.0.0-dev") : ManifestUtil.getVersion(); @Nonnull private final String group; @Nonnull @@ -321,7 +324,7 @@ public class PluginManifest { @Nonnull public static PluginManifest.CoreBuilder corePlugin(@Nonnull Class pluginClass) { - return new PluginManifest.CoreBuilder("Hytale", pluginClass.getSimpleName(), CORE_VERSION, pluginClass.getName()); + return new PluginManifest.CoreBuilder("Hytale", pluginClass.getSimpleName(), PluginManifest.CORE_VERSION, pluginClass.getName()); } private CoreBuilder(@Nonnull String group, @Nonnull String name, @Nonnull Semver version, @Nonnull String main) { @@ -377,7 +380,7 @@ public class PluginManifest { Collections.emptyList(), null, this.main, - null, + ManifestUtil.getVersion() == null ? "0.0.0-dev" : ManifestUtil.getVersion(), this.dependencies, this.optionalDependencies, this.loadBefore, diff --git a/src/com/hypixel/hytale/common/util/PathUtil.java b/src/com/hypixel/hytale/common/util/PathUtil.java index 8f5da5f9..1fdb8bd2 100644 --- a/src/com/hypixel/hytale/common/util/PathUtil.java +++ b/src/com/hypixel/hytale/common/util/PathUtil.java @@ -5,6 +5,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.regex.Pattern; import javax.annotation.Nonnull; @@ -12,6 +14,23 @@ import javax.annotation.Nullable; public class PathUtil { private static final Pattern PATH_PATTERN = Pattern.compile("[\\\\/]"); + private static final Set TRUSTED_PATH_ROOTS = ConcurrentHashMap.newKeySet(); + + public static void addTrustedRoot(@Nonnull Path root) { + TRUSTED_PATH_ROOTS.add(root.toAbsolutePath().normalize()); + } + + public static boolean isInTrustedRoot(@Nonnull Path path) { + Path normalized = path.toAbsolutePath().normalize(); + + for (Path trusted : TRUSTED_PATH_ROOTS) { + if (isChildOf(trusted, normalized)) { + return true; + } + } + + return false; + } @Nonnull public static Path getParent(@Nonnull Path path) { @@ -51,6 +70,21 @@ public class PathUtil { } } + public static boolean isValidName(@Nonnull String name) { + return !name.isBlank() && name.indexOf(47) < 0 && name.indexOf(92) < 0 && !".".equals(name) && !"..".equals(name); + } + + @Nullable + public static Path resolvePathWithinDir(@Nonnull Path directory, @Nonnull String relativePath) { + Path resolved = directory.resolve(relativePath); + return !isChildOf(directory, resolved) ? null : resolved; + } + + @Nullable + public static Path resolveName(@Nonnull Path directory, @Nonnull String name) { + return !isValidName(name) ? null : directory.resolve(name); + } + @Nonnull public static Path get(@Nonnull String path) { return get(Paths.get(path)); @@ -100,4 +134,9 @@ public class PathUtil { public static String toUnixPathString(@Nonnull Path path) { return "\\".equals(path.getFileSystem().getSeparator()) ? path.toString().replace("\\", "/") : path.toString(); } + + static { + TRUSTED_PATH_ROOTS.add(Path.of("").toAbsolutePath().normalize()); + TRUSTED_PATH_ROOTS.add(Path.of(System.getProperty("java.io.tmpdir")).toAbsolutePath().normalize()); + } } diff --git a/src/com/hypixel/hytale/common/util/StringUtil.java b/src/com/hypixel/hytale/common/util/StringUtil.java index 2264031a..a47de5f0 100644 --- a/src/com/hypixel/hytale/common/util/StringUtil.java +++ b/src/com/hypixel/hytale/common/util/StringUtil.java @@ -426,15 +426,19 @@ public class StringUtil { public static String toPaddedBinaryString(int val) { byte[] buf = new byte[]{48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48}; int leadingZeros = Integer.numberOfLeadingZeros(val); - int mag = 32 - leadingZeros; - int pos = Math.max(mag, 1); + if (leadingZeros == 32) { + return new String(buf, 0); + } else { + int mag = 32 - leadingZeros; + int pos = Math.max(mag, 1); - do { - buf[leadingZeros + --pos] = (byte)(48 + (val & 1)); - val >>>= 1; - } while (pos > 0); + do { + buf[leadingZeros + --pos] = (byte)(48 + (val & 1)); + val >>>= 1; + } while (pos > 0); - return new String(buf, 0); + return new String(buf, 0); + } } @Nonnull diff --git a/src/com/hypixel/hytale/common/util/java/ManifestUtil.java b/src/com/hypixel/hytale/common/util/java/ManifestUtil.java index 52e5da96..4b541fb2 100644 --- a/src/com/hypixel/hytale/common/util/java/ManifestUtil.java +++ b/src/com/hypixel/hytale/common/util/java/ManifestUtil.java @@ -1,6 +1,5 @@ package com.hypixel.hytale.common.util.java; -import com.hypixel.hytale.common.semver.Semver; import com.hypixel.hytale.function.supplier.CachedSupplier; import com.hypixel.hytale.function.supplier.SupplierUtil; import com.hypixel.hytale.logger.HytaleLogger; @@ -86,9 +85,9 @@ public class ManifestUtil { return "dev"; } }); - private static final CachedSupplier VERSION = SupplierUtil.cache(() -> { + private static final CachedSupplier VERSION = SupplierUtil.cache(() -> { String version = IMPLEMENTATION_VERSION.get(); - return "NoJar".equals(version) ? null : Semver.fromString(version); + return "NoJar".equals(version) ? null : version; }); public static boolean isJar() { @@ -106,7 +105,7 @@ public class ManifestUtil { } @Nullable - public static Semver getVersion() { + public static String getVersion() { return VERSION.get(); } diff --git a/src/com/hypixel/hytale/component/Archetype.java b/src/com/hypixel/hytale/component/Archetype.java index dde85ac6..bd12d655 100644 --- a/src/com/hypixel/hytale/component/Archetype.java +++ b/src/com/hypixel/hytale/component/Archetype.java @@ -158,10 +158,14 @@ public class Archetype implements Query { @Nonnull public static Archetype of(@Nonnull ComponentType componentTypes) { - int index = componentTypes.getIndex(); - ComponentType[] arr = new ComponentType[index + 1]; - arr[index] = componentTypes; - return new Archetype<>(index, 1, arr); + if (componentTypes == null) { + throw new IllegalArgumentException("ComponentType in Archetype cannot be null"); + } else { + int index = componentTypes.getIndex(); + ComponentType[] arr = new ComponentType[index + 1]; + arr[index] = componentTypes; + return new Archetype<>(index, 1, arr); + } } @SafeVarargs @@ -169,13 +173,20 @@ public class Archetype implements Query { if (componentTypes.length == 0) { return EMPTY; } else { + for (int i = 0; i < componentTypes.length; i++) { + ComponentType componentType = componentTypes[i]; + if (componentType == null) { + throw new IllegalArgumentException("ComponentType in Archetype cannot be null (Index: " + i + ")"); + } + } + ComponentRegistry registry = componentTypes[0].getRegistry(); int minIndex = Integer.MAX_VALUE; int maxIndex = Integer.MIN_VALUE; - for (int i = 0; i < componentTypes.length; i++) { - componentTypes[i].validateRegistry(registry); - int index = componentTypes[i].getIndex(); + for (int ix = 0; ix < componentTypes.length; ix++) { + componentTypes[ix].validateRegistry(registry); + int index = componentTypes[ix].getIndex(); if (index < minIndex) { minIndex = index; } @@ -184,8 +195,8 @@ public class Archetype implements Query { maxIndex = index; } - for (int n = i + 1; n < componentTypes.length; n++) { - if (componentTypes[i] == componentTypes[n]) { + for (int n = ix + 1; n < componentTypes.length; n++) { + if (componentTypes[ix] == componentTypes[n]) { throw new IllegalArgumentException("ComponentType provided multiple times! " + Arrays.toString((Object[])componentTypes)); } } 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/shape/Box.java b/src/com/hypixel/hytale/math/shape/Box.java index f68909e6..98a513dc 100644 --- a/src/com/hypixel/hytale/math/shape/Box.java +++ b/src/com/hypixel/hytale/math/shape/Box.java @@ -32,6 +32,7 @@ public class Box implements Shape { }) .build(); public static final Box UNIT = new Box(Vector3d.ZERO, Vector3d.ALL_ONES); + public static final Box ZERO = new Box(Vector3d.ZERO, Vector3d.ZERO); @Nonnull public final Vector3d min = new Vector3d(); @Nonnull diff --git a/src/com/hypixel/hytale/math/util/ChunkUtil.java b/src/com/hypixel/hytale/math/util/ChunkUtil.java index 457f6fa9..f839c931 100644 --- a/src/com/hypixel/hytale/math/util/ChunkUtil.java +++ b/src/com/hypixel/hytale/math/util/ChunkUtil.java @@ -13,6 +13,7 @@ public class ChunkUtil { public static final int SIZE_COLUMNS = 1024; public static final int SIZE_COLUMNS_MASK = 1023; public static final int SIZE_BLOCKS = 32768; + public static final int SIZE_BLOCKS_MASK = 32767; public static final int BITS2 = 10; public static final int NON_CHUNK_MASK = -32; public static final int HEIGHT_SECTIONS = 10; 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..3e9b6de0 --- /dev/null +++ b/src/com/hypixel/hytale/procedurallib/file/FileIO.java @@ -0,0 +1,152 @@ +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 FS openFileIOSystem(@Nonnull FS 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<>(); + ObjectOpenHashSet disabled = 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)) { + visited.addAll(disabled); + disabled.clear(); + + for (Path filepath : dirStream) { + AssetPath assetPath = AssetPath.fromAbsolute(root, filepath); + AssetPath disabledPath = disableOp.apply(assetPath); + if (disabledPath != assetPath) { + disabled.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..4ca5fa8a 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; @@ -66,16 +71,14 @@ public abstract class JsonLoader extends Loader protected JsonElement loadFile(@Nonnull String filePath) { 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); + if (!file.normalize().startsWith(this.dataFolder.normalize())) { + throw new IllegalArgumentException("Invalid file reference: " + filePath); + } else { + try { + return FileIO.load(file, JSON_LOADER); + } catch (Throwable var4) { + throw new Error("Error while loading file reference." + file.toString(), var4); } - - return var4; - } catch (Throwable var8) { - throw new Error("Error while loading file reference." + file.toString(), var8); } } 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/ActiveAnimationsUpdate.java b/src/com/hypixel/hytale/protocol/ActiveAnimationsUpdate.java new file mode 100644 index 00000000..6280900a --- /dev/null +++ b/src/com/hypixel/hytale/protocol/ActiveAnimationsUpdate.java @@ -0,0 +1,179 @@ +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.Arrays; +import javax.annotation.Nonnull; + +public class ActiveAnimationsUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 1677721600; + @Nonnull + public String[] activeAnimations = new String[0]; + + public ActiveAnimationsUpdate() { + } + + public ActiveAnimationsUpdate(@Nonnull String[] activeAnimations) { + this.activeAnimations = activeAnimations; + } + + public ActiveAnimationsUpdate(@Nonnull ActiveAnimationsUpdate other) { + this.activeAnimations = other.activeAnimations; + } + + @Nonnull + public static ActiveAnimationsUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + ActiveAnimationsUpdate obj = new ActiveAnimationsUpdate(); + int pos = offset + 0; + int activeAnimationsCount = VarInt.peek(buf, pos); + if (activeAnimationsCount < 0) { + throw ProtocolException.negativeLength("ActiveAnimations", activeAnimationsCount); + } else if (activeAnimationsCount > 4096000) { + throw ProtocolException.arrayTooLong("ActiveAnimations", activeAnimationsCount, 4096000); + } else { + pos += VarInt.size(activeAnimationsCount); + int activeAnimationsBitfieldSize = (activeAnimationsCount + 7) / 8; + byte[] activeAnimationsBitfield = PacketIO.readBytes(buf, pos, activeAnimationsBitfieldSize); + pos += activeAnimationsBitfieldSize; + obj.activeAnimations = new String[activeAnimationsCount]; + + for (int i = 0; i < activeAnimationsCount; i++) { + if ((activeAnimationsBitfield[i / 8] & 1 << i % 8) != 0) { + int strLen = VarInt.peek(buf, pos); + if (strLen < 0) { + throw ProtocolException.negativeLength("activeAnimations[" + i + "]", strLen); + } + + if (strLen > 4096000) { + throw ProtocolException.stringTooLong("activeAnimations[" + i + "]", strLen, 4096000); + } + + int strVarLen = VarInt.length(buf, pos); + obj.activeAnimations[i] = PacketIO.readVarString(buf, pos); + pos += strVarLen + strLen; + } + } + + return obj; + } + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int pos = offset + 0; + int arrLen = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos); + int bitfieldSize = (arrLen + 7) / 8; + byte[] bitfield = PacketIO.readBytes(buf, pos, bitfieldSize); + pos += bitfieldSize; + + for (int i = 0; i < arrLen; i++) { + if ((bitfield[i / 8] & 1 << i % 8) != 0) { + int sl = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos) + sl; + } + } + + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + if (this.activeAnimations.length > 4096000) { + throw ProtocolException.arrayTooLong("ActiveAnimations", this.activeAnimations.length, 4096000); + } else { + VarInt.write(buf, this.activeAnimations.length); + int activeAnimationsBitfieldSize = (this.activeAnimations.length + 7) / 8; + byte[] activeAnimationsBitfield = new byte[activeAnimationsBitfieldSize]; + + for (int i = 0; i < this.activeAnimations.length; i++) { + if (this.activeAnimations[i] != null) { + activeAnimationsBitfield[i / 8] = (byte)(activeAnimationsBitfield[i / 8] | (byte)(1 << i % 8)); + } + } + + buf.writeBytes(activeAnimationsBitfield); + + for (int ix = 0; ix < this.activeAnimations.length; ix++) { + if (this.activeAnimations[ix] != null) { + PacketIO.writeVarString(buf, this.activeAnimations[ix], 4096000); + } + } + + return buf.writerIndex() - startPos; + } + } + + @Override + public int computeSize() { + int size = 0; + int activeAnimationsSize = 0; + + for (String elem : this.activeAnimations) { + if (elem != null) { + activeAnimationsSize += PacketIO.stringSize(elem); + } + } + + return size + VarInt.size(this.activeAnimations.length) + (this.activeAnimations.length + 7) / 8 + activeAnimationsSize; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 0) { + return ValidationResult.error("Buffer too small: expected at least 0 bytes"); + } else { + int pos = offset + 0; + int activeAnimationsCount = VarInt.peek(buffer, pos); + if (activeAnimationsCount < 0) { + return ValidationResult.error("Invalid array count for ActiveAnimations"); + } else if (activeAnimationsCount > 4096000) { + return ValidationResult.error("ActiveAnimations exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + + for (int i = 0; i < activeAnimationsCount; i++) { + int strLen = VarInt.peek(buffer, pos); + if (strLen < 0) { + return ValidationResult.error("Invalid string length in ActiveAnimations"); + } + + pos += VarInt.length(buffer, pos); + pos += strLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading string in ActiveAnimations"); + } + } + + return ValidationResult.OK; + } + } + } + + public ActiveAnimationsUpdate clone() { + ActiveAnimationsUpdate copy = new ActiveAnimationsUpdate(); + copy.activeAnimations = Arrays.copyOf(this.activeAnimations, this.activeAnimations.length); + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof ActiveAnimationsUpdate other ? Arrays.equals((Object[])this.activeAnimations, (Object[])other.activeAnimations) : false; + } + } + + @Override + public int hashCode() { + int result = 1; + return 31 * result + Arrays.hashCode((Object[])this.activeAnimations); + } +} diff --git a/src/com/hypixel/hytale/protocol/AudioUpdate.java b/src/com/hypixel/hytale/protocol/AudioUpdate.java new file mode 100644 index 00000000..786e85cf --- /dev/null +++ b/src/com/hypixel/hytale/protocol/AudioUpdate.java @@ -0,0 +1,124 @@ +package com.hypixel.hytale.protocol; + +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.Arrays; +import javax.annotation.Nonnull; + +public class AudioUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 16384005; + @Nonnull + public int[] soundEventIds = new int[0]; + + public AudioUpdate() { + } + + public AudioUpdate(@Nonnull int[] soundEventIds) { + this.soundEventIds = soundEventIds; + } + + public AudioUpdate(@Nonnull AudioUpdate other) { + this.soundEventIds = other.soundEventIds; + } + + @Nonnull + public static AudioUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + AudioUpdate obj = new AudioUpdate(); + int pos = offset + 0; + int soundEventIdsCount = VarInt.peek(buf, pos); + if (soundEventIdsCount < 0) { + throw ProtocolException.negativeLength("SoundEventIds", soundEventIdsCount); + } else if (soundEventIdsCount > 4096000) { + throw ProtocolException.arrayTooLong("SoundEventIds", soundEventIdsCount, 4096000); + } else { + int soundEventIdsVarLen = VarInt.size(soundEventIdsCount); + if (pos + soundEventIdsVarLen + soundEventIdsCount * 4L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("SoundEventIds", pos + soundEventIdsVarLen + soundEventIdsCount * 4, buf.readableBytes()); + } else { + pos += soundEventIdsVarLen; + obj.soundEventIds = new int[soundEventIdsCount]; + + for (int i = 0; i < soundEventIdsCount; i++) { + obj.soundEventIds[i] = buf.getIntLE(pos + i * 4); + } + + pos += soundEventIdsCount * 4; + return obj; + } + } + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int pos = offset + 0; + int arrLen = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos) + arrLen * 4; + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + if (this.soundEventIds.length > 4096000) { + throw ProtocolException.arrayTooLong("SoundEventIds", this.soundEventIds.length, 4096000); + } else { + VarInt.write(buf, this.soundEventIds.length); + + for (int item : this.soundEventIds) { + buf.writeIntLE(item); + } + + return buf.writerIndex() - startPos; + } + } + + @Override + public int computeSize() { + int size = 0; + return size + VarInt.size(this.soundEventIds.length) + this.soundEventIds.length * 4; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 0) { + return ValidationResult.error("Buffer too small: expected at least 0 bytes"); + } else { + int pos = offset + 0; + int soundEventIdsCount = VarInt.peek(buffer, pos); + if (soundEventIdsCount < 0) { + return ValidationResult.error("Invalid array count for SoundEventIds"); + } else if (soundEventIdsCount > 4096000) { + return ValidationResult.error("SoundEventIds exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + pos += soundEventIdsCount * 4; + return pos > buffer.writerIndex() ? ValidationResult.error("Buffer overflow reading SoundEventIds") : ValidationResult.OK; + } + } + } + + public AudioUpdate clone() { + AudioUpdate copy = new AudioUpdate(); + copy.soundEventIds = Arrays.copyOf(this.soundEventIds, this.soundEventIds.length); + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof AudioUpdate other ? Arrays.equals(this.soundEventIds, other.soundEventIds) : false; + } + } + + @Override + public int hashCode() { + int result = 1; + return 31 * result + Arrays.hashCode(this.soundEventIds); + } +} diff --git a/src/com/hypixel/hytale/protocol/BenchRequirement.java b/src/com/hypixel/hytale/protocol/BenchRequirement.java index 446ddc96..81b44dd0 100644 --- a/src/com/hypixel/hytale/protocol/BenchRequirement.java +++ b/src/com/hypixel/hytale/protocol/BenchRequirement.java @@ -18,8 +18,8 @@ public class BenchRequirement { public static final int MAX_SIZE = 1677721600; @Nonnull public BenchType type = BenchType.Crafting; - @Nullable - public String id; + @Nonnull + public String id = ""; @Nullable public String[] categories; public int requiredTierLevel; @@ -27,7 +27,7 @@ public class BenchRequirement { public BenchRequirement() { } - public BenchRequirement(@Nonnull BenchType type, @Nullable String id, @Nullable String[] categories, int requiredTierLevel) { + public BenchRequirement(@Nonnull BenchType type, @Nonnull String id, @Nullable String[] categories, int requiredTierLevel) { this.type = type; this.id = id; this.categories = categories; @@ -47,84 +47,77 @@ public class BenchRequirement { byte nullBits = buf.getByte(offset); obj.type = BenchType.fromValue(buf.getByte(offset + 1)); obj.requiredTierLevel = buf.getIntLE(offset + 2); - if ((nullBits & 1) != 0) { - int varPos0 = offset + 14 + buf.getIntLE(offset + 6); - int idLen = VarInt.peek(buf, varPos0); - if (idLen < 0) { - throw ProtocolException.negativeLength("Id", idLen); - } - - if (idLen > 4096000) { - throw ProtocolException.stringTooLong("Id", idLen, 4096000); - } - + int varPos0 = offset + 14 + buf.getIntLE(offset + 6); + 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 & 2) != 0) { - int varPos1 = offset + 14 + buf.getIntLE(offset + 10); - int categoriesCount = VarInt.peek(buf, varPos1); - if (categoriesCount < 0) { - throw ProtocolException.negativeLength("Categories", categoriesCount); - } - - if (categoriesCount > 4096000) { - throw ProtocolException.arrayTooLong("Categories", categoriesCount, 4096000); - } - - int varIntLen = VarInt.length(buf, varPos1); - if (varPos1 + varIntLen + categoriesCount * 1L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall("Categories", varPos1 + varIntLen + categoriesCount * 1, buf.readableBytes()); - } - - obj.categories = new String[categoriesCount]; - int elemPos = varPos1 + varIntLen; - - for (int i = 0; i < categoriesCount; i++) { - int strLen = VarInt.peek(buf, elemPos); - if (strLen < 0) { - throw ProtocolException.negativeLength("categories[" + i + "]", strLen); + if ((nullBits & 1) != 0) { + varPos0 = offset + 14 + buf.getIntLE(offset + 10); + idLen = VarInt.peek(buf, varPos0); + if (idLen < 0) { + throw ProtocolException.negativeLength("Categories", idLen); } - if (strLen > 4096000) { - throw ProtocolException.stringTooLong("categories[" + i + "]", strLen, 4096000); + if (idLen > 4096000) { + throw ProtocolException.arrayTooLong("Categories", idLen, 4096000); } - int strVarLen = VarInt.length(buf, elemPos); - obj.categories[i] = PacketIO.readVarString(buf, elemPos); - elemPos += strVarLen + strLen; - } - } + int varIntLen = VarInt.length(buf, varPos0); + if (varPos0 + varIntLen + idLen * 1L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("Categories", varPos0 + varIntLen + idLen * 1, buf.readableBytes()); + } - return obj; + obj.categories = new String[idLen]; + int elemPos = varPos0 + varIntLen; + + for (int i = 0; i < idLen; i++) { + int strLen = VarInt.peek(buf, elemPos); + if (strLen < 0) { + throw ProtocolException.negativeLength("categories[" + i + "]", strLen); + } + + if (strLen > 4096000) { + throw ProtocolException.stringTooLong("categories[" + i + "]", strLen, 4096000); + } + + int strVarLen = VarInt.length(buf, elemPos); + obj.categories[i] = PacketIO.readVarString(buf, elemPos); + elemPos += strVarLen + strLen; + } + } + + return obj; + } } public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte nullBits = buf.getByte(offset); int maxEnd = 14; - if ((nullBits & 1) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 6); - int pos0 = offset + 14 + fieldOffset0; - int sl = VarInt.peek(buf, pos0); - pos0 += VarInt.length(buf, pos0) + sl; - if (pos0 - offset > maxEnd) { - maxEnd = pos0 - offset; - } + int fieldOffset0 = buf.getIntLE(offset + 6); + int pos0 = offset + 14 + 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 + 10); - int pos1 = offset + 14 + fieldOffset1; - int arrLen = VarInt.peek(buf, pos1); - pos1 += VarInt.length(buf, pos1); + if ((nullBits & 1) != 0) { + fieldOffset0 = buf.getIntLE(offset + 10); + pos0 = offset + 14 + fieldOffset0; + sl = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0); - for (int i = 0; i < arrLen; i++) { - int sl = VarInt.peek(buf, pos1); - pos1 += VarInt.length(buf, pos1) + sl; + for (int i = 0; i < sl; i++) { + int slx = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0) + slx; } - if (pos1 - offset > maxEnd) { - maxEnd = pos1 - offset; + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; } } @@ -134,12 +127,8 @@ public class BenchRequirement { public void serialize(@Nonnull ByteBuf buf) { int startPos = buf.writerIndex(); byte nullBits = 0; - if (this.id != null) { - nullBits = (byte)(nullBits | 1); - } - if (this.categories != null) { - nullBits = (byte)(nullBits | 2); + nullBits = (byte)(nullBits | 1); } buf.writeByte(nullBits); @@ -150,13 +139,8 @@ public class BenchRequirement { int categoriesOffsetSlot = 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.categories != null) { buf.setIntLE(categoriesOffsetSlot, buf.writerIndex() - varBlockStart); if (this.categories.length > 4096000) { @@ -175,10 +159,7 @@ public class BenchRequirement { public int computeSize() { int size = 14; - if (this.id != null) { - size += PacketIO.stringSize(this.id); - } - + size += PacketIO.stringSize(this.id); if (this.categories != null) { int categoriesSize = 0; @@ -197,70 +178,66 @@ public class BenchRequirement { return ValidationResult.error("Buffer too small: expected at least 14 bytes"); } else { byte nullBits = buffer.getByte(offset); - if ((nullBits & 1) != 0) { - int idOffset = buffer.getIntLE(offset + 6); - if (idOffset < 0) { - return ValidationResult.error("Invalid offset for Id"); - } - + int idOffset = buffer.getIntLE(offset + 6); + if (idOffset < 0) { + return ValidationResult.error("Invalid offset for Id"); + } else { int pos = offset + 14 + 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 + 10); + if (idOffset < 0) { + return ValidationResult.error("Invalid offset for Categories"); + } - int idLen = VarInt.peek(buffer, pos); - if (idLen < 0) { - return ValidationResult.error("Invalid string length for Id"); - } + pos = offset + 14 + idOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for Categories"); + } - if (idLen > 4096000) { - return ValidationResult.error("Id exceeds max length 4096000"); - } + idLen = VarInt.peek(buffer, pos); + if (idLen < 0) { + return ValidationResult.error("Invalid array count for Categories"); + } - pos += VarInt.length(buffer, pos); - pos += idLen; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Id"); - } - } + if (idLen > 4096000) { + return ValidationResult.error("Categories exceeds max length 4096000"); + } - if ((nullBits & 2) != 0) { - int categoriesOffset = buffer.getIntLE(offset + 10); - if (categoriesOffset < 0) { - return ValidationResult.error("Invalid offset for Categories"); - } + pos += VarInt.length(buffer, pos); - int posx = offset + 14 + categoriesOffset; - if (posx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Categories"); - } + for (int i = 0; i < idLen; i++) { + int strLen = VarInt.peek(buffer, pos); + if (strLen < 0) { + return ValidationResult.error("Invalid string length in Categories"); + } - int categoriesCount = VarInt.peek(buffer, posx); - if (categoriesCount < 0) { - return ValidationResult.error("Invalid array count for Categories"); - } + pos += VarInt.length(buffer, pos); + pos += strLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading string in Categories"); + } + } + } - if (categoriesCount > 4096000) { - return ValidationResult.error("Categories exceeds max length 4096000"); - } - - posx += VarInt.length(buffer, posx); - - for (int i = 0; i < categoriesCount; i++) { - int strLen = VarInt.peek(buffer, posx); - if (strLen < 0) { - return ValidationResult.error("Invalid string length in Categories"); - } - - posx += VarInt.length(buffer, posx); - posx += strLen; - if (posx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading string in Categories"); + return ValidationResult.OK; + } } } } - - return ValidationResult.OK; } } diff --git a/src/com/hypixel/hytale/protocol/BlockPlacementSettings.java b/src/com/hypixel/hytale/protocol/BlockPlacementSettings.java index 9dd0e82b..f7084450 100644 --- a/src/com/hypixel/hytale/protocol/BlockPlacementSettings.java +++ b/src/com/hypixel/hytale/protocol/BlockPlacementSettings.java @@ -7,10 +7,10 @@ import javax.annotation.Nonnull; public class BlockPlacementSettings { public static final int NULLABLE_BIT_FIELD_SIZE = 0; - public static final int FIXED_BLOCK_SIZE = 16; + public static final int FIXED_BLOCK_SIZE = 17; public static final int VARIABLE_FIELD_COUNT = 0; - public static final int VARIABLE_BLOCK_START = 16; - public static final int MAX_SIZE = 16; + public static final int VARIABLE_BLOCK_START = 17; + public static final int MAX_SIZE = 17; public boolean allowRotationKey; public boolean placeInEmptyBlocks; @Nonnull @@ -20,6 +20,7 @@ public class BlockPlacementSettings { public int wallPlacementOverrideBlockId; public int floorPlacementOverrideBlockId; public int ceilingPlacementOverrideBlockId; + public boolean allowBreakReplace; public BlockPlacementSettings() { } @@ -31,7 +32,8 @@ public class BlockPlacementSettings { @Nonnull BlockPlacementRotationMode rotationMode, int wallPlacementOverrideBlockId, int floorPlacementOverrideBlockId, - int ceilingPlacementOverrideBlockId + int ceilingPlacementOverrideBlockId, + boolean allowBreakReplace ) { this.allowRotationKey = allowRotationKey; this.placeInEmptyBlocks = placeInEmptyBlocks; @@ -40,6 +42,7 @@ public class BlockPlacementSettings { this.wallPlacementOverrideBlockId = wallPlacementOverrideBlockId; this.floorPlacementOverrideBlockId = floorPlacementOverrideBlockId; this.ceilingPlacementOverrideBlockId = ceilingPlacementOverrideBlockId; + this.allowBreakReplace = allowBreakReplace; } public BlockPlacementSettings(@Nonnull BlockPlacementSettings other) { @@ -50,6 +53,7 @@ public class BlockPlacementSettings { this.wallPlacementOverrideBlockId = other.wallPlacementOverrideBlockId; this.floorPlacementOverrideBlockId = other.floorPlacementOverrideBlockId; this.ceilingPlacementOverrideBlockId = other.ceilingPlacementOverrideBlockId; + this.allowBreakReplace = other.allowBreakReplace; } @Nonnull @@ -62,11 +66,12 @@ public class BlockPlacementSettings { obj.wallPlacementOverrideBlockId = buf.getIntLE(offset + 4); obj.floorPlacementOverrideBlockId = buf.getIntLE(offset + 8); obj.ceilingPlacementOverrideBlockId = buf.getIntLE(offset + 12); + obj.allowBreakReplace = buf.getByte(offset + 16) != 0; return obj; } public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { - return 16; + return 17; } public void serialize(@Nonnull ByteBuf buf) { @@ -77,14 +82,15 @@ public class BlockPlacementSettings { buf.writeIntLE(this.wallPlacementOverrideBlockId); buf.writeIntLE(this.floorPlacementOverrideBlockId); buf.writeIntLE(this.ceilingPlacementOverrideBlockId); + buf.writeByte(this.allowBreakReplace ? 1 : 0); } public int computeSize() { - return 16; + return 17; } 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; + return buffer.readableBytes() - offset < 17 ? ValidationResult.error("Buffer too small: expected at least 17 bytes") : ValidationResult.OK; } public BlockPlacementSettings clone() { @@ -96,6 +102,7 @@ public class BlockPlacementSettings { copy.wallPlacementOverrideBlockId = this.wallPlacementOverrideBlockId; copy.floorPlacementOverrideBlockId = this.floorPlacementOverrideBlockId; copy.ceilingPlacementOverrideBlockId = this.ceilingPlacementOverrideBlockId; + copy.allowBreakReplace = this.allowBreakReplace; return copy; } @@ -112,7 +119,8 @@ public class BlockPlacementSettings { && Objects.equals(this.rotationMode, other.rotationMode) && this.wallPlacementOverrideBlockId == other.wallPlacementOverrideBlockId && this.floorPlacementOverrideBlockId == other.floorPlacementOverrideBlockId - && this.ceilingPlacementOverrideBlockId == other.ceilingPlacementOverrideBlockId; + && this.ceilingPlacementOverrideBlockId == other.ceilingPlacementOverrideBlockId + && this.allowBreakReplace == other.allowBreakReplace; } } @@ -125,7 +133,8 @@ public class BlockPlacementSettings { this.rotationMode, this.wallPlacementOverrideBlockId, this.floorPlacementOverrideBlockId, - this.ceilingPlacementOverrideBlockId + this.ceilingPlacementOverrideBlockId, + this.allowBreakReplace ); } } diff --git a/src/com/hypixel/hytale/protocol/BlockType.java b/src/com/hypixel/hytale/protocol/BlockType.java index 854fa7b3..70e3aaa3 100644 --- a/src/com/hypixel/hytale/protocol/BlockType.java +++ b/src/com/hypixel/hytale/protocol/BlockType.java @@ -15,9 +15,9 @@ import javax.annotation.Nullable; public class BlockType { public static final int NULLABLE_BIT_FIELD_SIZE = 4; - public static final int FIXED_BLOCK_SIZE = 163; + public static final int FIXED_BLOCK_SIZE = 164; public static final int VARIABLE_FIELD_COUNT = 24; - public static final int VARIABLE_BLOCK_START = 259; + public static final int VARIABLE_BLOCK_START = 260; public static final int MAX_SIZE = 1677721600; @Nullable public String item; @@ -323,10 +323,10 @@ public class BlockType { obj.placementSettings = BlockPlacementSettings.deserialize(buf, offset + 142); } - obj.ignoreSupportWhenPlaced = buf.getByte(offset + 158) != 0; - obj.transitionToTag = buf.getIntLE(offset + 159); + obj.ignoreSupportWhenPlaced = buf.getByte(offset + 159) != 0; + obj.transitionToTag = buf.getIntLE(offset + 160); if ((nullBits[0] & 128) != 0) { - int varPos0 = offset + 259 + buf.getIntLE(offset + 163); + int varPos0 = offset + 260 + buf.getIntLE(offset + 164); int itemLen = VarInt.peek(buf, varPos0); if (itemLen < 0) { throw ProtocolException.negativeLength("Item", itemLen); @@ -340,7 +340,7 @@ public class BlockType { } if ((nullBits[1] & 1) != 0) { - int varPos1 = offset + 259 + buf.getIntLE(offset + 167); + int varPos1 = offset + 260 + buf.getIntLE(offset + 168); int nameLen = VarInt.peek(buf, varPos1); if (nameLen < 0) { throw ProtocolException.negativeLength("Name", nameLen); @@ -354,7 +354,7 @@ public class BlockType { } if ((nullBits[1] & 2) != 0) { - int varPos2 = offset + 259 + buf.getIntLE(offset + 171); + int varPos2 = offset + 260 + buf.getIntLE(offset + 172); int shaderEffectCount = VarInt.peek(buf, varPos2); if (shaderEffectCount < 0) { throw ProtocolException.negativeLength("ShaderEffect", shaderEffectCount); @@ -379,7 +379,7 @@ public class BlockType { } if ((nullBits[1] & 4) != 0) { - int varPos3 = offset + 259 + buf.getIntLE(offset + 175); + int varPos3 = offset + 260 + buf.getIntLE(offset + 176); int modelLen = VarInt.peek(buf, varPos3); if (modelLen < 0) { throw ProtocolException.negativeLength("Model", modelLen); @@ -393,7 +393,7 @@ public class BlockType { } if ((nullBits[1] & 8) != 0) { - int varPos4 = offset + 259 + buf.getIntLE(offset + 179); + int varPos4 = offset + 260 + buf.getIntLE(offset + 180); int modelTextureCount = VarInt.peek(buf, varPos4); if (modelTextureCount < 0) { throw ProtocolException.negativeLength("ModelTexture", modelTextureCount); @@ -418,7 +418,7 @@ public class BlockType { } if ((nullBits[1] & 16) != 0) { - int varPos5 = offset + 259 + buf.getIntLE(offset + 183); + int varPos5 = offset + 260 + buf.getIntLE(offset + 184); int modelAnimationLen = VarInt.peek(buf, varPos5); if (modelAnimationLen < 0) { throw ProtocolException.negativeLength("ModelAnimation", modelAnimationLen); @@ -432,7 +432,7 @@ public class BlockType { } if ((nullBits[1] & 32) != 0) { - int varPos6 = offset + 259 + buf.getIntLE(offset + 187); + int varPos6 = offset + 260 + buf.getIntLE(offset + 188); int supportCount = VarInt.peek(buf, varPos6); if (supportCount < 0) { throw ProtocolException.negativeLength("Support", supportCount); @@ -477,7 +477,7 @@ public class BlockType { } if ((nullBits[1] & 64) != 0) { - int varPos7 = offset + 259 + buf.getIntLE(offset + 191); + int varPos7 = offset + 260 + buf.getIntLE(offset + 192); int supportingCount = VarInt.peek(buf, varPos7); if (supportingCount < 0) { throw ProtocolException.negativeLength("Supporting", supportingCount); @@ -522,7 +522,7 @@ public class BlockType { } if ((nullBits[1] & 128) != 0) { - int varPos8 = offset + 259 + buf.getIntLE(offset + 195); + int varPos8 = offset + 260 + buf.getIntLE(offset + 196); int cubeTexturesCount = VarInt.peek(buf, varPos8); if (cubeTexturesCount < 0) { throw ProtocolException.negativeLength("CubeTextures", cubeTexturesCount); @@ -547,7 +547,7 @@ public class BlockType { } if ((nullBits[2] & 1) != 0) { - int varPos9 = offset + 259 + buf.getIntLE(offset + 199); + int varPos9 = offset + 260 + buf.getIntLE(offset + 200); int cubeSideMaskTextureLen = VarInt.peek(buf, varPos9); if (cubeSideMaskTextureLen < 0) { throw ProtocolException.negativeLength("CubeSideMaskTexture", cubeSideMaskTextureLen); @@ -561,7 +561,7 @@ public class BlockType { } if ((nullBits[2] & 2) != 0) { - int varPos10 = offset + 259 + buf.getIntLE(offset + 203); + int varPos10 = offset + 260 + buf.getIntLE(offset + 204); int particlesCount = VarInt.peek(buf, varPos10); if (particlesCount < 0) { throw ProtocolException.negativeLength("Particles", particlesCount); @@ -586,7 +586,7 @@ public class BlockType { } if ((nullBits[2] & 4) != 0) { - int varPos11 = offset + 259 + buf.getIntLE(offset + 207); + int varPos11 = offset + 260 + buf.getIntLE(offset + 208); int blockParticleSetIdLen = VarInt.peek(buf, varPos11); if (blockParticleSetIdLen < 0) { throw ProtocolException.negativeLength("BlockParticleSetId", blockParticleSetIdLen); @@ -600,7 +600,7 @@ public class BlockType { } if ((nullBits[2] & 8) != 0) { - int varPos12 = offset + 259 + buf.getIntLE(offset + 211); + int varPos12 = offset + 260 + buf.getIntLE(offset + 212); int blockBreakingDecalIdLen = VarInt.peek(buf, varPos12); if (blockBreakingDecalIdLen < 0) { throw ProtocolException.negativeLength("BlockBreakingDecalId", blockBreakingDecalIdLen); @@ -614,7 +614,7 @@ public class BlockType { } if ((nullBits[2] & 16) != 0) { - int varPos13 = offset + 259 + buf.getIntLE(offset + 215); + int varPos13 = offset + 260 + buf.getIntLE(offset + 216); int transitionTextureLen = VarInt.peek(buf, varPos13); if (transitionTextureLen < 0) { throw ProtocolException.negativeLength("TransitionTexture", transitionTextureLen); @@ -628,7 +628,7 @@ public class BlockType { } if ((nullBits[2] & 32) != 0) { - int varPos14 = offset + 259 + buf.getIntLE(offset + 219); + int varPos14 = offset + 260 + buf.getIntLE(offset + 220); int transitionToGroupsCount = VarInt.peek(buf, varPos14); if (transitionToGroupsCount < 0) { throw ProtocolException.negativeLength("TransitionToGroups", transitionToGroupsCount); @@ -651,7 +651,7 @@ public class BlockType { } if ((nullBits[2] & 64) != 0) { - int varPos15 = offset + 259 + buf.getIntLE(offset + 223); + int varPos15 = offset + 260 + buf.getIntLE(offset + 224); int interactionHintLen = VarInt.peek(buf, varPos15); if (interactionHintLen < 0) { throw ProtocolException.negativeLength("InteractionHint", interactionHintLen); @@ -665,22 +665,22 @@ public class BlockType { } if ((nullBits[2] & 128) != 0) { - int varPos16 = offset + 259 + buf.getIntLE(offset + 227); + int varPos16 = offset + 260 + buf.getIntLE(offset + 228); obj.gathering = BlockGathering.deserialize(buf, varPos16); } if ((nullBits[3] & 1) != 0) { - int varPos17 = offset + 259 + buf.getIntLE(offset + 231); + int varPos17 = offset + 260 + buf.getIntLE(offset + 232); obj.display = ModelDisplay.deserialize(buf, varPos17); } if ((nullBits[3] & 2) != 0) { - int varPos18 = offset + 259 + buf.getIntLE(offset + 235); + int varPos18 = offset + 260 + buf.getIntLE(offset + 236); obj.rail = RailConfig.deserialize(buf, varPos18); } if ((nullBits[3] & 4) != 0) { - int varPos19 = offset + 259 + buf.getIntLE(offset + 239); + int varPos19 = offset + 260 + buf.getIntLE(offset + 240); int interactionsCount = VarInt.peek(buf, varPos19); if (interactionsCount < 0) { throw ProtocolException.negativeLength("Interactions", interactionsCount); @@ -705,7 +705,7 @@ public class BlockType { } if ((nullBits[3] & 8) != 0) { - int varPos20 = offset + 259 + buf.getIntLE(offset + 243); + int varPos20 = offset + 260 + buf.getIntLE(offset + 244); int statesCount = VarInt.peek(buf, varPos20); if (statesCount < 0) { throw ProtocolException.negativeLength("States", statesCount); @@ -741,7 +741,7 @@ public class BlockType { } if ((nullBits[3] & 16) != 0) { - int varPos21 = offset + 259 + buf.getIntLE(offset + 247); + int varPos21 = offset + 260 + buf.getIntLE(offset + 248); int tagIndexesCount = VarInt.peek(buf, varPos21); if (tagIndexesCount < 0) { throw ProtocolException.negativeLength("TagIndexes", tagIndexesCount); @@ -764,12 +764,12 @@ public class BlockType { } if ((nullBits[3] & 32) != 0) { - int varPos22 = offset + 259 + buf.getIntLE(offset + 251); + int varPos22 = offset + 260 + buf.getIntLE(offset + 252); obj.bench = Bench.deserialize(buf, varPos22); } if ((nullBits[3] & 64) != 0) { - int varPos23 = offset + 259 + buf.getIntLE(offset + 255); + int varPos23 = offset + 260 + buf.getIntLE(offset + 256); obj.connectedBlockRuleSet = ConnectedBlockRuleSet.deserialize(buf, varPos23); } @@ -778,10 +778,10 @@ public class BlockType { public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte[] nullBits = PacketIO.readBytes(buf, offset, 4); - int maxEnd = 259; + int maxEnd = 260; if ((nullBits[0] & 128) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 163); - int pos0 = offset + 259 + fieldOffset0; + int fieldOffset0 = buf.getIntLE(offset + 164); + int pos0 = offset + 260 + fieldOffset0; int sl = VarInt.peek(buf, pos0); pos0 += VarInt.length(buf, pos0) + sl; if (pos0 - offset > maxEnd) { @@ -790,8 +790,8 @@ public class BlockType { } if ((nullBits[1] & 1) != 0) { - int fieldOffset1 = buf.getIntLE(offset + 167); - int pos1 = offset + 259 + fieldOffset1; + int fieldOffset1 = buf.getIntLE(offset + 168); + int pos1 = offset + 260 + fieldOffset1; int sl = VarInt.peek(buf, pos1); pos1 += VarInt.length(buf, pos1) + sl; if (pos1 - offset > maxEnd) { @@ -800,8 +800,8 @@ public class BlockType { } if ((nullBits[1] & 2) != 0) { - int fieldOffset2 = buf.getIntLE(offset + 171); - int pos2 = offset + 259 + fieldOffset2; + int fieldOffset2 = buf.getIntLE(offset + 172); + int pos2 = offset + 260 + fieldOffset2; int arrLen = VarInt.peek(buf, pos2); pos2 += VarInt.length(buf, pos2) + arrLen * 1; if (pos2 - offset > maxEnd) { @@ -810,8 +810,8 @@ public class BlockType { } if ((nullBits[1] & 4) != 0) { - int fieldOffset3 = buf.getIntLE(offset + 175); - int pos3 = offset + 259 + fieldOffset3; + int fieldOffset3 = buf.getIntLE(offset + 176); + int pos3 = offset + 260 + fieldOffset3; int sl = VarInt.peek(buf, pos3); pos3 += VarInt.length(buf, pos3) + sl; if (pos3 - offset > maxEnd) { @@ -820,8 +820,8 @@ public class BlockType { } if ((nullBits[1] & 8) != 0) { - int fieldOffset4 = buf.getIntLE(offset + 179); - int pos4 = offset + 259 + fieldOffset4; + int fieldOffset4 = buf.getIntLE(offset + 180); + int pos4 = offset + 260 + fieldOffset4; int arrLen = VarInt.peek(buf, pos4); pos4 += VarInt.length(buf, pos4); @@ -835,8 +835,8 @@ public class BlockType { } if ((nullBits[1] & 16) != 0) { - int fieldOffset5 = buf.getIntLE(offset + 183); - int pos5 = offset + 259 + fieldOffset5; + int fieldOffset5 = buf.getIntLE(offset + 184); + int pos5 = offset + 260 + fieldOffset5; int sl = VarInt.peek(buf, pos5); pos5 += VarInt.length(buf, pos5) + sl; if (pos5 - offset > maxEnd) { @@ -845,8 +845,8 @@ public class BlockType { } if ((nullBits[1] & 32) != 0) { - int fieldOffset6 = buf.getIntLE(offset + 187); - int pos6 = offset + 259 + fieldOffset6; + int fieldOffset6 = buf.getIntLE(offset + 188); + int pos6 = offset + 260 + fieldOffset6; int dictLen = VarInt.peek(buf, pos6); pos6 += VarInt.length(buf, pos6); @@ -865,8 +865,8 @@ public class BlockType { } if ((nullBits[1] & 64) != 0) { - int fieldOffset7 = buf.getIntLE(offset + 191); - int pos7 = offset + 259 + fieldOffset7; + int fieldOffset7 = buf.getIntLE(offset + 192); + int pos7 = offset + 260 + fieldOffset7; int dictLen = VarInt.peek(buf, pos7); pos7 += VarInt.length(buf, pos7); @@ -885,8 +885,8 @@ public class BlockType { } if ((nullBits[1] & 128) != 0) { - int fieldOffset8 = buf.getIntLE(offset + 195); - int pos8 = offset + 259 + fieldOffset8; + int fieldOffset8 = buf.getIntLE(offset + 196); + int pos8 = offset + 260 + fieldOffset8; int arrLen = VarInt.peek(buf, pos8); pos8 += VarInt.length(buf, pos8); @@ -900,8 +900,8 @@ public class BlockType { } if ((nullBits[2] & 1) != 0) { - int fieldOffset9 = buf.getIntLE(offset + 199); - int pos9 = offset + 259 + fieldOffset9; + int fieldOffset9 = buf.getIntLE(offset + 200); + int pos9 = offset + 260 + fieldOffset9; int sl = VarInt.peek(buf, pos9); pos9 += VarInt.length(buf, pos9) + sl; if (pos9 - offset > maxEnd) { @@ -910,8 +910,8 @@ public class BlockType { } if ((nullBits[2] & 2) != 0) { - int fieldOffset10 = buf.getIntLE(offset + 203); - int pos10 = offset + 259 + fieldOffset10; + int fieldOffset10 = buf.getIntLE(offset + 204); + int pos10 = offset + 260 + fieldOffset10; int arrLen = VarInt.peek(buf, pos10); pos10 += VarInt.length(buf, pos10); @@ -925,8 +925,8 @@ public class BlockType { } if ((nullBits[2] & 4) != 0) { - int fieldOffset11 = buf.getIntLE(offset + 207); - int pos11 = offset + 259 + fieldOffset11; + int fieldOffset11 = buf.getIntLE(offset + 208); + int pos11 = offset + 260 + fieldOffset11; int sl = VarInt.peek(buf, pos11); pos11 += VarInt.length(buf, pos11) + sl; if (pos11 - offset > maxEnd) { @@ -935,8 +935,8 @@ public class BlockType { } if ((nullBits[2] & 8) != 0) { - int fieldOffset12 = buf.getIntLE(offset + 211); - int pos12 = offset + 259 + fieldOffset12; + int fieldOffset12 = buf.getIntLE(offset + 212); + int pos12 = offset + 260 + fieldOffset12; int sl = VarInt.peek(buf, pos12); pos12 += VarInt.length(buf, pos12) + sl; if (pos12 - offset > maxEnd) { @@ -945,8 +945,8 @@ public class BlockType { } if ((nullBits[2] & 16) != 0) { - int fieldOffset13 = buf.getIntLE(offset + 215); - int pos13 = offset + 259 + fieldOffset13; + int fieldOffset13 = buf.getIntLE(offset + 216); + int pos13 = offset + 260 + fieldOffset13; int sl = VarInt.peek(buf, pos13); pos13 += VarInt.length(buf, pos13) + sl; if (pos13 - offset > maxEnd) { @@ -955,8 +955,8 @@ public class BlockType { } if ((nullBits[2] & 32) != 0) { - int fieldOffset14 = buf.getIntLE(offset + 219); - int pos14 = offset + 259 + fieldOffset14; + int fieldOffset14 = buf.getIntLE(offset + 220); + int pos14 = offset + 260 + fieldOffset14; int arrLen = VarInt.peek(buf, pos14); pos14 += VarInt.length(buf, pos14) + arrLen * 4; if (pos14 - offset > maxEnd) { @@ -965,8 +965,8 @@ public class BlockType { } if ((nullBits[2] & 64) != 0) { - int fieldOffset15 = buf.getIntLE(offset + 223); - int pos15 = offset + 259 + fieldOffset15; + int fieldOffset15 = buf.getIntLE(offset + 224); + int pos15 = offset + 260 + fieldOffset15; int sl = VarInt.peek(buf, pos15); pos15 += VarInt.length(buf, pos15) + sl; if (pos15 - offset > maxEnd) { @@ -975,8 +975,8 @@ public class BlockType { } if ((nullBits[2] & 128) != 0) { - int fieldOffset16 = buf.getIntLE(offset + 227); - int pos16 = offset + 259 + fieldOffset16; + int fieldOffset16 = buf.getIntLE(offset + 228); + int pos16 = offset + 260 + fieldOffset16; pos16 += BlockGathering.computeBytesConsumed(buf, pos16); if (pos16 - offset > maxEnd) { maxEnd = pos16 - offset; @@ -984,8 +984,8 @@ public class BlockType { } if ((nullBits[3] & 1) != 0) { - int fieldOffset17 = buf.getIntLE(offset + 231); - int pos17 = offset + 259 + fieldOffset17; + int fieldOffset17 = buf.getIntLE(offset + 232); + int pos17 = offset + 260 + fieldOffset17; pos17 += ModelDisplay.computeBytesConsumed(buf, pos17); if (pos17 - offset > maxEnd) { maxEnd = pos17 - offset; @@ -993,8 +993,8 @@ public class BlockType { } if ((nullBits[3] & 2) != 0) { - int fieldOffset18 = buf.getIntLE(offset + 235); - int pos18 = offset + 259 + fieldOffset18; + int fieldOffset18 = buf.getIntLE(offset + 236); + int pos18 = offset + 260 + fieldOffset18; pos18 += RailConfig.computeBytesConsumed(buf, pos18); if (pos18 - offset > maxEnd) { maxEnd = pos18 - offset; @@ -1002,8 +1002,8 @@ public class BlockType { } if ((nullBits[3] & 4) != 0) { - int fieldOffset19 = buf.getIntLE(offset + 239); - int pos19 = offset + 259 + fieldOffset19; + int fieldOffset19 = buf.getIntLE(offset + 240); + int pos19 = offset + 260 + fieldOffset19; int dictLen = VarInt.peek(buf, pos19); pos19 += VarInt.length(buf, pos19); @@ -1017,8 +1017,8 @@ public class BlockType { } if ((nullBits[3] & 8) != 0) { - int fieldOffset20 = buf.getIntLE(offset + 243); - int pos20 = offset + 259 + fieldOffset20; + int fieldOffset20 = buf.getIntLE(offset + 244); + int pos20 = offset + 260 + fieldOffset20; int dictLen = VarInt.peek(buf, pos20); pos20 += VarInt.length(buf, pos20); @@ -1034,8 +1034,8 @@ public class BlockType { } if ((nullBits[3] & 16) != 0) { - int fieldOffset21 = buf.getIntLE(offset + 247); - int pos21 = offset + 259 + fieldOffset21; + int fieldOffset21 = buf.getIntLE(offset + 248); + int pos21 = offset + 260 + fieldOffset21; int arrLen = VarInt.peek(buf, pos21); pos21 += VarInt.length(buf, pos21) + arrLen * 4; if (pos21 - offset > maxEnd) { @@ -1044,8 +1044,8 @@ public class BlockType { } if ((nullBits[3] & 32) != 0) { - int fieldOffset22 = buf.getIntLE(offset + 251); - int pos22 = offset + 259 + fieldOffset22; + int fieldOffset22 = buf.getIntLE(offset + 252); + int pos22 = offset + 260 + fieldOffset22; pos22 += Bench.computeBytesConsumed(buf, pos22); if (pos22 - offset > maxEnd) { maxEnd = pos22 - offset; @@ -1053,8 +1053,8 @@ public class BlockType { } if ((nullBits[3] & 64) != 0) { - int fieldOffset23 = buf.getIntLE(offset + 255); - int pos23 = offset + 259 + fieldOffset23; + int fieldOffset23 = buf.getIntLE(offset + 256); + int pos23 = offset + 260 + fieldOffset23; pos23 += ConnectedBlockRuleSet.computeBytesConsumed(buf, pos23); if (pos23 - offset > maxEnd) { maxEnd = pos23 - offset; @@ -1249,7 +1249,7 @@ public class BlockType { if (this.placementSettings != null) { this.placementSettings.serialize(buf); } else { - buf.writeZero(16); + buf.writeZero(17); } buf.writeByte(this.ignoreSupportWhenPlaced ? 1 : 0); @@ -1565,7 +1565,7 @@ public class BlockType { } public int computeSize() { - int size = 259; + int size = 260; if (this.item != null) { size += PacketIO.stringSize(this.item); } @@ -1702,17 +1702,17 @@ public class BlockType { } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 259) { - return ValidationResult.error("Buffer too small: expected at least 259 bytes"); + if (buffer.readableBytes() - offset < 260) { + return ValidationResult.error("Buffer too small: expected at least 260 bytes"); } else { byte[] nullBits = PacketIO.readBytes(buffer, offset, 4); if ((nullBits[0] & 128) != 0) { - int itemOffset = buffer.getIntLE(offset + 163); + int itemOffset = buffer.getIntLE(offset + 164); if (itemOffset < 0) { return ValidationResult.error("Invalid offset for Item"); } - int pos = offset + 259 + itemOffset; + int pos = offset + 260 + itemOffset; if (pos >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Item"); } @@ -1734,12 +1734,12 @@ public class BlockType { } if ((nullBits[1] & 1) != 0) { - int nameOffset = buffer.getIntLE(offset + 167); + int nameOffset = buffer.getIntLE(offset + 168); if (nameOffset < 0) { return ValidationResult.error("Invalid offset for Name"); } - int posx = offset + 259 + nameOffset; + int posx = offset + 260 + nameOffset; if (posx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Name"); } @@ -1761,12 +1761,12 @@ public class BlockType { } if ((nullBits[1] & 2) != 0) { - int shaderEffectOffset = buffer.getIntLE(offset + 171); + int shaderEffectOffset = buffer.getIntLE(offset + 172); if (shaderEffectOffset < 0) { return ValidationResult.error("Invalid offset for ShaderEffect"); } - int posxx = offset + 259 + shaderEffectOffset; + int posxx = offset + 260 + shaderEffectOffset; if (posxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for ShaderEffect"); } @@ -1788,12 +1788,12 @@ public class BlockType { } if ((nullBits[1] & 4) != 0) { - int modelOffset = buffer.getIntLE(offset + 175); + int modelOffset = buffer.getIntLE(offset + 176); if (modelOffset < 0) { return ValidationResult.error("Invalid offset for Model"); } - int posxxx = offset + 259 + modelOffset; + int posxxx = offset + 260 + modelOffset; if (posxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Model"); } @@ -1815,12 +1815,12 @@ public class BlockType { } if ((nullBits[1] & 8) != 0) { - int modelTextureOffset = buffer.getIntLE(offset + 179); + int modelTextureOffset = buffer.getIntLE(offset + 180); if (modelTextureOffset < 0) { return ValidationResult.error("Invalid offset for ModelTexture"); } - int posxxxx = offset + 259 + modelTextureOffset; + int posxxxx = offset + 260 + modelTextureOffset; if (posxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for ModelTexture"); } @@ -1847,12 +1847,12 @@ public class BlockType { } if ((nullBits[1] & 16) != 0) { - int modelAnimationOffset = buffer.getIntLE(offset + 183); + int modelAnimationOffset = buffer.getIntLE(offset + 184); if (modelAnimationOffset < 0) { return ValidationResult.error("Invalid offset for ModelAnimation"); } - int posxxxxx = offset + 259 + modelAnimationOffset; + int posxxxxx = offset + 260 + modelAnimationOffset; if (posxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for ModelAnimation"); } @@ -1874,12 +1874,12 @@ public class BlockType { } if ((nullBits[1] & 32) != 0) { - int supportOffset = buffer.getIntLE(offset + 187); + int supportOffset = buffer.getIntLE(offset + 188); if (supportOffset < 0) { return ValidationResult.error("Invalid offset for Support"); } - int posxxxxxx = offset + 259 + supportOffset; + int posxxxxxx = offset + 260 + supportOffset; if (posxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Support"); } @@ -1910,12 +1910,12 @@ public class BlockType { } if ((nullBits[1] & 64) != 0) { - int supportingOffset = buffer.getIntLE(offset + 191); + int supportingOffset = buffer.getIntLE(offset + 192); if (supportingOffset < 0) { return ValidationResult.error("Invalid offset for Supporting"); } - int posxxxxxxx = offset + 259 + supportingOffset; + int posxxxxxxx = offset + 260 + supportingOffset; if (posxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Supporting"); } @@ -1946,12 +1946,12 @@ public class BlockType { } if ((nullBits[1] & 128) != 0) { - int cubeTexturesOffset = buffer.getIntLE(offset + 195); + int cubeTexturesOffset = buffer.getIntLE(offset + 196); if (cubeTexturesOffset < 0) { return ValidationResult.error("Invalid offset for CubeTextures"); } - int posxxxxxxxx = offset + 259 + cubeTexturesOffset; + int posxxxxxxxx = offset + 260 + cubeTexturesOffset; if (posxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for CubeTextures"); } @@ -1978,12 +1978,12 @@ public class BlockType { } if ((nullBits[2] & 1) != 0) { - int cubeSideMaskTextureOffset = buffer.getIntLE(offset + 199); + int cubeSideMaskTextureOffset = buffer.getIntLE(offset + 200); if (cubeSideMaskTextureOffset < 0) { return ValidationResult.error("Invalid offset for CubeSideMaskTexture"); } - int posxxxxxxxxx = offset + 259 + cubeSideMaskTextureOffset; + int posxxxxxxxxx = offset + 260 + cubeSideMaskTextureOffset; if (posxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for CubeSideMaskTexture"); } @@ -2005,12 +2005,12 @@ public class BlockType { } if ((nullBits[2] & 2) != 0) { - int particlesOffset = buffer.getIntLE(offset + 203); + int particlesOffset = buffer.getIntLE(offset + 204); if (particlesOffset < 0) { return ValidationResult.error("Invalid offset for Particles"); } - int posxxxxxxxxxx = offset + 259 + particlesOffset; + int posxxxxxxxxxx = offset + 260 + particlesOffset; if (posxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Particles"); } @@ -2037,12 +2037,12 @@ public class BlockType { } if ((nullBits[2] & 4) != 0) { - int blockParticleSetIdOffset = buffer.getIntLE(offset + 207); + int blockParticleSetIdOffset = buffer.getIntLE(offset + 208); if (blockParticleSetIdOffset < 0) { return ValidationResult.error("Invalid offset for BlockParticleSetId"); } - int posxxxxxxxxxxx = offset + 259 + blockParticleSetIdOffset; + int posxxxxxxxxxxx = offset + 260 + blockParticleSetIdOffset; if (posxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for BlockParticleSetId"); } @@ -2064,12 +2064,12 @@ public class BlockType { } if ((nullBits[2] & 8) != 0) { - int blockBreakingDecalIdOffset = buffer.getIntLE(offset + 211); + int blockBreakingDecalIdOffset = buffer.getIntLE(offset + 212); if (blockBreakingDecalIdOffset < 0) { return ValidationResult.error("Invalid offset for BlockBreakingDecalId"); } - int posxxxxxxxxxxxx = offset + 259 + blockBreakingDecalIdOffset; + int posxxxxxxxxxxxx = offset + 260 + blockBreakingDecalIdOffset; if (posxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for BlockBreakingDecalId"); } @@ -2091,12 +2091,12 @@ public class BlockType { } if ((nullBits[2] & 16) != 0) { - int transitionTextureOffset = buffer.getIntLE(offset + 215); + int transitionTextureOffset = buffer.getIntLE(offset + 216); if (transitionTextureOffset < 0) { return ValidationResult.error("Invalid offset for TransitionTexture"); } - int posxxxxxxxxxxxxx = offset + 259 + transitionTextureOffset; + int posxxxxxxxxxxxxx = offset + 260 + transitionTextureOffset; if (posxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for TransitionTexture"); } @@ -2118,12 +2118,12 @@ public class BlockType { } if ((nullBits[2] & 32) != 0) { - int transitionToGroupsOffset = buffer.getIntLE(offset + 219); + int transitionToGroupsOffset = buffer.getIntLE(offset + 220); if (transitionToGroupsOffset < 0) { return ValidationResult.error("Invalid offset for TransitionToGroups"); } - int posxxxxxxxxxxxxxx = offset + 259 + transitionToGroupsOffset; + int posxxxxxxxxxxxxxx = offset + 260 + transitionToGroupsOffset; if (posxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for TransitionToGroups"); } @@ -2145,12 +2145,12 @@ public class BlockType { } if ((nullBits[2] & 64) != 0) { - int interactionHintOffset = buffer.getIntLE(offset + 223); + int interactionHintOffset = buffer.getIntLE(offset + 224); if (interactionHintOffset < 0) { return ValidationResult.error("Invalid offset for InteractionHint"); } - int posxxxxxxxxxxxxxxx = offset + 259 + interactionHintOffset; + int posxxxxxxxxxxxxxxx = offset + 260 + interactionHintOffset; if (posxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for InteractionHint"); } @@ -2172,12 +2172,12 @@ public class BlockType { } if ((nullBits[2] & 128) != 0) { - int gatheringOffset = buffer.getIntLE(offset + 227); + int gatheringOffset = buffer.getIntLE(offset + 228); if (gatheringOffset < 0) { return ValidationResult.error("Invalid offset for Gathering"); } - int posxxxxxxxxxxxxxxxx = offset + 259 + gatheringOffset; + int posxxxxxxxxxxxxxxxx = offset + 260 + gatheringOffset; if (posxxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Gathering"); } @@ -2191,12 +2191,12 @@ public class BlockType { } if ((nullBits[3] & 1) != 0) { - int displayOffset = buffer.getIntLE(offset + 231); + int displayOffset = buffer.getIntLE(offset + 232); if (displayOffset < 0) { return ValidationResult.error("Invalid offset for Display"); } - int posxxxxxxxxxxxxxxxxx = offset + 259 + displayOffset; + int posxxxxxxxxxxxxxxxxx = offset + 260 + displayOffset; if (posxxxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Display"); } @@ -2210,12 +2210,12 @@ public class BlockType { } if ((nullBits[3] & 2) != 0) { - int railOffset = buffer.getIntLE(offset + 235); + int railOffset = buffer.getIntLE(offset + 236); if (railOffset < 0) { return ValidationResult.error("Invalid offset for Rail"); } - int posxxxxxxxxxxxxxxxxxx = offset + 259 + railOffset; + int posxxxxxxxxxxxxxxxxxx = offset + 260 + railOffset; if (posxxxxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Rail"); } @@ -2229,12 +2229,12 @@ public class BlockType { } if ((nullBits[3] & 4) != 0) { - int interactionsOffset = buffer.getIntLE(offset + 239); + int interactionsOffset = buffer.getIntLE(offset + 240); if (interactionsOffset < 0) { return ValidationResult.error("Invalid offset for Interactions"); } - int posxxxxxxxxxxxxxxxxxxx = offset + 259 + interactionsOffset; + int posxxxxxxxxxxxxxxxxxxx = offset + 260 + interactionsOffset; if (posxxxxxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Interactions"); } @@ -2259,12 +2259,12 @@ public class BlockType { } if ((nullBits[3] & 8) != 0) { - int statesOffset = buffer.getIntLE(offset + 243); + int statesOffset = buffer.getIntLE(offset + 244); if (statesOffset < 0) { return ValidationResult.error("Invalid offset for States"); } - int posxxxxxxxxxxxxxxxxxxxx = offset + 259 + statesOffset; + int posxxxxxxxxxxxxxxxxxxxx = offset + 260 + statesOffset; if (posxxxxxxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for States"); } @@ -2304,12 +2304,12 @@ public class BlockType { } if ((nullBits[3] & 16) != 0) { - int tagIndexesOffset = buffer.getIntLE(offset + 247); + int tagIndexesOffset = buffer.getIntLE(offset + 248); if (tagIndexesOffset < 0) { return ValidationResult.error("Invalid offset for TagIndexes"); } - int posxxxxxxxxxxxxxxxxxxxxx = offset + 259 + tagIndexesOffset; + int posxxxxxxxxxxxxxxxxxxxxx = offset + 260 + tagIndexesOffset; if (posxxxxxxxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for TagIndexes"); } @@ -2331,12 +2331,12 @@ public class BlockType { } if ((nullBits[3] & 32) != 0) { - int benchOffset = buffer.getIntLE(offset + 251); + int benchOffset = buffer.getIntLE(offset + 252); if (benchOffset < 0) { return ValidationResult.error("Invalid offset for Bench"); } - int posxxxxxxxxxxxxxxxxxxxxxx = offset + 259 + benchOffset; + int posxxxxxxxxxxxxxxxxxxxxxx = offset + 260 + benchOffset; if (posxxxxxxxxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Bench"); } @@ -2350,12 +2350,12 @@ public class BlockType { } if ((nullBits[3] & 64) != 0) { - int connectedBlockRuleSetOffset = buffer.getIntLE(offset + 255); + int connectedBlockRuleSetOffset = buffer.getIntLE(offset + 256); if (connectedBlockRuleSetOffset < 0) { return ValidationResult.error("Invalid offset for ConnectedBlockRuleSet"); } - int posxxxxxxxxxxxxxxxxxxxxxxx = offset + 259 + connectedBlockRuleSetOffset; + int posxxxxxxxxxxxxxxxxxxxxxxx = offset + 260 + connectedBlockRuleSetOffset; if (posxxxxxxxxxxxxxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for ConnectedBlockRuleSet"); } diff --git a/src/com/hypixel/hytale/protocol/BlockUpdate.java b/src/com/hypixel/hytale/protocol/BlockUpdate.java new file mode 100644 index 00000000..44c27935 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/BlockUpdate.java @@ -0,0 +1,79 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; + +public class BlockUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 8; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 8; + public static final int MAX_SIZE = 8; + public int blockId; + public float entityScale; + + public BlockUpdate() { + } + + public BlockUpdate(int blockId, float entityScale) { + this.blockId = blockId; + this.entityScale = entityScale; + } + + public BlockUpdate(@Nonnull BlockUpdate other) { + this.blockId = other.blockId; + this.entityScale = other.entityScale; + } + + @Nonnull + public static BlockUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + BlockUpdate obj = new BlockUpdate(); + obj.blockId = buf.getIntLE(offset + 0); + obj.entityScale = buf.getFloatLE(offset + 4); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 8; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + buf.writeIntLE(this.blockId); + buf.writeFloatLE(this.entityScale); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 8; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 8 ? ValidationResult.error("Buffer too small: expected at least 8 bytes") : ValidationResult.OK; + } + + public BlockUpdate clone() { + BlockUpdate copy = new BlockUpdate(); + copy.blockId = this.blockId; + copy.entityScale = this.entityScale; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof BlockUpdate other) ? false : this.blockId == other.blockId && this.entityScale == other.entityScale; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.blockId, this.entityScale); + } +} diff --git a/src/com/hypixel/hytale/protocol/CachedPacket.java b/src/com/hypixel/hytale/protocol/CachedPacket.java index 86859f65..4f66f968 100644 --- a/src/com/hypixel/hytale/protocol/CachedPacket.java +++ b/src/com/hypixel/hytale/protocol/CachedPacket.java @@ -4,24 +4,26 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import javax.annotation.Nonnull; -public final class CachedPacket implements Packet, AutoCloseable { +public final class CachedPacket implements ToClientPacket, AutoCloseable { private final Class packetType; private final int packetId; + private final NetworkChannel packetChannel; private final ByteBuf cachedBytes; - private CachedPacket(Class packetType, int packetId, ByteBuf cachedBytes) { + private CachedPacket(Class packetType, int packetId, NetworkChannel packetChannel, ByteBuf cachedBytes) { this.packetType = packetType; this.packetId = packetId; + this.packetChannel = packetChannel; this.cachedBytes = cachedBytes; } - public static CachedPacket cache(@Nonnull T packet) { + public static CachedPacket cache(@Nonnull T packet) { if (packet instanceof CachedPacket) { throw new IllegalArgumentException("Cannot cache a CachedPacket"); } else { ByteBuf buf = Unpooled.buffer(); packet.serialize(buf); - return new CachedPacket<>((Class)packet.getClass(), packet.getId(), buf); + return new CachedPacket<>((Class)packet.getClass(), packet.getId(), packet.getChannel(), buf); } } @@ -30,6 +32,11 @@ public final class CachedPacket implements Packet, AutoCloseab return this.packetId; } + @Override + public NetworkChannel getChannel() { + return this.packetChannel; + } + @Override public void serialize(@Nonnull ByteBuf buf) { if (this.cachedBytes.refCnt() <= 0) { diff --git a/src/com/hypixel/hytale/protocol/CombatTextUpdate.java b/src/com/hypixel/hytale/protocol/CombatTextUpdate.java index e58bab3e..64226c32 100644 --- a/src/com/hypixel/hytale/protocol/CombatTextUpdate.java +++ b/src/com/hypixel/hytale/protocol/CombatTextUpdate.java @@ -7,22 +7,21 @@ 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 CombatTextUpdate { - public static final int NULLABLE_BIT_FIELD_SIZE = 1; - public static final int FIXED_BLOCK_SIZE = 5; +public class CombatTextUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 4; public static final int VARIABLE_FIELD_COUNT = 1; - public static final int VARIABLE_BLOCK_START = 5; - public static final int MAX_SIZE = 16384010; + public static final int VARIABLE_BLOCK_START = 4; + public static final int MAX_SIZE = 16384009; public float hitAngleDeg; - @Nullable - public String text; + @Nonnull + public String text = ""; public CombatTextUpdate() { } - public CombatTextUpdate(float hitAngleDeg, @Nullable String text) { + public CombatTextUpdate(float hitAngleDeg, @Nonnull String text) { this.hitAngleDeg = hitAngleDeg; this.text = text; } @@ -35,84 +34,57 @@ public class CombatTextUpdate { @Nonnull public static CombatTextUpdate deserialize(@Nonnull ByteBuf buf, int offset) { CombatTextUpdate obj = new CombatTextUpdate(); - byte nullBits = buf.getByte(offset); - obj.hitAngleDeg = buf.getFloatLE(offset + 1); - int pos = offset + 5; - if ((nullBits & 1) != 0) { - int textLen = VarInt.peek(buf, pos); - if (textLen < 0) { - throw ProtocolException.negativeLength("Text", textLen); - } - - if (textLen > 4096000) { - throw ProtocolException.stringTooLong("Text", textLen, 4096000); - } - + obj.hitAngleDeg = buf.getFloatLE(offset + 0); + int pos = offset + 4; + int textLen = VarInt.peek(buf, pos); + if (textLen < 0) { + throw ProtocolException.negativeLength("Text", textLen); + } else if (textLen > 4096000) { + throw ProtocolException.stringTooLong("Text", textLen, 4096000); + } else { int textVarLen = VarInt.length(buf, pos); obj.text = PacketIO.readVarString(buf, pos, PacketIO.UTF8); pos += textVarLen + textLen; + return obj; } - - 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; - } - + int pos = offset + 4; + int sl = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos) + sl; return pos - offset; } - public void serialize(@Nonnull ByteBuf buf) { - byte nullBits = 0; - if (this.text != null) { - nullBits = (byte)(nullBits | 1); - } - - buf.writeByte(nullBits); + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); buf.writeFloatLE(this.hitAngleDeg); - if (this.text != null) { - PacketIO.writeVarString(buf, this.text, 4096000); - } + PacketIO.writeVarString(buf, this.text, 4096000); + return buf.writerIndex() - startPos; } + @Override public int computeSize() { - int size = 5; - if (this.text != null) { - size += PacketIO.stringSize(this.text); - } - - return size; + int size = 4; + return size + PacketIO.stringSize(this.text); } 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"); + if (buffer.readableBytes() - offset < 4) { + return ValidationResult.error("Buffer too small: expected at least 4 bytes"); } else { - byte nullBits = buffer.getByte(offset); - int pos = offset + 5; - if ((nullBits & 1) != 0) { - int textLen = VarInt.peek(buffer, pos); - if (textLen < 0) { - return ValidationResult.error("Invalid string length for Text"); - } - - if (textLen > 4096000) { - return ValidationResult.error("Text exceeds max length 4096000"); - } - + int pos = offset + 4; + int textLen = VarInt.peek(buffer, pos); + if (textLen < 0) { + return ValidationResult.error("Invalid string length for Text"); + } else if (textLen > 4096000) { + return ValidationResult.error("Text exceeds max length 4096000"); + } else { pos += VarInt.length(buffer, pos); pos += textLen; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Text"); - } + return pos > buffer.writerIndex() ? ValidationResult.error("Buffer overflow reading Text") : ValidationResult.OK; } - - return ValidationResult.OK; } } diff --git a/src/com/hypixel/hytale/protocol/ComponentUpdate.java b/src/com/hypixel/hytale/protocol/ComponentUpdate.java index 838efbe5..618cf515 100644 --- a/src/com/hypixel/hytale/protocol/ComponentUpdate.java +++ b/src/com/hypixel/hytale/protocol/ComponentUpdate.java @@ -1,1363 +1,190 @@ 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.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import java.util.Map.Entry; import javax.annotation.Nonnull; -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 VARIABLE_FIELD_COUNT = 13; - public static final int VARIABLE_BLOCK_START = 211; - public static final int MAX_SIZE = 1677721600; - @Nonnull - public ComponentUpdateType type = ComponentUpdateType.Nameplate; - @Nullable - public Nameplate nameplate; - @Nullable - public int[] entityUIComponents; - @Nullable - public CombatTextUpdate combatTextUpdate; - @Nullable - public Model model; - @Nullable - public PlayerSkin skin; - @Nullable - public ItemWithAllMetadata item; - public int blockId; - public float entityScale; - @Nullable - public Equipment equipment; - @Nullable - public Map entityStatUpdates; - @Nullable - public ModelTransform transform; - @Nullable - public MovementStates movementStates; - @Nullable - public EntityEffectUpdate[] entityEffectUpdates; - @Nullable - public Map interactions; - @Nullable - public ColorLight dynamicLight; - public int hitboxCollisionConfigIndex; - public int repulsionConfigIndex; - @Nonnull - public UUID predictionId = new UUID(0L, 0L); - @Nullable - public int[] soundEventIds; - @Nullable - public String interactionHint; - @Nullable - public MountedUpdate mounted; - @Nullable - public String[] activeAnimations; - - public ComponentUpdate() { - } - - public ComponentUpdate( - @Nonnull ComponentUpdateType type, - @Nullable Nameplate nameplate, - @Nullable int[] entityUIComponents, - @Nullable CombatTextUpdate combatTextUpdate, - @Nullable Model model, - @Nullable PlayerSkin skin, - @Nullable ItemWithAllMetadata item, - int blockId, - float entityScale, - @Nullable Equipment equipment, - @Nullable Map entityStatUpdates, - @Nullable ModelTransform transform, - @Nullable MovementStates movementStates, - @Nullable EntityEffectUpdate[] entityEffectUpdates, - @Nullable Map interactions, - @Nullable ColorLight dynamicLight, - int hitboxCollisionConfigIndex, - int repulsionConfigIndex, - @Nonnull UUID predictionId, - @Nullable int[] soundEventIds, - @Nullable String interactionHint, - @Nullable MountedUpdate mounted, - @Nullable String[] activeAnimations - ) { - this.type = type; - this.nameplate = nameplate; - this.entityUIComponents = entityUIComponents; - this.combatTextUpdate = combatTextUpdate; - this.model = model; - this.skin = skin; - this.item = item; - this.blockId = blockId; - this.entityScale = entityScale; - this.equipment = equipment; - this.entityStatUpdates = entityStatUpdates; - this.transform = transform; - this.movementStates = movementStates; - this.entityEffectUpdates = entityEffectUpdates; - this.interactions = interactions; - this.dynamicLight = dynamicLight; - this.hitboxCollisionConfigIndex = hitboxCollisionConfigIndex; - this.repulsionConfigIndex = repulsionConfigIndex; - this.predictionId = predictionId; - this.soundEventIds = soundEventIds; - this.interactionHint = interactionHint; - this.mounted = mounted; - this.activeAnimations = activeAnimations; - } - - public ComponentUpdate(@Nonnull ComponentUpdate other) { - this.type = other.type; - this.nameplate = other.nameplate; - this.entityUIComponents = other.entityUIComponents; - this.combatTextUpdate = other.combatTextUpdate; - this.model = other.model; - this.skin = other.skin; - this.item = other.item; - this.blockId = other.blockId; - this.entityScale = other.entityScale; - this.equipment = other.equipment; - this.entityStatUpdates = other.entityStatUpdates; - this.transform = other.transform; - this.movementStates = other.movementStates; - this.entityEffectUpdates = other.entityEffectUpdates; - this.interactions = other.interactions; - this.dynamicLight = other.dynamicLight; - this.hitboxCollisionConfigIndex = other.hitboxCollisionConfigIndex; - this.repulsionConfigIndex = other.repulsionConfigIndex; - this.predictionId = other.predictionId; - this.soundEventIds = other.soundEventIds; - this.interactionHint = other.interactionHint; - this.mounted = other.mounted; - this.activeAnimations = other.activeAnimations; - } +public abstract class ComponentUpdate { + public static final int MAX_SIZE = 1677721605; @Nonnull public static ComponentUpdate deserialize(@Nonnull ByteBuf buf, int offset) { - ComponentUpdate obj = new ComponentUpdate(); - byte[] nullBits = PacketIO.readBytes(buf, offset, 3); - obj.type = ComponentUpdateType.fromValue(buf.getByte(offset + 3)); - obj.blockId = buf.getIntLE(offset + 4); - obj.entityScale = buf.getFloatLE(offset + 8); - if ((nullBits[0] & 1) != 0) { - obj.transform = ModelTransform.deserialize(buf, offset + 12); - } + int typeId = VarInt.peek(buf, offset); + int typeIdLen = VarInt.length(buf, offset); - if ((nullBits[0] & 2) != 0) { - obj.movementStates = MovementStates.deserialize(buf, offset + 61); - } - - if ((nullBits[0] & 4) != 0) { - obj.dynamicLight = ColorLight.deserialize(buf, offset + 83); - } - - obj.hitboxCollisionConfigIndex = buf.getIntLE(offset + 87); - obj.repulsionConfigIndex = buf.getIntLE(offset + 91); - obj.predictionId = PacketIO.readUUID(buf, offset + 95); - if ((nullBits[0] & 8) != 0) { - obj.mounted = MountedUpdate.deserialize(buf, offset + 111); - } - - if ((nullBits[0] & 16) != 0) { - int varPos0 = offset + 211 + buf.getIntLE(offset + 159); - obj.nameplate = Nameplate.deserialize(buf, varPos0); - } - - if ((nullBits[0] & 32) != 0) { - int varPos1 = offset + 211 + buf.getIntLE(offset + 163); - int entityUIComponentsCount = VarInt.peek(buf, varPos1); - if (entityUIComponentsCount < 0) { - throw ProtocolException.negativeLength("EntityUIComponents", entityUIComponentsCount); - } - - if (entityUIComponentsCount > 4096000) { - throw ProtocolException.arrayTooLong("EntityUIComponents", entityUIComponentsCount, 4096000); - } - - int varIntLen = VarInt.length(buf, varPos1); - if (varPos1 + varIntLen + entityUIComponentsCount * 4L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall("EntityUIComponents", varPos1 + varIntLen + entityUIComponentsCount * 4, buf.readableBytes()); - } - - obj.entityUIComponents = new int[entityUIComponentsCount]; - - for (int i = 0; i < entityUIComponentsCount; i++) { - obj.entityUIComponents[i] = buf.getIntLE(varPos1 + varIntLen + i * 4); - } - } - - if ((nullBits[0] & 64) != 0) { - int varPos2 = offset + 211 + buf.getIntLE(offset + 167); - obj.combatTextUpdate = CombatTextUpdate.deserialize(buf, varPos2); - } - - if ((nullBits[0] & 128) != 0) { - int varPos3 = offset + 211 + buf.getIntLE(offset + 171); - obj.model = Model.deserialize(buf, varPos3); - } - - if ((nullBits[1] & 1) != 0) { - int varPos4 = offset + 211 + buf.getIntLE(offset + 175); - obj.skin = PlayerSkin.deserialize(buf, varPos4); - } - - if ((nullBits[1] & 2) != 0) { - int varPos5 = offset + 211 + buf.getIntLE(offset + 179); - obj.item = ItemWithAllMetadata.deserialize(buf, varPos5); - } - - if ((nullBits[1] & 4) != 0) { - int varPos6 = offset + 211 + buf.getIntLE(offset + 183); - obj.equipment = Equipment.deserialize(buf, varPos6); - } - - if ((nullBits[1] & 8) != 0) { - int varPos7 = offset + 211 + buf.getIntLE(offset + 187); - int entityStatUpdatesCount = VarInt.peek(buf, varPos7); - if (entityStatUpdatesCount < 0) { - throw ProtocolException.negativeLength("EntityStatUpdates", entityStatUpdatesCount); - } - - if (entityStatUpdatesCount > 4096000) { - throw ProtocolException.dictionaryTooLarge("EntityStatUpdates", entityStatUpdatesCount, 4096000); - } - - int varIntLen = VarInt.length(buf, varPos7); - obj.entityStatUpdates = new HashMap<>(entityStatUpdatesCount); - int dictPos = varPos7 + varIntLen; - - for (int i = 0; i < entityStatUpdatesCount; i++) { - int key = buf.getIntLE(dictPos); - dictPos += 4; - int valLen = VarInt.peek(buf, dictPos); - if (valLen < 0) { - throw ProtocolException.negativeLength("val", valLen); - } - - if (valLen > 64) { - throw ProtocolException.arrayTooLong("val", valLen, 64); - } - - int valVarLen = VarInt.length(buf, dictPos); - if (dictPos + valVarLen + valLen * 13L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall("val", dictPos + valVarLen + valLen * 13, buf.readableBytes()); - } - - dictPos += valVarLen; - EntityStatUpdate[] val = new EntityStatUpdate[valLen]; - - for (int valIdx = 0; valIdx < valLen; valIdx++) { - val[valIdx] = EntityStatUpdate.deserialize(buf, dictPos); - dictPos += EntityStatUpdate.computeBytesConsumed(buf, dictPos); - } - - if (obj.entityStatUpdates.put(key, val) != null) { - throw ProtocolException.duplicateKey("entityStatUpdates", key); - } - } - } - - if ((nullBits[1] & 16) != 0) { - int varPos8 = offset + 211 + buf.getIntLE(offset + 191); - int entityEffectUpdatesCount = VarInt.peek(buf, varPos8); - if (entityEffectUpdatesCount < 0) { - throw ProtocolException.negativeLength("EntityEffectUpdates", entityEffectUpdatesCount); - } - - if (entityEffectUpdatesCount > 4096000) { - throw ProtocolException.arrayTooLong("EntityEffectUpdates", entityEffectUpdatesCount, 4096000); - } - - int varIntLen = VarInt.length(buf, varPos8); - if (varPos8 + varIntLen + entityEffectUpdatesCount * 12L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall("EntityEffectUpdates", varPos8 + varIntLen + entityEffectUpdatesCount * 12, buf.readableBytes()); - } - - obj.entityEffectUpdates = new EntityEffectUpdate[entityEffectUpdatesCount]; - int elemPos = varPos8 + varIntLen; - - for (int i = 0; i < entityEffectUpdatesCount; i++) { - obj.entityEffectUpdates[i] = EntityEffectUpdate.deserialize(buf, elemPos); - elemPos += EntityEffectUpdate.computeBytesConsumed(buf, elemPos); - } - } - - if ((nullBits[1] & 32) != 0) { - int varPos9 = offset + 211 + buf.getIntLE(offset + 195); - int interactionsCount = VarInt.peek(buf, varPos9); - if (interactionsCount < 0) { - throw ProtocolException.negativeLength("Interactions", interactionsCount); - } - - if (interactionsCount > 4096000) { - throw ProtocolException.dictionaryTooLarge("Interactions", interactionsCount, 4096000); - } - - int varIntLen = VarInt.length(buf, varPos9); - obj.interactions = new HashMap<>(interactionsCount); - int dictPos = varPos9 + varIntLen; - - for (int i = 0; i < interactionsCount; i++) { - InteractionType keyx = InteractionType.fromValue(buf.getByte(dictPos)); - int val = buf.getIntLE(++dictPos); - dictPos += 4; - if (obj.interactions.put(keyx, val) != null) { - throw ProtocolException.duplicateKey("interactions", keyx); - } - } - } - - if ((nullBits[1] & 64) != 0) { - int varPos10 = offset + 211 + buf.getIntLE(offset + 199); - int soundEventIdsCount = VarInt.peek(buf, varPos10); - if (soundEventIdsCount < 0) { - throw ProtocolException.negativeLength("SoundEventIds", soundEventIdsCount); - } - - if (soundEventIdsCount > 4096000) { - throw ProtocolException.arrayTooLong("SoundEventIds", soundEventIdsCount, 4096000); - } - - int varIntLen = VarInt.length(buf, varPos10); - if (varPos10 + varIntLen + soundEventIdsCount * 4L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall("SoundEventIds", varPos10 + varIntLen + soundEventIdsCount * 4, buf.readableBytes()); - } - - obj.soundEventIds = new int[soundEventIdsCount]; - - for (int ix = 0; ix < soundEventIdsCount; ix++) { - obj.soundEventIds[ix] = buf.getIntLE(varPos10 + varIntLen + ix * 4); - } - } - - if ((nullBits[1] & 128) != 0) { - int varPos11 = offset + 211 + buf.getIntLE(offset + 203); - int interactionHintLen = VarInt.peek(buf, varPos11); - if (interactionHintLen < 0) { - throw ProtocolException.negativeLength("InteractionHint", interactionHintLen); - } - - if (interactionHintLen > 4096000) { - throw ProtocolException.stringTooLong("InteractionHint", interactionHintLen, 4096000); - } - - obj.interactionHint = PacketIO.readVarString(buf, varPos11, PacketIO.UTF8); - } - - if ((nullBits[2] & 1) != 0) { - int varPos12 = offset + 211 + buf.getIntLE(offset + 207); - int activeAnimationsCount = VarInt.peek(buf, varPos12); - if (activeAnimationsCount < 0) { - throw ProtocolException.negativeLength("ActiveAnimations", activeAnimationsCount); - } - - if (activeAnimationsCount > 4096000) { - throw ProtocolException.arrayTooLong("ActiveAnimations", activeAnimationsCount, 4096000); - } - - int varIntLen = VarInt.length(buf, varPos12); - int activeAnimationsBitfieldSize = (activeAnimationsCount + 7) / 8; - byte[] activeAnimationsBitfield = PacketIO.readBytes(buf, varPos12 + varIntLen, activeAnimationsBitfieldSize); - obj.activeAnimations = new String[activeAnimationsCount]; - int elemPos = varPos12 + varIntLen + activeAnimationsBitfieldSize; - - for (int ix = 0; ix < activeAnimationsCount; ix++) { - if ((activeAnimationsBitfield[ix / 8] & 1 << ix % 8) != 0) { - int strLen = VarInt.peek(buf, elemPos); - if (strLen < 0) { - throw ProtocolException.negativeLength("activeAnimations[" + ix + "]", strLen); - } - - if (strLen > 4096000) { - throw ProtocolException.stringTooLong("activeAnimations[" + ix + "]", strLen, 4096000); - } - - int strVarLen = VarInt.length(buf, elemPos); - obj.activeAnimations[ix] = PacketIO.readVarString(buf, elemPos); - elemPos += strVarLen + strLen; - } - } - } - - return obj; + return (ComponentUpdate)(switch (typeId) { + case 0 -> NameplateUpdate.deserialize(buf, offset + typeIdLen); + case 1 -> UIComponentsUpdate.deserialize(buf, offset + typeIdLen); + case 2 -> CombatTextUpdate.deserialize(buf, offset + typeIdLen); + case 3 -> ModelUpdate.deserialize(buf, offset + typeIdLen); + case 4 -> PlayerSkinUpdate.deserialize(buf, offset + typeIdLen); + case 5 -> ItemUpdate.deserialize(buf, offset + typeIdLen); + case 6 -> BlockUpdate.deserialize(buf, offset + typeIdLen); + case 7 -> EquipmentUpdate.deserialize(buf, offset + typeIdLen); + case 8 -> EntityStatsUpdate.deserialize(buf, offset + typeIdLen); + case 9 -> TransformUpdate.deserialize(buf, offset + typeIdLen); + case 10 -> MovementStatesUpdate.deserialize(buf, offset + typeIdLen); + case 11 -> EntityEffectsUpdate.deserialize(buf, offset + typeIdLen); + case 12 -> InteractionsUpdate.deserialize(buf, offset + typeIdLen); + case 13 -> DynamicLightUpdate.deserialize(buf, offset + typeIdLen); + case 14 -> InteractableUpdate.deserialize(buf, offset + typeIdLen); + case 15 -> IntangibleUpdate.deserialize(buf, offset + typeIdLen); + case 16 -> InvulnerableUpdate.deserialize(buf, offset + typeIdLen); + case 17 -> RespondToHitUpdate.deserialize(buf, offset + typeIdLen); + case 18 -> HitboxCollisionUpdate.deserialize(buf, offset + typeIdLen); + case 19 -> RepulsionUpdate.deserialize(buf, offset + typeIdLen); + case 20 -> PredictionUpdate.deserialize(buf, offset + typeIdLen); + case 21 -> AudioUpdate.deserialize(buf, offset + typeIdLen); + case 22 -> MountedUpdate.deserialize(buf, offset + typeIdLen); + case 23 -> NewSpawnUpdate.deserialize(buf, offset + typeIdLen); + case 24 -> ActiveAnimationsUpdate.deserialize(buf, offset + typeIdLen); + case 25 -> PropUpdate.deserialize(buf, offset + typeIdLen); + default -> throw ProtocolException.unknownPolymorphicType("ComponentUpdate", typeId); + }); } public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { - byte[] nullBits = PacketIO.readBytes(buf, offset, 3); - int maxEnd = 211; - if ((nullBits[0] & 16) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 159); - int pos0 = offset + 211 + fieldOffset0; - pos0 += Nameplate.computeBytesConsumed(buf, pos0); - if (pos0 - offset > maxEnd) { - maxEnd = pos0 - offset; - } - } + int typeId = VarInt.peek(buf, offset); + int typeIdLen = VarInt.length(buf, offset); - if ((nullBits[0] & 32) != 0) { - int fieldOffset1 = buf.getIntLE(offset + 163); - int pos1 = offset + 211 + fieldOffset1; - int arrLen = VarInt.peek(buf, pos1); - pos1 += VarInt.length(buf, pos1) + arrLen * 4; - if (pos1 - offset > maxEnd) { - maxEnd = pos1 - offset; - } - } - - if ((nullBits[0] & 64) != 0) { - int fieldOffset2 = buf.getIntLE(offset + 167); - int pos2 = offset + 211 + fieldOffset2; - pos2 += CombatTextUpdate.computeBytesConsumed(buf, pos2); - if (pos2 - offset > maxEnd) { - maxEnd = pos2 - offset; - } - } - - if ((nullBits[0] & 128) != 0) { - int fieldOffset3 = buf.getIntLE(offset + 171); - int pos3 = offset + 211 + fieldOffset3; - pos3 += Model.computeBytesConsumed(buf, pos3); - if (pos3 - offset > maxEnd) { - maxEnd = pos3 - offset; - } - } - - if ((nullBits[1] & 1) != 0) { - int fieldOffset4 = buf.getIntLE(offset + 175); - int pos4 = offset + 211 + fieldOffset4; - pos4 += PlayerSkin.computeBytesConsumed(buf, pos4); - if (pos4 - offset > maxEnd) { - maxEnd = pos4 - offset; - } - } - - if ((nullBits[1] & 2) != 0) { - int fieldOffset5 = buf.getIntLE(offset + 179); - int pos5 = offset + 211 + fieldOffset5; - pos5 += ItemWithAllMetadata.computeBytesConsumed(buf, pos5); - if (pos5 - offset > maxEnd) { - maxEnd = pos5 - offset; - } - } - - if ((nullBits[1] & 4) != 0) { - int fieldOffset6 = buf.getIntLE(offset + 183); - int pos6 = offset + 211 + fieldOffset6; - pos6 += Equipment.computeBytesConsumed(buf, pos6); - if (pos6 - offset > maxEnd) { - maxEnd = pos6 - offset; - } - } - - if ((nullBits[1] & 8) != 0) { - int fieldOffset7 = buf.getIntLE(offset + 187); - int pos7 = offset + 211 + fieldOffset7; - int dictLen = VarInt.peek(buf, pos7); - pos7 += VarInt.length(buf, pos7); - - for (int i = 0; i < dictLen; i++) { - pos7 += 4; - int al = VarInt.peek(buf, pos7); - pos7 += VarInt.length(buf, pos7); - - for (int j = 0; j < al; j++) { - pos7 += EntityStatUpdate.computeBytesConsumed(buf, pos7); - } - } - - if (pos7 - offset > maxEnd) { - maxEnd = pos7 - offset; - } - } - - if ((nullBits[1] & 16) != 0) { - int fieldOffset8 = buf.getIntLE(offset + 191); - int pos8 = offset + 211 + fieldOffset8; - int arrLen = VarInt.peek(buf, pos8); - pos8 += VarInt.length(buf, pos8); - - for (int i = 0; i < arrLen; i++) { - pos8 += EntityEffectUpdate.computeBytesConsumed(buf, pos8); - } - - if (pos8 - offset > maxEnd) { - maxEnd = pos8 - offset; - } - } - - if ((nullBits[1] & 32) != 0) { - int fieldOffset9 = buf.getIntLE(offset + 195); - int pos9 = offset + 211 + fieldOffset9; - int dictLen = VarInt.peek(buf, pos9); - pos9 += VarInt.length(buf, pos9); - - for (int i = 0; i < dictLen; i++) { - pos9 = ++pos9 + 4; - } - - if (pos9 - offset > maxEnd) { - maxEnd = pos9 - offset; - } - } - - if ((nullBits[1] & 64) != 0) { - int fieldOffset10 = buf.getIntLE(offset + 199); - int pos10 = offset + 211 + fieldOffset10; - int arrLen = VarInt.peek(buf, pos10); - pos10 += VarInt.length(buf, pos10) + arrLen * 4; - if (pos10 - offset > maxEnd) { - maxEnd = pos10 - offset; - } - } - - if ((nullBits[1] & 128) != 0) { - int fieldOffset11 = buf.getIntLE(offset + 203); - int pos11 = offset + 211 + fieldOffset11; - int sl = VarInt.peek(buf, pos11); - pos11 += VarInt.length(buf, pos11) + sl; - if (pos11 - offset > maxEnd) { - maxEnd = pos11 - offset; - } - } - - if ((nullBits[2] & 1) != 0) { - int fieldOffset12 = buf.getIntLE(offset + 207); - int pos12 = offset + 211 + fieldOffset12; - int arrLen = VarInt.peek(buf, pos12); - pos12 += VarInt.length(buf, pos12); - int bitfieldSize = (arrLen + 7) / 8; - byte[] bitfield = PacketIO.readBytes(buf, pos12, bitfieldSize); - pos12 += bitfieldSize; - - for (int i = 0; i < arrLen; i++) { - if ((bitfield[i / 8] & 1 << i % 8) != 0) { - int sl = VarInt.peek(buf, pos12); - pos12 += VarInt.length(buf, pos12) + sl; - } - } - - if (pos12 - offset > maxEnd) { - maxEnd = pos12 - offset; - } - } - - return maxEnd; + return typeIdLen + switch (typeId) { + case 0 -> NameplateUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 1 -> UIComponentsUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 2 -> CombatTextUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 3 -> ModelUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 4 -> PlayerSkinUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 5 -> ItemUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 6 -> BlockUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 7 -> EquipmentUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 8 -> EntityStatsUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 9 -> TransformUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 10 -> MovementStatesUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 11 -> EntityEffectsUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 12 -> InteractionsUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 13 -> DynamicLightUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 14 -> InteractableUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 15 -> IntangibleUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 16 -> InvulnerableUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 17 -> RespondToHitUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 18 -> HitboxCollisionUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 19 -> RepulsionUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 20 -> PredictionUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 21 -> AudioUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 22 -> MountedUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 23 -> NewSpawnUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 24 -> ActiveAnimationsUpdate.computeBytesConsumed(buf, offset + typeIdLen); + case 25 -> PropUpdate.computeBytesConsumed(buf, offset + typeIdLen); + default -> throw ProtocolException.unknownPolymorphicType("ComponentUpdate", typeId); + }; } - public void serialize(@Nonnull ByteBuf buf) { + public int getTypeId() { + if (this instanceof NameplateUpdate sub) { + return 0; + } else if (this instanceof UIComponentsUpdate sub) { + return 1; + } else if (this instanceof CombatTextUpdate sub) { + return 2; + } else if (this instanceof ModelUpdate sub) { + return 3; + } else if (this instanceof PlayerSkinUpdate sub) { + return 4; + } else if (this instanceof ItemUpdate sub) { + return 5; + } else if (this instanceof BlockUpdate sub) { + return 6; + } else if (this instanceof EquipmentUpdate sub) { + return 7; + } else if (this instanceof EntityStatsUpdate sub) { + return 8; + } else if (this instanceof TransformUpdate sub) { + return 9; + } else if (this instanceof MovementStatesUpdate sub) { + return 10; + } else if (this instanceof EntityEffectsUpdate sub) { + return 11; + } else if (this instanceof InteractionsUpdate sub) { + return 12; + } else if (this instanceof DynamicLightUpdate sub) { + return 13; + } else if (this instanceof InteractableUpdate sub) { + return 14; + } else if (this instanceof IntangibleUpdate sub) { + return 15; + } else if (this instanceof InvulnerableUpdate sub) { + return 16; + } else if (this instanceof RespondToHitUpdate sub) { + return 17; + } else if (this instanceof HitboxCollisionUpdate sub) { + return 18; + } else if (this instanceof RepulsionUpdate sub) { + return 19; + } else if (this instanceof PredictionUpdate sub) { + return 20; + } else if (this instanceof AudioUpdate sub) { + return 21; + } else if (this instanceof MountedUpdate sub) { + return 22; + } else if (this instanceof NewSpawnUpdate sub) { + return 23; + } else if (this instanceof ActiveAnimationsUpdate sub) { + return 24; + } else if (this instanceof PropUpdate sub) { + return 25; + } 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(); - byte[] nullBits = new byte[3]; - if (this.transform != null) { - nullBits[0] = (byte)(nullBits[0] | 1); - } - - if (this.movementStates != null) { - nullBits[0] = (byte)(nullBits[0] | 2); - } - - if (this.dynamicLight != null) { - nullBits[0] = (byte)(nullBits[0] | 4); - } - - if (this.mounted != null) { - nullBits[0] = (byte)(nullBits[0] | 8); - } - - if (this.nameplate != null) { - nullBits[0] = (byte)(nullBits[0] | 16); - } - - if (this.entityUIComponents != null) { - nullBits[0] = (byte)(nullBits[0] | 32); - } - - if (this.combatTextUpdate != null) { - nullBits[0] = (byte)(nullBits[0] | 64); - } - - if (this.model != null) { - nullBits[0] = (byte)(nullBits[0] | 128); - } - - if (this.skin != null) { - nullBits[1] = (byte)(nullBits[1] | 1); - } - - if (this.item != null) { - nullBits[1] = (byte)(nullBits[1] | 2); - } - - if (this.equipment != null) { - nullBits[1] = (byte)(nullBits[1] | 4); - } - - if (this.entityStatUpdates != null) { - nullBits[1] = (byte)(nullBits[1] | 8); - } - - if (this.entityEffectUpdates != null) { - nullBits[1] = (byte)(nullBits[1] | 16); - } - - if (this.interactions != null) { - nullBits[1] = (byte)(nullBits[1] | 32); - } - - if (this.soundEventIds != null) { - nullBits[1] = (byte)(nullBits[1] | 64); - } - - if (this.interactionHint != null) { - nullBits[1] = (byte)(nullBits[1] | 128); - } - - if (this.activeAnimations != null) { - nullBits[2] = (byte)(nullBits[2] | 1); - } - - buf.writeBytes(nullBits); - buf.writeByte(this.type.getValue()); - buf.writeIntLE(this.blockId); - buf.writeFloatLE(this.entityScale); - if (this.transform != null) { - this.transform.serialize(buf); - } else { - buf.writeZero(49); - } - - if (this.movementStates != null) { - this.movementStates.serialize(buf); - } else { - buf.writeZero(22); - } - - if (this.dynamicLight != null) { - this.dynamicLight.serialize(buf); - } else { - buf.writeZero(4); - } - - buf.writeIntLE(this.hitboxCollisionConfigIndex); - buf.writeIntLE(this.repulsionConfigIndex); - PacketIO.writeUUID(buf, this.predictionId); - if (this.mounted != null) { - this.mounted.serialize(buf); - } else { - buf.writeZero(48); - } - - int nameplateOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int entityUIComponentsOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int combatTextUpdateOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int modelOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int skinOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int itemOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int equipmentOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int entityStatUpdatesOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int entityEffectUpdatesOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int interactionsOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int soundEventIdsOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int interactionHintOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int activeAnimationsOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int varBlockStart = buf.writerIndex(); - if (this.nameplate != null) { - buf.setIntLE(nameplateOffsetSlot, buf.writerIndex() - varBlockStart); - this.nameplate.serialize(buf); - } else { - buf.setIntLE(nameplateOffsetSlot, -1); - } - - if (this.entityUIComponents != null) { - buf.setIntLE(entityUIComponentsOffsetSlot, buf.writerIndex() - varBlockStart); - if (this.entityUIComponents.length > 4096000) { - throw ProtocolException.arrayTooLong("EntityUIComponents", this.entityUIComponents.length, 4096000); - } - - VarInt.write(buf, this.entityUIComponents.length); - - for (int item : this.entityUIComponents) { - buf.writeIntLE(item); - } - } else { - buf.setIntLE(entityUIComponentsOffsetSlot, -1); - } - - if (this.combatTextUpdate != null) { - buf.setIntLE(combatTextUpdateOffsetSlot, buf.writerIndex() - varBlockStart); - this.combatTextUpdate.serialize(buf); - } else { - buf.setIntLE(combatTextUpdateOffsetSlot, -1); - } - - if (this.model != null) { - buf.setIntLE(modelOffsetSlot, buf.writerIndex() - varBlockStart); - this.model.serialize(buf); - } else { - buf.setIntLE(modelOffsetSlot, -1); - } - - if (this.skin != null) { - buf.setIntLE(skinOffsetSlot, buf.writerIndex() - varBlockStart); - this.skin.serialize(buf); - } else { - buf.setIntLE(skinOffsetSlot, -1); - } - - if (this.item != null) { - buf.setIntLE(itemOffsetSlot, buf.writerIndex() - varBlockStart); - this.item.serialize(buf); - } else { - buf.setIntLE(itemOffsetSlot, -1); - } - - if (this.equipment != null) { - buf.setIntLE(equipmentOffsetSlot, buf.writerIndex() - varBlockStart); - this.equipment.serialize(buf); - } else { - buf.setIntLE(equipmentOffsetSlot, -1); - } - - if (this.entityStatUpdates != null) { - buf.setIntLE(entityStatUpdatesOffsetSlot, buf.writerIndex() - varBlockStart); - if (this.entityStatUpdates.size() > 4096000) { - throw ProtocolException.dictionaryTooLarge("EntityStatUpdates", this.entityStatUpdates.size(), 4096000); - } - - VarInt.write(buf, this.entityStatUpdates.size()); - - for (Entry e : this.entityStatUpdates.entrySet()) { - buf.writeIntLE(e.getKey()); - VarInt.write(buf, e.getValue().length); - - for (EntityStatUpdate arrItem : e.getValue()) { - arrItem.serialize(buf); - } - } - } else { - buf.setIntLE(entityStatUpdatesOffsetSlot, -1); - } - - if (this.entityEffectUpdates != null) { - buf.setIntLE(entityEffectUpdatesOffsetSlot, buf.writerIndex() - varBlockStart); - if (this.entityEffectUpdates.length > 4096000) { - throw ProtocolException.arrayTooLong("EntityEffectUpdates", this.entityEffectUpdates.length, 4096000); - } - - VarInt.write(buf, this.entityEffectUpdates.length); - - for (EntityEffectUpdate item : this.entityEffectUpdates) { - item.serialize(buf); - } - } else { - buf.setIntLE(entityEffectUpdatesOffsetSlot, -1); - } - - if (this.interactions != null) { - buf.setIntLE(interactionsOffsetSlot, buf.writerIndex() - varBlockStart); - if (this.interactions.size() > 4096000) { - throw ProtocolException.dictionaryTooLarge("Interactions", this.interactions.size(), 4096000); - } - - VarInt.write(buf, this.interactions.size()); - - for (Entry e : this.interactions.entrySet()) { - buf.writeByte(e.getKey().getValue()); - buf.writeIntLE(e.getValue()); - } - } else { - buf.setIntLE(interactionsOffsetSlot, -1); - } - - if (this.soundEventIds != null) { - buf.setIntLE(soundEventIdsOffsetSlot, buf.writerIndex() - varBlockStart); - if (this.soundEventIds.length > 4096000) { - throw ProtocolException.arrayTooLong("SoundEventIds", this.soundEventIds.length, 4096000); - } - - VarInt.write(buf, this.soundEventIds.length); - - for (int item : this.soundEventIds) { - buf.writeIntLE(item); - } - } else { - buf.setIntLE(soundEventIdsOffsetSlot, -1); - } - - if (this.interactionHint != null) { - buf.setIntLE(interactionHintOffsetSlot, buf.writerIndex() - varBlockStart); - PacketIO.writeVarString(buf, this.interactionHint, 4096000); - } else { - buf.setIntLE(interactionHintOffsetSlot, -1); - } - - if (this.activeAnimations != null) { - buf.setIntLE(activeAnimationsOffsetSlot, buf.writerIndex() - varBlockStart); - if (this.activeAnimations.length > 4096000) { - throw ProtocolException.arrayTooLong("ActiveAnimations", this.activeAnimations.length, 4096000); - } - - VarInt.write(buf, this.activeAnimations.length); - int activeAnimationsBitfieldSize = (this.activeAnimations.length + 7) / 8; - byte[] activeAnimationsBitfield = new byte[activeAnimationsBitfieldSize]; - - for (int i = 0; i < this.activeAnimations.length; i++) { - if (this.activeAnimations[i] != null) { - activeAnimationsBitfield[i / 8] = (byte)(activeAnimationsBitfield[i / 8] | (byte)(1 << i % 8)); - } - } - - buf.writeBytes(activeAnimationsBitfield); - - for (int ix = 0; ix < this.activeAnimations.length; ix++) { - if (this.activeAnimations[ix] != null) { - PacketIO.writeVarString(buf, this.activeAnimations[ix], 4096000); - } - } - } else { - buf.setIntLE(activeAnimationsOffsetSlot, -1); - } + VarInt.write(buf, this.getTypeId()); + this.serialize(buf); + return buf.writerIndex() - startPos; } - public int computeSize() { - int size = 211; - if (this.nameplate != null) { - size += this.nameplate.computeSize(); - } - - if (this.entityUIComponents != null) { - size += VarInt.size(this.entityUIComponents.length) + this.entityUIComponents.length * 4; - } - - if (this.combatTextUpdate != null) { - size += this.combatTextUpdate.computeSize(); - } - - if (this.model != null) { - size += this.model.computeSize(); - } - - if (this.skin != null) { - size += this.skin.computeSize(); - } - - if (this.item != null) { - size += this.item.computeSize(); - } - - if (this.equipment != null) { - size += this.equipment.computeSize(); - } - - if (this.entityStatUpdates != null) { - int entityStatUpdatesSize = 0; - - for (Entry kvp : this.entityStatUpdates.entrySet()) { - entityStatUpdatesSize += 4 + VarInt.size(kvp.getValue().length) + Arrays.stream(kvp.getValue()).mapToInt(inner -> inner.computeSize()).sum(); - } - - size += VarInt.size(this.entityStatUpdates.size()) + entityStatUpdatesSize; - } - - if (this.entityEffectUpdates != null) { - int entityEffectUpdatesSize = 0; - - for (EntityEffectUpdate elem : this.entityEffectUpdates) { - entityEffectUpdatesSize += elem.computeSize(); - } - - size += VarInt.size(this.entityEffectUpdates.length) + entityEffectUpdatesSize; - } - - if (this.interactions != null) { - size += VarInt.size(this.interactions.size()) + this.interactions.size() * 5; - } - - if (this.soundEventIds != null) { - size += VarInt.size(this.soundEventIds.length) + this.soundEventIds.length * 4; - } - - if (this.interactionHint != null) { - size += PacketIO.stringSize(this.interactionHint); - } - - if (this.activeAnimations != null) { - int activeAnimationsSize = 0; - - for (String elem : this.activeAnimations) { - if (elem != null) { - activeAnimationsSize += PacketIO.stringSize(elem); - } - } - - size += VarInt.size(this.activeAnimations.length) + (this.activeAnimations.length + 7) / 8 + activeAnimationsSize; - } - - return size; + public int computeSizeWithTypeId() { + return VarInt.size(this.getTypeId()) + this.computeSize(); } 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"); - } else { - byte[] nullBits = PacketIO.readBytes(buffer, offset, 3); - if ((nullBits[0] & 16) != 0) { - int nameplateOffset = buffer.getIntLE(offset + 159); - if (nameplateOffset < 0) { - return ValidationResult.error("Invalid offset for Nameplate"); - } - - int pos = offset + 211 + nameplateOffset; - if (pos >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Nameplate"); - } - - ValidationResult nameplateResult = Nameplate.validateStructure(buffer, pos); - if (!nameplateResult.isValid()) { - return ValidationResult.error("Invalid Nameplate: " + nameplateResult.error()); - } - - pos += Nameplate.computeBytesConsumed(buffer, pos); - } - - if ((nullBits[0] & 32) != 0) { - int entityUIComponentsOffset = buffer.getIntLE(offset + 163); - if (entityUIComponentsOffset < 0) { - return ValidationResult.error("Invalid offset for EntityUIComponents"); - } - - int posx = offset + 211 + entityUIComponentsOffset; - if (posx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for EntityUIComponents"); - } - - int entityUIComponentsCount = VarInt.peek(buffer, posx); - if (entityUIComponentsCount < 0) { - return ValidationResult.error("Invalid array count for EntityUIComponents"); - } - - if (entityUIComponentsCount > 4096000) { - return ValidationResult.error("EntityUIComponents exceeds max length 4096000"); - } - - posx += VarInt.length(buffer, posx); - posx += entityUIComponentsCount * 4; - if (posx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading EntityUIComponents"); - } - } - - if ((nullBits[0] & 64) != 0) { - int combatTextUpdateOffset = buffer.getIntLE(offset + 167); - if (combatTextUpdateOffset < 0) { - return ValidationResult.error("Invalid offset for CombatTextUpdate"); - } - - int posxx = offset + 211 + combatTextUpdateOffset; - if (posxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for CombatTextUpdate"); - } - - ValidationResult combatTextUpdateResult = CombatTextUpdate.validateStructure(buffer, posxx); - if (!combatTextUpdateResult.isValid()) { - return ValidationResult.error("Invalid CombatTextUpdate: " + combatTextUpdateResult.error()); - } - - posxx += CombatTextUpdate.computeBytesConsumed(buffer, posxx); - } - - if ((nullBits[0] & 128) != 0) { - int modelOffset = buffer.getIntLE(offset + 171); - if (modelOffset < 0) { - return ValidationResult.error("Invalid offset for Model"); - } - - int posxxx = offset + 211 + modelOffset; - if (posxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Model"); - } - - ValidationResult modelResult = Model.validateStructure(buffer, posxxx); - if (!modelResult.isValid()) { - return ValidationResult.error("Invalid Model: " + modelResult.error()); - } - - posxxx += Model.computeBytesConsumed(buffer, posxxx); - } - - if ((nullBits[1] & 1) != 0) { - int skinOffset = buffer.getIntLE(offset + 175); - if (skinOffset < 0) { - return ValidationResult.error("Invalid offset for Skin"); - } - - int posxxxx = offset + 211 + skinOffset; - if (posxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Skin"); - } - - ValidationResult skinResult = PlayerSkin.validateStructure(buffer, posxxxx); - if (!skinResult.isValid()) { - return ValidationResult.error("Invalid Skin: " + skinResult.error()); - } - - posxxxx += PlayerSkin.computeBytesConsumed(buffer, posxxxx); - } - - if ((nullBits[1] & 2) != 0) { - int itemOffset = buffer.getIntLE(offset + 179); - if (itemOffset < 0) { - return ValidationResult.error("Invalid offset for Item"); - } - - int posxxxxx = offset + 211 + itemOffset; - if (posxxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Item"); - } - - ValidationResult itemResult = ItemWithAllMetadata.validateStructure(buffer, posxxxxx); - if (!itemResult.isValid()) { - return ValidationResult.error("Invalid Item: " + itemResult.error()); - } - - posxxxxx += ItemWithAllMetadata.computeBytesConsumed(buffer, posxxxxx); - } - - if ((nullBits[1] & 4) != 0) { - int equipmentOffset = buffer.getIntLE(offset + 183); - if (equipmentOffset < 0) { - return ValidationResult.error("Invalid offset for Equipment"); - } - - int posxxxxxx = offset + 211 + equipmentOffset; - if (posxxxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Equipment"); - } - - ValidationResult equipmentResult = Equipment.validateStructure(buffer, posxxxxxx); - if (!equipmentResult.isValid()) { - return ValidationResult.error("Invalid Equipment: " + equipmentResult.error()); - } - - posxxxxxx += Equipment.computeBytesConsumed(buffer, posxxxxxx); - } - - if ((nullBits[1] & 8) != 0) { - int entityStatUpdatesOffset = buffer.getIntLE(offset + 187); - if (entityStatUpdatesOffset < 0) { - return ValidationResult.error("Invalid offset for EntityStatUpdates"); - } - - int posxxxxxxx = offset + 211 + entityStatUpdatesOffset; - if (posxxxxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for EntityStatUpdates"); - } - - int entityStatUpdatesCount = VarInt.peek(buffer, posxxxxxxx); - if (entityStatUpdatesCount < 0) { - return ValidationResult.error("Invalid dictionary count for EntityStatUpdates"); - } - - if (entityStatUpdatesCount > 4096000) { - return ValidationResult.error("EntityStatUpdates exceeds max length 4096000"); - } - - posxxxxxxx += VarInt.length(buffer, posxxxxxxx); - - for (int i = 0; i < entityStatUpdatesCount; i++) { - posxxxxxxx += 4; - if (posxxxxxxx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading key"); - } - - int valueArrCount = VarInt.peek(buffer, posxxxxxxx); - if (valueArrCount < 0) { - return ValidationResult.error("Invalid array count for value"); - } - - posxxxxxxx += VarInt.length(buffer, posxxxxxxx); - - for (int valueArrIdx = 0; valueArrIdx < valueArrCount; valueArrIdx++) { - posxxxxxxx += EntityStatUpdate.computeBytesConsumed(buffer, posxxxxxxx); - } - } - } - - if ((nullBits[1] & 16) != 0) { - int entityEffectUpdatesOffset = buffer.getIntLE(offset + 191); - if (entityEffectUpdatesOffset < 0) { - return ValidationResult.error("Invalid offset for EntityEffectUpdates"); - } - - int posxxxxxxxx = offset + 211 + entityEffectUpdatesOffset; - if (posxxxxxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for EntityEffectUpdates"); - } - - int entityEffectUpdatesCount = VarInt.peek(buffer, posxxxxxxxx); - if (entityEffectUpdatesCount < 0) { - return ValidationResult.error("Invalid array count for EntityEffectUpdates"); - } - - if (entityEffectUpdatesCount > 4096000) { - return ValidationResult.error("EntityEffectUpdates exceeds max length 4096000"); - } - - posxxxxxxxx += VarInt.length(buffer, posxxxxxxxx); - - for (int i = 0; i < entityEffectUpdatesCount; i++) { - ValidationResult structResult = EntityEffectUpdate.validateStructure(buffer, posxxxxxxxx); - if (!structResult.isValid()) { - return ValidationResult.error("Invalid EntityEffectUpdate in EntityEffectUpdates[" + i + "]: " + structResult.error()); - } - - posxxxxxxxx += EntityEffectUpdate.computeBytesConsumed(buffer, posxxxxxxxx); - } - } - - if ((nullBits[1] & 32) != 0) { - int interactionsOffset = buffer.getIntLE(offset + 195); - if (interactionsOffset < 0) { - return ValidationResult.error("Invalid offset for Interactions"); - } - - int posxxxxxxxxx = offset + 211 + interactionsOffset; - if (posxxxxxxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Interactions"); - } - - int interactionsCount = VarInt.peek(buffer, posxxxxxxxxx); - if (interactionsCount < 0) { - return ValidationResult.error("Invalid dictionary count for Interactions"); - } - - if (interactionsCount > 4096000) { - return ValidationResult.error("Interactions exceeds max length 4096000"); - } - - posxxxxxxxxx += VarInt.length(buffer, posxxxxxxxxx); - - for (int i = 0; i < interactionsCount; i++) { - posxxxxxxxxx = ++posxxxxxxxxx + 4; - if (posxxxxxxxxx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading value"); - } - } - } - - if ((nullBits[1] & 64) != 0) { - int soundEventIdsOffset = buffer.getIntLE(offset + 199); - if (soundEventIdsOffset < 0) { - return ValidationResult.error("Invalid offset for SoundEventIds"); - } - - int posxxxxxxxxxx = offset + 211 + soundEventIdsOffset; - if (posxxxxxxxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for SoundEventIds"); - } - - int soundEventIdsCount = VarInt.peek(buffer, posxxxxxxxxxx); - if (soundEventIdsCount < 0) { - return ValidationResult.error("Invalid array count for SoundEventIds"); - } - - if (soundEventIdsCount > 4096000) { - return ValidationResult.error("SoundEventIds exceeds max length 4096000"); - } - - posxxxxxxxxxx += VarInt.length(buffer, posxxxxxxxxxx); - posxxxxxxxxxx += soundEventIdsCount * 4; - if (posxxxxxxxxxx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading SoundEventIds"); - } - } - - if ((nullBits[1] & 128) != 0) { - int interactionHintOffset = buffer.getIntLE(offset + 203); - if (interactionHintOffset < 0) { - return ValidationResult.error("Invalid offset for InteractionHint"); - } - - int posxxxxxxxxxxx = offset + 211 + interactionHintOffset; - if (posxxxxxxxxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for InteractionHint"); - } - - int interactionHintLen = VarInt.peek(buffer, posxxxxxxxxxxx); - if (interactionHintLen < 0) { - return ValidationResult.error("Invalid string length for InteractionHint"); - } - - if (interactionHintLen > 4096000) { - return ValidationResult.error("InteractionHint exceeds max length 4096000"); - } - - posxxxxxxxxxxx += VarInt.length(buffer, posxxxxxxxxxxx); - posxxxxxxxxxxx += interactionHintLen; - if (posxxxxxxxxxxx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading InteractionHint"); - } - } - - if ((nullBits[2] & 1) != 0) { - int activeAnimationsOffset = buffer.getIntLE(offset + 207); - if (activeAnimationsOffset < 0) { - return ValidationResult.error("Invalid offset for ActiveAnimations"); - } - - int posxxxxxxxxxxxx = offset + 211 + activeAnimationsOffset; - if (posxxxxxxxxxxxx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for ActiveAnimations"); - } - - int activeAnimationsCount = VarInt.peek(buffer, posxxxxxxxxxxxx); - if (activeAnimationsCount < 0) { - return ValidationResult.error("Invalid array count for ActiveAnimations"); - } - - if (activeAnimationsCount > 4096000) { - return ValidationResult.error("ActiveAnimations exceeds max length 4096000"); - } - - posxxxxxxxxxxxx += VarInt.length(buffer, posxxxxxxxxxxxx); - - for (int ix = 0; ix < activeAnimationsCount; ix++) { - int strLen = VarInt.peek(buffer, posxxxxxxxxxxxx); - if (strLen < 0) { - return ValidationResult.error("Invalid string length in ActiveAnimations"); - } - - posxxxxxxxxxxxx += VarInt.length(buffer, posxxxxxxxxxxxx); - posxxxxxxxxxxxx += strLen; - if (posxxxxxxxxxxxx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading string in ActiveAnimations"); - } - } - } - - return ValidationResult.OK; - } - } - - public ComponentUpdate clone() { - ComponentUpdate copy = new ComponentUpdate(); - copy.type = this.type; - copy.nameplate = this.nameplate != null ? this.nameplate.clone() : null; - copy.entityUIComponents = this.entityUIComponents != null ? Arrays.copyOf(this.entityUIComponents, this.entityUIComponents.length) : null; - copy.combatTextUpdate = this.combatTextUpdate != null ? this.combatTextUpdate.clone() : null; - copy.model = this.model != null ? this.model.clone() : null; - copy.skin = this.skin != null ? this.skin.clone() : null; - copy.item = this.item != null ? this.item.clone() : null; - copy.blockId = this.blockId; - copy.entityScale = this.entityScale; - copy.equipment = this.equipment != null ? this.equipment.clone() : null; - if (this.entityStatUpdates != null) { - Map m = new HashMap<>(); - - for (Entry e : this.entityStatUpdates.entrySet()) { - m.put(e.getKey(), Arrays.stream(e.getValue()).map(x -> x.clone()).toArray(EntityStatUpdate[]::new)); - } - - copy.entityStatUpdates = m; - } - - copy.transform = this.transform != null ? this.transform.clone() : null; - copy.movementStates = this.movementStates != null ? this.movementStates.clone() : null; - copy.entityEffectUpdates = this.entityEffectUpdates != null - ? Arrays.stream(this.entityEffectUpdates).map(ex -> ex.clone()).toArray(EntityEffectUpdate[]::new) - : null; - copy.interactions = this.interactions != null ? new HashMap<>(this.interactions) : null; - copy.dynamicLight = this.dynamicLight != null ? this.dynamicLight.clone() : null; - copy.hitboxCollisionConfigIndex = this.hitboxCollisionConfigIndex; - copy.repulsionConfigIndex = this.repulsionConfigIndex; - copy.predictionId = this.predictionId; - copy.soundEventIds = this.soundEventIds != null ? Arrays.copyOf(this.soundEventIds, this.soundEventIds.length) : null; - 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; - return copy; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } else { - return !(obj instanceof ComponentUpdate other) - ? false - : Objects.equals(this.type, other.type) - && Objects.equals(this.nameplate, other.nameplate) - && Arrays.equals(this.entityUIComponents, other.entityUIComponents) - && Objects.equals(this.combatTextUpdate, other.combatTextUpdate) - && Objects.equals(this.model, other.model) - && Objects.equals(this.skin, other.skin) - && Objects.equals(this.item, other.item) - && this.blockId == other.blockId - && this.entityScale == other.entityScale - && Objects.equals(this.equipment, other.equipment) - && Objects.equals(this.entityStatUpdates, other.entityStatUpdates) - && Objects.equals(this.transform, other.transform) - && Objects.equals(this.movementStates, other.movementStates) - && Arrays.equals((Object[])this.entityEffectUpdates, (Object[])other.entityEffectUpdates) - && Objects.equals(this.interactions, other.interactions) - && Objects.equals(this.dynamicLight, other.dynamicLight) - && this.hitboxCollisionConfigIndex == other.hitboxCollisionConfigIndex - && this.repulsionConfigIndex == other.repulsionConfigIndex - && Objects.equals(this.predictionId, other.predictionId) - && 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); - } - } - - @Override - public int hashCode() { - int result = 1; - result = 31 * result + Objects.hashCode(this.type); - result = 31 * result + Objects.hashCode(this.nameplate); - result = 31 * result + Arrays.hashCode(this.entityUIComponents); - result = 31 * result + Objects.hashCode(this.combatTextUpdate); - result = 31 * result + Objects.hashCode(this.model); - result = 31 * result + Objects.hashCode(this.skin); - result = 31 * result + Objects.hashCode(this.item); - result = 31 * result + Integer.hashCode(this.blockId); - result = 31 * result + Float.hashCode(this.entityScale); - result = 31 * result + Objects.hashCode(this.equipment); - result = 31 * result + Objects.hashCode(this.entityStatUpdates); - result = 31 * result + Objects.hashCode(this.transform); - result = 31 * result + Objects.hashCode(this.movementStates); - result = 31 * result + Arrays.hashCode((Object[])this.entityEffectUpdates); - result = 31 * result + Objects.hashCode(this.interactions); - result = 31 * result + Objects.hashCode(this.dynamicLight); - result = 31 * result + Integer.hashCode(this.hitboxCollisionConfigIndex); - result = 31 * result + Integer.hashCode(this.repulsionConfigIndex); - result = 31 * result + Objects.hashCode(this.predictionId); - 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); + int typeId = VarInt.peek(buffer, offset); + int typeIdLen = VarInt.length(buffer, offset); + + return switch (typeId) { + case 0 -> NameplateUpdate.validateStructure(buffer, offset + typeIdLen); + case 1 -> UIComponentsUpdate.validateStructure(buffer, offset + typeIdLen); + case 2 -> CombatTextUpdate.validateStructure(buffer, offset + typeIdLen); + case 3 -> ModelUpdate.validateStructure(buffer, offset + typeIdLen); + case 4 -> PlayerSkinUpdate.validateStructure(buffer, offset + typeIdLen); + case 5 -> ItemUpdate.validateStructure(buffer, offset + typeIdLen); + case 6 -> BlockUpdate.validateStructure(buffer, offset + typeIdLen); + case 7 -> EquipmentUpdate.validateStructure(buffer, offset + typeIdLen); + case 8 -> EntityStatsUpdate.validateStructure(buffer, offset + typeIdLen); + case 9 -> TransformUpdate.validateStructure(buffer, offset + typeIdLen); + case 10 -> MovementStatesUpdate.validateStructure(buffer, offset + typeIdLen); + case 11 -> EntityEffectsUpdate.validateStructure(buffer, offset + typeIdLen); + case 12 -> InteractionsUpdate.validateStructure(buffer, offset + typeIdLen); + case 13 -> DynamicLightUpdate.validateStructure(buffer, offset + typeIdLen); + case 14 -> InteractableUpdate.validateStructure(buffer, offset + typeIdLen); + case 15 -> IntangibleUpdate.validateStructure(buffer, offset + typeIdLen); + case 16 -> InvulnerableUpdate.validateStructure(buffer, offset + typeIdLen); + case 17 -> RespondToHitUpdate.validateStructure(buffer, offset + typeIdLen); + case 18 -> HitboxCollisionUpdate.validateStructure(buffer, offset + typeIdLen); + case 19 -> RepulsionUpdate.validateStructure(buffer, offset + typeIdLen); + case 20 -> PredictionUpdate.validateStructure(buffer, offset + typeIdLen); + case 21 -> AudioUpdate.validateStructure(buffer, offset + typeIdLen); + case 22 -> MountedUpdate.validateStructure(buffer, offset + typeIdLen); + case 23 -> NewSpawnUpdate.validateStructure(buffer, offset + typeIdLen); + case 24 -> ActiveAnimationsUpdate.validateStructure(buffer, offset + typeIdLen); + case 25 -> PropUpdate.validateStructure(buffer, offset + typeIdLen); + default -> ValidationResult.error("Unknown polymorphic type ID " + typeId + " for ComponentUpdate"); + }; } } 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/DebugShape.java b/src/com/hypixel/hytale/protocol/DebugShape.java index f2756293..1b77bdb5 100644 --- a/src/com/hypixel/hytale/protocol/DebugShape.java +++ b/src/com/hypixel/hytale/protocol/DebugShape.java @@ -7,7 +7,9 @@ public enum DebugShape { Cylinder(1), Cone(2), Cube(3), - Frustum(4); + Frustum(4), + Sector(5), + Disc(6); public static final DebugShape[] VALUES = values(); private final int value; diff --git a/src/com/hypixel/hytale/protocol/DynamicLightUpdate.java b/src/com/hypixel/hytale/protocol/DynamicLightUpdate.java new file mode 100644 index 00000000..dad76a9d --- /dev/null +++ b/src/com/hypixel/hytale/protocol/DynamicLightUpdate.java @@ -0,0 +1,74 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; + +public class DynamicLightUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 4; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 4; + public static final int MAX_SIZE = 4; + @Nonnull + public ColorLight dynamicLight = new ColorLight(); + + public DynamicLightUpdate() { + } + + public DynamicLightUpdate(@Nonnull ColorLight dynamicLight) { + this.dynamicLight = dynamicLight; + } + + public DynamicLightUpdate(@Nonnull DynamicLightUpdate other) { + this.dynamicLight = other.dynamicLight; + } + + @Nonnull + public static DynamicLightUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + DynamicLightUpdate obj = new DynamicLightUpdate(); + obj.dynamicLight = ColorLight.deserialize(buf, offset + 0); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 4; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + this.dynamicLight.serialize(buf); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 4; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 4 ? ValidationResult.error("Buffer too small: expected at least 4 bytes") : ValidationResult.OK; + } + + public DynamicLightUpdate clone() { + DynamicLightUpdate copy = new DynamicLightUpdate(); + copy.dynamicLight = this.dynamicLight.clone(); + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof DynamicLightUpdate other ? Objects.equals(this.dynamicLight, other.dynamicLight) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.dynamicLight); + } +} diff --git a/src/com/hypixel/hytale/protocol/EntityEffectsUpdate.java b/src/com/hypixel/hytale/protocol/EntityEffectsUpdate.java new file mode 100644 index 00000000..9cb51e13 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/EntityEffectsUpdate.java @@ -0,0 +1,144 @@ +package com.hypixel.hytale.protocol; + +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.Arrays; +import javax.annotation.Nonnull; + +public class EntityEffectsUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 1677721600; + @Nonnull + public EntityEffectUpdate[] entityEffectUpdates = new EntityEffectUpdate[0]; + + public EntityEffectsUpdate() { + } + + public EntityEffectsUpdate(@Nonnull EntityEffectUpdate[] entityEffectUpdates) { + this.entityEffectUpdates = entityEffectUpdates; + } + + public EntityEffectsUpdate(@Nonnull EntityEffectsUpdate other) { + this.entityEffectUpdates = other.entityEffectUpdates; + } + + @Nonnull + public static EntityEffectsUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + EntityEffectsUpdate obj = new EntityEffectsUpdate(); + int pos = offset + 0; + int entityEffectUpdatesCount = VarInt.peek(buf, pos); + if (entityEffectUpdatesCount < 0) { + throw ProtocolException.negativeLength("EntityEffectUpdates", entityEffectUpdatesCount); + } else if (entityEffectUpdatesCount > 4096000) { + throw ProtocolException.arrayTooLong("EntityEffectUpdates", entityEffectUpdatesCount, 4096000); + } else { + int entityEffectUpdatesVarLen = VarInt.size(entityEffectUpdatesCount); + if (pos + entityEffectUpdatesVarLen + entityEffectUpdatesCount * 12L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("EntityEffectUpdates", pos + entityEffectUpdatesVarLen + entityEffectUpdatesCount * 12, buf.readableBytes()); + } else { + pos += entityEffectUpdatesVarLen; + obj.entityEffectUpdates = new EntityEffectUpdate[entityEffectUpdatesCount]; + + for (int i = 0; i < entityEffectUpdatesCount; i++) { + obj.entityEffectUpdates[i] = EntityEffectUpdate.deserialize(buf, pos); + pos += EntityEffectUpdate.computeBytesConsumed(buf, pos); + } + + return obj; + } + } + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int pos = offset + 0; + int arrLen = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos); + + for (int i = 0; i < arrLen; i++) { + pos += EntityEffectUpdate.computeBytesConsumed(buf, pos); + } + + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + if (this.entityEffectUpdates.length > 4096000) { + throw ProtocolException.arrayTooLong("EntityEffectUpdates", this.entityEffectUpdates.length, 4096000); + } else { + VarInt.write(buf, this.entityEffectUpdates.length); + + for (EntityEffectUpdate item : this.entityEffectUpdates) { + item.serialize(buf); + } + + return buf.writerIndex() - startPos; + } + } + + @Override + public int computeSize() { + int size = 0; + int entityEffectUpdatesSize = 0; + + for (EntityEffectUpdate elem : this.entityEffectUpdates) { + entityEffectUpdatesSize += elem.computeSize(); + } + + return size + VarInt.size(this.entityEffectUpdates.length) + entityEffectUpdatesSize; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 0) { + return ValidationResult.error("Buffer too small: expected at least 0 bytes"); + } else { + int pos = offset + 0; + int entityEffectUpdatesCount = VarInt.peek(buffer, pos); + if (entityEffectUpdatesCount < 0) { + return ValidationResult.error("Invalid array count for EntityEffectUpdates"); + } else if (entityEffectUpdatesCount > 4096000) { + return ValidationResult.error("EntityEffectUpdates exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + + for (int i = 0; i < entityEffectUpdatesCount; i++) { + ValidationResult structResult = EntityEffectUpdate.validateStructure(buffer, pos); + if (!structResult.isValid()) { + return ValidationResult.error("Invalid EntityEffectUpdate in EntityEffectUpdates[" + i + "]: " + structResult.error()); + } + + pos += EntityEffectUpdate.computeBytesConsumed(buffer, pos); + } + + return ValidationResult.OK; + } + } + } + + public EntityEffectsUpdate clone() { + EntityEffectsUpdate copy = new EntityEffectsUpdate(); + copy.entityEffectUpdates = Arrays.stream(this.entityEffectUpdates).map(e -> e.clone()).toArray(EntityEffectUpdate[]::new); + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof EntityEffectsUpdate other ? Arrays.equals((Object[])this.entityEffectUpdates, (Object[])other.entityEffectUpdates) : false; + } + } + + @Override + public int hashCode() { + int result = 1; + return 31 * result + Arrays.hashCode((Object[])this.entityEffectUpdates); + } +} diff --git a/src/com/hypixel/hytale/protocol/EntityStatType.java b/src/com/hypixel/hytale/protocol/EntityStatType.java index 5d72ac67..42e0b972 100644 --- a/src/com/hypixel/hytale/protocol/EntityStatType.java +++ b/src/com/hypixel/hytale/protocol/EntityStatType.java @@ -11,9 +11,9 @@ import javax.annotation.Nullable; public class EntityStatType { public static final int NULLABLE_BIT_FIELD_SIZE = 1; - public static final int FIXED_BLOCK_SIZE = 14; + public static final int FIXED_BLOCK_SIZE = 15; public static final int VARIABLE_FIELD_COUNT = 3; - public static final int VARIABLE_BLOCK_START = 26; + public static final int VARIABLE_BLOCK_START = 27; public static final int MAX_SIZE = 1677721600; @Nullable public String id; @@ -26,6 +26,7 @@ public class EntityStatType { public EntityStatEffects maxValueEffects; @Nonnull public EntityStatResetBehavior resetBehavior = EntityStatResetBehavior.InitialValue; + public boolean hideFromTooltip; public EntityStatType() { } @@ -37,7 +38,8 @@ public class EntityStatType { float max, @Nullable EntityStatEffects minValueEffects, @Nullable EntityStatEffects maxValueEffects, - @Nonnull EntityStatResetBehavior resetBehavior + @Nonnull EntityStatResetBehavior resetBehavior, + boolean hideFromTooltip ) { this.id = id; this.value = value; @@ -46,6 +48,7 @@ public class EntityStatType { this.minValueEffects = minValueEffects; this.maxValueEffects = maxValueEffects; this.resetBehavior = resetBehavior; + this.hideFromTooltip = hideFromTooltip; } public EntityStatType(@Nonnull EntityStatType other) { @@ -56,6 +59,7 @@ public class EntityStatType { this.minValueEffects = other.minValueEffects; this.maxValueEffects = other.maxValueEffects; this.resetBehavior = other.resetBehavior; + this.hideFromTooltip = other.hideFromTooltip; } @Nonnull @@ -66,8 +70,9 @@ public class EntityStatType { obj.min = buf.getFloatLE(offset + 5); obj.max = buf.getFloatLE(offset + 9); obj.resetBehavior = EntityStatResetBehavior.fromValue(buf.getByte(offset + 13)); + obj.hideFromTooltip = buf.getByte(offset + 14) != 0; if ((nullBits & 1) != 0) { - int varPos0 = offset + 26 + buf.getIntLE(offset + 14); + int varPos0 = offset + 27 + buf.getIntLE(offset + 15); int idLen = VarInt.peek(buf, varPos0); if (idLen < 0) { throw ProtocolException.negativeLength("Id", idLen); @@ -81,12 +86,12 @@ public class EntityStatType { } if ((nullBits & 2) != 0) { - int varPos1 = offset + 26 + buf.getIntLE(offset + 18); + int varPos1 = offset + 27 + buf.getIntLE(offset + 19); obj.minValueEffects = EntityStatEffects.deserialize(buf, varPos1); } if ((nullBits & 4) != 0) { - int varPos2 = offset + 26 + buf.getIntLE(offset + 22); + int varPos2 = offset + 27 + buf.getIntLE(offset + 23); obj.maxValueEffects = EntityStatEffects.deserialize(buf, varPos2); } @@ -95,10 +100,10 @@ public class EntityStatType { public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte nullBits = buf.getByte(offset); - int maxEnd = 26; + int maxEnd = 27; if ((nullBits & 1) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 14); - int pos0 = offset + 26 + fieldOffset0; + int fieldOffset0 = buf.getIntLE(offset + 15); + int pos0 = offset + 27 + fieldOffset0; int sl = VarInt.peek(buf, pos0); pos0 += VarInt.length(buf, pos0) + sl; if (pos0 - offset > maxEnd) { @@ -107,8 +112,8 @@ public class EntityStatType { } if ((nullBits & 2) != 0) { - int fieldOffset1 = buf.getIntLE(offset + 18); - int pos1 = offset + 26 + fieldOffset1; + int fieldOffset1 = buf.getIntLE(offset + 19); + int pos1 = offset + 27 + fieldOffset1; pos1 += EntityStatEffects.computeBytesConsumed(buf, pos1); if (pos1 - offset > maxEnd) { maxEnd = pos1 - offset; @@ -116,8 +121,8 @@ public class EntityStatType { } if ((nullBits & 4) != 0) { - int fieldOffset2 = buf.getIntLE(offset + 22); - int pos2 = offset + 26 + fieldOffset2; + int fieldOffset2 = buf.getIntLE(offset + 23); + int pos2 = offset + 27 + fieldOffset2; pos2 += EntityStatEffects.computeBytesConsumed(buf, pos2); if (pos2 - offset > maxEnd) { maxEnd = pos2 - offset; @@ -147,6 +152,7 @@ public class EntityStatType { buf.writeFloatLE(this.min); buf.writeFloatLE(this.max); buf.writeByte(this.resetBehavior.getValue()); + buf.writeByte(this.hideFromTooltip ? 1 : 0); int idOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); int minValueEffectsOffsetSlot = buf.writerIndex(); @@ -177,7 +183,7 @@ public class EntityStatType { } public int computeSize() { - int size = 26; + int size = 27; if (this.id != null) { size += PacketIO.stringSize(this.id); } @@ -194,17 +200,17 @@ public class EntityStatType { } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 26) { - return ValidationResult.error("Buffer too small: expected at least 26 bytes"); + if (buffer.readableBytes() - offset < 27) { + return ValidationResult.error("Buffer too small: expected at least 27 bytes"); } else { byte nullBits = buffer.getByte(offset); if ((nullBits & 1) != 0) { - int idOffset = buffer.getIntLE(offset + 14); + int idOffset = buffer.getIntLE(offset + 15); if (idOffset < 0) { return ValidationResult.error("Invalid offset for Id"); } - int pos = offset + 26 + idOffset; + int pos = offset + 27 + idOffset; if (pos >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Id"); } @@ -226,12 +232,12 @@ public class EntityStatType { } if ((nullBits & 2) != 0) { - int minValueEffectsOffset = buffer.getIntLE(offset + 18); + int minValueEffectsOffset = buffer.getIntLE(offset + 19); if (minValueEffectsOffset < 0) { return ValidationResult.error("Invalid offset for MinValueEffects"); } - int posx = offset + 26 + minValueEffectsOffset; + int posx = offset + 27 + minValueEffectsOffset; if (posx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for MinValueEffects"); } @@ -245,12 +251,12 @@ public class EntityStatType { } if ((nullBits & 4) != 0) { - int maxValueEffectsOffset = buffer.getIntLE(offset + 22); + int maxValueEffectsOffset = buffer.getIntLE(offset + 23); if (maxValueEffectsOffset < 0) { return ValidationResult.error("Invalid offset for MaxValueEffects"); } - int posxx = offset + 26 + maxValueEffectsOffset; + int posxx = offset + 27 + maxValueEffectsOffset; if (posxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for MaxValueEffects"); } @@ -276,6 +282,7 @@ public class EntityStatType { copy.minValueEffects = this.minValueEffects != null ? this.minValueEffects.clone() : null; copy.maxValueEffects = this.maxValueEffects != null ? this.maxValueEffects.clone() : null; copy.resetBehavior = this.resetBehavior; + copy.hideFromTooltip = this.hideFromTooltip; return copy; } @@ -292,12 +299,13 @@ public class EntityStatType { && this.max == other.max && Objects.equals(this.minValueEffects, other.minValueEffects) && Objects.equals(this.maxValueEffects, other.maxValueEffects) - && Objects.equals(this.resetBehavior, other.resetBehavior); + && Objects.equals(this.resetBehavior, other.resetBehavior) + && this.hideFromTooltip == other.hideFromTooltip; } } @Override public int hashCode() { - return Objects.hash(this.id, this.value, this.min, this.max, this.minValueEffects, this.maxValueEffects, this.resetBehavior); + return Objects.hash(this.id, this.value, this.min, this.max, this.minValueEffects, this.maxValueEffects, this.resetBehavior, this.hideFromTooltip); } } diff --git a/src/com/hypixel/hytale/protocol/EntityStatsUpdate.java b/src/com/hypixel/hytale/protocol/EntityStatsUpdate.java new file mode 100644 index 00000000..1a762299 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/EntityStatsUpdate.java @@ -0,0 +1,193 @@ +package com.hypixel.hytale.protocol; + +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.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Map.Entry; +import javax.annotation.Nonnull; + +public class EntityStatsUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 1677721600; + @Nonnull + public Map entityStatUpdates = new HashMap<>(); + + public EntityStatsUpdate() { + } + + public EntityStatsUpdate(@Nonnull Map entityStatUpdates) { + this.entityStatUpdates = entityStatUpdates; + } + + public EntityStatsUpdate(@Nonnull EntityStatsUpdate other) { + this.entityStatUpdates = other.entityStatUpdates; + } + + @Nonnull + public static EntityStatsUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + EntityStatsUpdate obj = new EntityStatsUpdate(); + int pos = offset + 0; + int entityStatUpdatesCount = VarInt.peek(buf, pos); + if (entityStatUpdatesCount < 0) { + throw ProtocolException.negativeLength("EntityStatUpdates", entityStatUpdatesCount); + } else if (entityStatUpdatesCount > 4096000) { + throw ProtocolException.dictionaryTooLarge("EntityStatUpdates", entityStatUpdatesCount, 4096000); + } else { + pos += VarInt.size(entityStatUpdatesCount); + obj.entityStatUpdates = new HashMap<>(entityStatUpdatesCount); + + for (int i = 0; i < entityStatUpdatesCount; i++) { + int key = buf.getIntLE(pos); + pos += 4; + int valLen = VarInt.peek(buf, pos); + if (valLen < 0) { + throw ProtocolException.negativeLength("val", valLen); + } + + if (valLen > 64) { + throw ProtocolException.arrayTooLong("val", valLen, 64); + } + + int valVarLen = VarInt.length(buf, pos); + if (pos + valVarLen + valLen * 13L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("val", pos + valVarLen + valLen * 13, buf.readableBytes()); + } + + pos += valVarLen; + EntityStatUpdate[] val = new EntityStatUpdate[valLen]; + + for (int valIdx = 0; valIdx < valLen; valIdx++) { + val[valIdx] = EntityStatUpdate.deserialize(buf, pos); + pos += EntityStatUpdate.computeBytesConsumed(buf, pos); + } + + if (obj.entityStatUpdates.put(key, val) != null) { + throw ProtocolException.duplicateKey("entityStatUpdates", key); + } + } + + return obj; + } + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int pos = offset + 0; + int dictLen = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos); + + for (int i = 0; i < dictLen; i++) { + pos += 4; + int al = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos); + + for (int j = 0; j < al; j++) { + pos += EntityStatUpdate.computeBytesConsumed(buf, pos); + } + } + + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + if (this.entityStatUpdates.size() > 4096000) { + throw ProtocolException.dictionaryTooLarge("EntityStatUpdates", this.entityStatUpdates.size(), 4096000); + } else { + VarInt.write(buf, this.entityStatUpdates.size()); + + for (Entry e : this.entityStatUpdates.entrySet()) { + buf.writeIntLE(e.getKey()); + VarInt.write(buf, e.getValue().length); + + for (EntityStatUpdate arrItem : e.getValue()) { + arrItem.serialize(buf); + } + } + + return buf.writerIndex() - startPos; + } + } + + @Override + public int computeSize() { + int size = 0; + int entityStatUpdatesSize = 0; + + for (Entry kvp : this.entityStatUpdates.entrySet()) { + entityStatUpdatesSize += 4 + VarInt.size(kvp.getValue().length) + Arrays.stream(kvp.getValue()).mapToInt(inner -> inner.computeSize()).sum(); + } + + return size + VarInt.size(this.entityStatUpdates.size()) + entityStatUpdatesSize; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 0) { + return ValidationResult.error("Buffer too small: expected at least 0 bytes"); + } else { + int pos = offset + 0; + int entityStatUpdatesCount = VarInt.peek(buffer, pos); + if (entityStatUpdatesCount < 0) { + return ValidationResult.error("Invalid dictionary count for EntityStatUpdates"); + } else if (entityStatUpdatesCount > 4096000) { + return ValidationResult.error("EntityStatUpdates exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + + for (int i = 0; i < entityStatUpdatesCount; i++) { + pos += 4; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading key"); + } + + int valueArrCount = VarInt.peek(buffer, pos); + if (valueArrCount < 0) { + return ValidationResult.error("Invalid array count for value"); + } + + pos += VarInt.length(buffer, pos); + + for (int valueArrIdx = 0; valueArrIdx < valueArrCount; valueArrIdx++) { + pos += EntityStatUpdate.computeBytesConsumed(buffer, pos); + } + } + + return ValidationResult.OK; + } + } + } + + public EntityStatsUpdate clone() { + EntityStatsUpdate copy = new EntityStatsUpdate(); + Map m = new HashMap<>(); + + for (Entry e : this.entityStatUpdates.entrySet()) { + m.put(e.getKey(), Arrays.stream(e.getValue()).map(x -> x.clone()).toArray(EntityStatUpdate[]::new)); + } + + copy.entityStatUpdates = m; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof EntityStatsUpdate other ? Objects.equals(this.entityStatUpdates, other.entityStatUpdates) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.entityStatUpdates); + } +} diff --git a/src/com/hypixel/hytale/protocol/EntityUpdate.java b/src/com/hypixel/hytale/protocol/EntityUpdate.java index eab33dfe..a9fbd756 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 * 1L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("Updates", varPos1 + varIntLen + updatesCount * 1, buf.readableBytes()); } obj.updates = new ComponentUpdate[updatesCount]; @@ -166,7 +166,7 @@ public class EntityUpdate { VarInt.write(buf, this.updates.length); for (ComponentUpdate item : this.updates) { - item.serialize(buf); + item.serializeWithTypeId(buf); } } else { buf.setIntLE(updatesOffsetSlot, -1); @@ -183,7 +183,7 @@ public class EntityUpdate { int updatesSize = 0; for (ComponentUpdate elem : this.updates) { - updatesSize += elem.computeSize(); + updatesSize += elem.computeSizeWithTypeId(); } size += VarInt.size(this.updates.length) + updatesSize; @@ -264,7 +264,7 @@ public class EntityUpdate { EntityUpdate copy = new EntityUpdate(); copy.networkId = this.networkId; copy.removed = this.removed != null ? Arrays.copyOf(this.removed, this.removed.length) : null; - copy.updates = this.updates != null ? Arrays.stream(this.updates).map(e -> e.clone()).toArray(ComponentUpdate[]::new) : null; + copy.updates = this.updates != null ? Arrays.copyOf(this.updates, this.updates.length) : null; return copy; } diff --git a/src/com/hypixel/hytale/protocol/Equipment.java b/src/com/hypixel/hytale/protocol/EquipmentUpdate.java similarity index 94% rename from src/com/hypixel/hytale/protocol/Equipment.java rename to src/com/hypixel/hytale/protocol/EquipmentUpdate.java index cfd76d8d..6b2763aa 100644 --- a/src/com/hypixel/hytale/protocol/Equipment.java +++ b/src/com/hypixel/hytale/protocol/EquipmentUpdate.java @@ -10,7 +10,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class Equipment { +public class EquipmentUpdate extends ComponentUpdate { public static final int NULLABLE_BIT_FIELD_SIZE = 1; public static final int FIXED_BLOCK_SIZE = 1; public static final int VARIABLE_FIELD_COUNT = 3; @@ -23,24 +23,24 @@ public class Equipment { @Nullable public String leftHandItemId; - public Equipment() { + public EquipmentUpdate() { } - public Equipment(@Nullable String[] armorIds, @Nullable String rightHandItemId, @Nullable String leftHandItemId) { + public EquipmentUpdate(@Nullable String[] armorIds, @Nullable String rightHandItemId, @Nullable String leftHandItemId) { this.armorIds = armorIds; this.rightHandItemId = rightHandItemId; this.leftHandItemId = leftHandItemId; } - public Equipment(@Nonnull Equipment other) { + public EquipmentUpdate(@Nonnull EquipmentUpdate other) { this.armorIds = other.armorIds; this.rightHandItemId = other.rightHandItemId; this.leftHandItemId = other.leftHandItemId; } @Nonnull - public static Equipment deserialize(@Nonnull ByteBuf buf, int offset) { - Equipment obj = new Equipment(); + public static EquipmentUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + EquipmentUpdate obj = new EquipmentUpdate(); byte nullBits = buf.getByte(offset); if ((nullBits & 1) != 0) { int varPos0 = offset + 13 + buf.getIntLE(offset + 1); @@ -150,7 +150,8 @@ public class Equipment { return maxEnd; } - public void serialize(@Nonnull ByteBuf buf) { + @Override + public int serialize(@Nonnull ByteBuf buf) { int startPos = buf.writerIndex(); byte nullBits = 0; if (this.armorIds != null) { @@ -201,8 +202,11 @@ public class Equipment { } else { buf.setIntLE(leftHandItemIdOffsetSlot, -1); } + + return buf.writerIndex() - startPos; } + @Override public int computeSize() { int size = 13; if (this.armorIds != null) { @@ -325,8 +329,8 @@ public class Equipment { } } - public Equipment clone() { - Equipment copy = new Equipment(); + public EquipmentUpdate clone() { + EquipmentUpdate copy = new EquipmentUpdate(); copy.armorIds = this.armorIds != null ? Arrays.copyOf(this.armorIds, this.armorIds.length) : null; copy.rightHandItemId = this.rightHandItemId; copy.leftHandItemId = this.leftHandItemId; @@ -338,7 +342,7 @@ public class Equipment { if (this == obj) { return true; } else { - return !(obj instanceof Equipment other) + return !(obj instanceof EquipmentUpdate other) ? false : Arrays.equals((Object[])this.armorIds, (Object[])other.armorIds) && Objects.equals(this.rightHandItemId, other.rightHandItemId) diff --git a/src/com/hypixel/hytale/protocol/Fluid.java b/src/com/hypixel/hytale/protocol/Fluid.java index 4c36ee36..881fe2d0 100644 --- a/src/com/hypixel/hytale/protocol/Fluid.java +++ b/src/com/hypixel/hytale/protocol/Fluid.java @@ -12,9 +12,9 @@ import javax.annotation.Nullable; public class Fluid { public static final int NULLABLE_BIT_FIELD_SIZE = 1; - public static final int FIXED_BLOCK_SIZE = 22; - public static final int VARIABLE_FIELD_COUNT = 5; - public static final int VARIABLE_BLOCK_START = 42; + public static final int FIXED_BLOCK_SIZE = 23; + public static final int VARIABLE_FIELD_COUNT = 6; + public static final int VARIABLE_BLOCK_START = 47; public static final int MAX_SIZE = 1677721600; @Nullable public String id; @@ -28,6 +28,10 @@ public class Fluid { public ShaderType[] shaderEffect; @Nullable public ColorLight light; + @Nullable + public ModelParticle[] particles; + @Nonnull + public FluidDrawType drawType = FluidDrawType.None; public int fluidFXIndex; public int blockSoundSetIndex; @Nullable @@ -48,6 +52,8 @@ public class Fluid { @Nonnull Opacity opacity, @Nullable ShaderType[] shaderEffect, @Nullable ColorLight light, + @Nullable ModelParticle[] particles, + @Nonnull FluidDrawType drawType, int fluidFXIndex, int blockSoundSetIndex, @Nullable String blockParticleSetId, @@ -61,6 +67,8 @@ public class Fluid { this.opacity = opacity; this.shaderEffect = shaderEffect; this.light = light; + this.particles = particles; + this.drawType = drawType; this.fluidFXIndex = fluidFXIndex; this.blockSoundSetIndex = blockSoundSetIndex; this.blockParticleSetId = blockParticleSetId; @@ -76,6 +84,8 @@ public class Fluid { this.opacity = other.opacity; this.shaderEffect = other.shaderEffect; this.light = other.light; + this.particles = other.particles; + this.drawType = other.drawType; this.fluidFXIndex = other.fluidFXIndex; this.blockSoundSetIndex = other.blockSoundSetIndex; this.blockParticleSetId = other.blockParticleSetId; @@ -94,14 +104,15 @@ public class Fluid { obj.light = ColorLight.deserialize(buf, offset + 7); } - obj.fluidFXIndex = buf.getIntLE(offset + 11); - obj.blockSoundSetIndex = buf.getIntLE(offset + 15); + obj.drawType = FluidDrawType.fromValue(buf.getByte(offset + 11)); + obj.fluidFXIndex = buf.getIntLE(offset + 12); + obj.blockSoundSetIndex = buf.getIntLE(offset + 16); if ((nullBits & 2) != 0) { - obj.particleColor = Color.deserialize(buf, offset + 19); + obj.particleColor = Color.deserialize(buf, offset + 20); } if ((nullBits & 4) != 0) { - int varPos0 = offset + 42 + buf.getIntLE(offset + 22); + int varPos0 = offset + 47 + buf.getIntLE(offset + 23); int idLen = VarInt.peek(buf, varPos0); if (idLen < 0) { throw ProtocolException.negativeLength("Id", idLen); @@ -115,7 +126,7 @@ public class Fluid { } if ((nullBits & 8) != 0) { - int varPos1 = offset + 42 + buf.getIntLE(offset + 26); + int varPos1 = offset + 47 + buf.getIntLE(offset + 27); int cubeTexturesCount = VarInt.peek(buf, varPos1); if (cubeTexturesCount < 0) { throw ProtocolException.negativeLength("CubeTextures", cubeTexturesCount); @@ -140,7 +151,7 @@ public class Fluid { } if ((nullBits & 16) != 0) { - int varPos2 = offset + 42 + buf.getIntLE(offset + 30); + int varPos2 = offset + 47 + buf.getIntLE(offset + 31); int shaderEffectCount = VarInt.peek(buf, varPos2); if (shaderEffectCount < 0) { throw ProtocolException.negativeLength("ShaderEffect", shaderEffectCount); @@ -165,8 +176,33 @@ public class Fluid { } if ((nullBits & 32) != 0) { - int varPos3 = offset + 42 + buf.getIntLE(offset + 34); - int blockParticleSetIdLen = VarInt.peek(buf, varPos3); + int varPos3 = offset + 47 + buf.getIntLE(offset + 35); + int particlesCount = VarInt.peek(buf, varPos3); + if (particlesCount < 0) { + throw ProtocolException.negativeLength("Particles", particlesCount); + } + + if (particlesCount > 4096000) { + throw ProtocolException.arrayTooLong("Particles", particlesCount, 4096000); + } + + int varIntLen = VarInt.length(buf, varPos3); + if (varPos3 + varIntLen + particlesCount * 34L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("Particles", varPos3 + varIntLen + particlesCount * 34, buf.readableBytes()); + } + + obj.particles = new ModelParticle[particlesCount]; + int elemPos = varPos3 + varIntLen; + + for (int i = 0; i < particlesCount; i++) { + obj.particles[i] = ModelParticle.deserialize(buf, elemPos); + elemPos += ModelParticle.computeBytesConsumed(buf, elemPos); + } + } + + if ((nullBits & 64) != 0) { + int varPos4 = offset + 47 + buf.getIntLE(offset + 39); + int blockParticleSetIdLen = VarInt.peek(buf, varPos4); if (blockParticleSetIdLen < 0) { throw ProtocolException.negativeLength("BlockParticleSetId", blockParticleSetIdLen); } @@ -175,12 +211,12 @@ public class Fluid { throw ProtocolException.stringTooLong("BlockParticleSetId", blockParticleSetIdLen, 4096000); } - obj.blockParticleSetId = PacketIO.readVarString(buf, varPos3, PacketIO.UTF8); + obj.blockParticleSetId = PacketIO.readVarString(buf, varPos4, PacketIO.UTF8); } - if ((nullBits & 64) != 0) { - int varPos4 = offset + 42 + buf.getIntLE(offset + 38); - int tagIndexesCount = VarInt.peek(buf, varPos4); + if ((nullBits & 128) != 0) { + int varPos5 = offset + 47 + buf.getIntLE(offset + 43); + int tagIndexesCount = VarInt.peek(buf, varPos5); if (tagIndexesCount < 0) { throw ProtocolException.negativeLength("TagIndexes", tagIndexesCount); } @@ -189,15 +225,15 @@ public class Fluid { throw ProtocolException.arrayTooLong("TagIndexes", tagIndexesCount, 4096000); } - int varIntLen = VarInt.length(buf, varPos4); - if (varPos4 + varIntLen + tagIndexesCount * 4L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall("TagIndexes", varPos4 + varIntLen + tagIndexesCount * 4, buf.readableBytes()); + int varIntLen = VarInt.length(buf, varPos5); + if (varPos5 + varIntLen + tagIndexesCount * 4L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("TagIndexes", varPos5 + varIntLen + tagIndexesCount * 4, buf.readableBytes()); } obj.tagIndexes = new int[tagIndexesCount]; for (int i = 0; i < tagIndexesCount; i++) { - obj.tagIndexes[i] = buf.getIntLE(varPos4 + varIntLen + i * 4); + obj.tagIndexes[i] = buf.getIntLE(varPos5 + varIntLen + i * 4); } } @@ -206,10 +242,10 @@ public class Fluid { public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte nullBits = buf.getByte(offset); - int maxEnd = 42; + int maxEnd = 47; if ((nullBits & 4) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 22); - int pos0 = offset + 42 + fieldOffset0; + int fieldOffset0 = buf.getIntLE(offset + 23); + int pos0 = offset + 47 + fieldOffset0; int sl = VarInt.peek(buf, pos0); pos0 += VarInt.length(buf, pos0) + sl; if (pos0 - offset > maxEnd) { @@ -218,8 +254,8 @@ public class Fluid { } if ((nullBits & 8) != 0) { - int fieldOffset1 = buf.getIntLE(offset + 26); - int pos1 = offset + 42 + fieldOffset1; + int fieldOffset1 = buf.getIntLE(offset + 27); + int pos1 = offset + 47 + fieldOffset1; int arrLen = VarInt.peek(buf, pos1); pos1 += VarInt.length(buf, pos1); @@ -233,8 +269,8 @@ public class Fluid { } if ((nullBits & 16) != 0) { - int fieldOffset2 = buf.getIntLE(offset + 30); - int pos2 = offset + 42 + fieldOffset2; + int fieldOffset2 = buf.getIntLE(offset + 31); + int pos2 = offset + 47 + fieldOffset2; int arrLen = VarInt.peek(buf, pos2); pos2 += VarInt.length(buf, pos2) + arrLen * 1; if (pos2 - offset > maxEnd) { @@ -243,25 +279,40 @@ public class Fluid { } if ((nullBits & 32) != 0) { - int fieldOffset3 = buf.getIntLE(offset + 34); - int pos3 = offset + 42 + fieldOffset3; - int sl = VarInt.peek(buf, pos3); - pos3 += VarInt.length(buf, pos3) + sl; + int fieldOffset3 = buf.getIntLE(offset + 35); + int pos3 = offset + 47 + fieldOffset3; + int arrLen = VarInt.peek(buf, pos3); + pos3 += VarInt.length(buf, pos3); + + for (int i = 0; i < arrLen; i++) { + pos3 += ModelParticle.computeBytesConsumed(buf, pos3); + } + if (pos3 - offset > maxEnd) { maxEnd = pos3 - offset; } } if ((nullBits & 64) != 0) { - int fieldOffset4 = buf.getIntLE(offset + 38); - int pos4 = offset + 42 + fieldOffset4; - int arrLen = VarInt.peek(buf, pos4); - pos4 += VarInt.length(buf, pos4) + arrLen * 4; + int fieldOffset4 = buf.getIntLE(offset + 39); + int pos4 = offset + 47 + fieldOffset4; + int sl = VarInt.peek(buf, pos4); + pos4 += VarInt.length(buf, pos4) + sl; if (pos4 - offset > maxEnd) { maxEnd = pos4 - offset; } } + if ((nullBits & 128) != 0) { + int fieldOffset5 = buf.getIntLE(offset + 43); + int pos5 = offset + 47 + fieldOffset5; + int arrLen = VarInt.peek(buf, pos5); + pos5 += VarInt.length(buf, pos5) + arrLen * 4; + if (pos5 - offset > maxEnd) { + maxEnd = pos5 - offset; + } + } + return maxEnd; } @@ -288,14 +339,18 @@ public class Fluid { nullBits = (byte)(nullBits | 16); } - if (this.blockParticleSetId != null) { + if (this.particles != null) { nullBits = (byte)(nullBits | 32); } - if (this.tagIndexes != null) { + if (this.blockParticleSetId != null) { nullBits = (byte)(nullBits | 64); } + if (this.tagIndexes != null) { + nullBits = (byte)(nullBits | 128); + } + buf.writeByte(nullBits); buf.writeIntLE(this.maxFluidLevel); buf.writeByte(this.requiresAlphaBlending ? 1 : 0); @@ -306,6 +361,7 @@ public class Fluid { buf.writeZero(4); } + buf.writeByte(this.drawType.getValue()); buf.writeIntLE(this.fluidFXIndex); buf.writeIntLE(this.blockSoundSetIndex); if (this.particleColor != null) { @@ -320,6 +376,8 @@ public class Fluid { buf.writeIntLE(0); int shaderEffectOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); + int particlesOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); int blockParticleSetIdOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); int tagIndexesOffsetSlot = buf.writerIndex(); @@ -362,6 +420,21 @@ public class Fluid { buf.setIntLE(shaderEffectOffsetSlot, -1); } + if (this.particles != null) { + buf.setIntLE(particlesOffsetSlot, buf.writerIndex() - varBlockStart); + if (this.particles.length > 4096000) { + throw ProtocolException.arrayTooLong("Particles", this.particles.length, 4096000); + } + + VarInt.write(buf, this.particles.length); + + for (ModelParticle item : this.particles) { + item.serialize(buf); + } + } else { + buf.setIntLE(particlesOffsetSlot, -1); + } + if (this.blockParticleSetId != null) { buf.setIntLE(blockParticleSetIdOffsetSlot, buf.writerIndex() - varBlockStart); PacketIO.writeVarString(buf, this.blockParticleSetId, 4096000); @@ -386,7 +459,7 @@ public class Fluid { } public int computeSize() { - int size = 42; + int size = 47; if (this.id != null) { size += PacketIO.stringSize(this.id); } @@ -405,6 +478,16 @@ public class Fluid { size += VarInt.size(this.shaderEffect.length) + this.shaderEffect.length * 1; } + if (this.particles != null) { + int particlesSize = 0; + + for (ModelParticle elem : this.particles) { + particlesSize += elem.computeSize(); + } + + size += VarInt.size(this.particles.length) + particlesSize; + } + if (this.blockParticleSetId != null) { size += PacketIO.stringSize(this.blockParticleSetId); } @@ -417,17 +500,17 @@ public class Fluid { } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 42) { - return ValidationResult.error("Buffer too small: expected at least 42 bytes"); + if (buffer.readableBytes() - offset < 47) { + return ValidationResult.error("Buffer too small: expected at least 47 bytes"); } else { byte nullBits = buffer.getByte(offset); if ((nullBits & 4) != 0) { - int idOffset = buffer.getIntLE(offset + 22); + int idOffset = buffer.getIntLE(offset + 23); if (idOffset < 0) { return ValidationResult.error("Invalid offset for Id"); } - int pos = offset + 42 + idOffset; + int pos = offset + 47 + idOffset; if (pos >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Id"); } @@ -449,12 +532,12 @@ public class Fluid { } if ((nullBits & 8) != 0) { - int cubeTexturesOffset = buffer.getIntLE(offset + 26); + int cubeTexturesOffset = buffer.getIntLE(offset + 27); if (cubeTexturesOffset < 0) { return ValidationResult.error("Invalid offset for CubeTextures"); } - int posx = offset + 42 + cubeTexturesOffset; + int posx = offset + 47 + cubeTexturesOffset; if (posx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for CubeTextures"); } @@ -481,12 +564,12 @@ public class Fluid { } if ((nullBits & 16) != 0) { - int shaderEffectOffset = buffer.getIntLE(offset + 30); + int shaderEffectOffset = buffer.getIntLE(offset + 31); if (shaderEffectOffset < 0) { return ValidationResult.error("Invalid offset for ShaderEffect"); } - int posxx = offset + 42 + shaderEffectOffset; + int posxx = offset + 47 + shaderEffectOffset; if (posxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for ShaderEffect"); } @@ -508,17 +591,49 @@ public class Fluid { } if ((nullBits & 32) != 0) { - int blockParticleSetIdOffset = buffer.getIntLE(offset + 34); + int particlesOffset = buffer.getIntLE(offset + 35); + if (particlesOffset < 0) { + return ValidationResult.error("Invalid offset for Particles"); + } + + int posxxx = offset + 47 + particlesOffset; + if (posxxx >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for Particles"); + } + + int particlesCount = VarInt.peek(buffer, posxxx); + if (particlesCount < 0) { + return ValidationResult.error("Invalid array count for Particles"); + } + + if (particlesCount > 4096000) { + return ValidationResult.error("Particles exceeds max length 4096000"); + } + + posxxx += VarInt.length(buffer, posxxx); + + for (int i = 0; i < particlesCount; i++) { + ValidationResult structResult = ModelParticle.validateStructure(buffer, posxxx); + if (!structResult.isValid()) { + return ValidationResult.error("Invalid ModelParticle in Particles[" + i + "]: " + structResult.error()); + } + + posxxx += ModelParticle.computeBytesConsumed(buffer, posxxx); + } + } + + if ((nullBits & 64) != 0) { + int blockParticleSetIdOffset = buffer.getIntLE(offset + 39); if (blockParticleSetIdOffset < 0) { return ValidationResult.error("Invalid offset for BlockParticleSetId"); } - int posxxx = offset + 42 + blockParticleSetIdOffset; - if (posxxx >= buffer.writerIndex()) { + int posxxxx = offset + 47 + blockParticleSetIdOffset; + if (posxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for BlockParticleSetId"); } - int blockParticleSetIdLen = VarInt.peek(buffer, posxxx); + int blockParticleSetIdLen = VarInt.peek(buffer, posxxxx); if (blockParticleSetIdLen < 0) { return ValidationResult.error("Invalid string length for BlockParticleSetId"); } @@ -527,25 +642,25 @@ public class Fluid { return ValidationResult.error("BlockParticleSetId exceeds max length 4096000"); } - posxxx += VarInt.length(buffer, posxxx); - posxxx += blockParticleSetIdLen; - if (posxxx > buffer.writerIndex()) { + posxxxx += VarInt.length(buffer, posxxxx); + posxxxx += blockParticleSetIdLen; + if (posxxxx > buffer.writerIndex()) { return ValidationResult.error("Buffer overflow reading BlockParticleSetId"); } } - if ((nullBits & 64) != 0) { - int tagIndexesOffset = buffer.getIntLE(offset + 38); + if ((nullBits & 128) != 0) { + int tagIndexesOffset = buffer.getIntLE(offset + 43); if (tagIndexesOffset < 0) { return ValidationResult.error("Invalid offset for TagIndexes"); } - int posxxxx = offset + 42 + tagIndexesOffset; - if (posxxxx >= buffer.writerIndex()) { + int posxxxxx = offset + 47 + tagIndexesOffset; + if (posxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for TagIndexes"); } - int tagIndexesCount = VarInt.peek(buffer, posxxxx); + int tagIndexesCount = VarInt.peek(buffer, posxxxxx); if (tagIndexesCount < 0) { return ValidationResult.error("Invalid array count for TagIndexes"); } @@ -554,9 +669,9 @@ public class Fluid { return ValidationResult.error("TagIndexes exceeds max length 4096000"); } - posxxxx += VarInt.length(buffer, posxxxx); - posxxxx += tagIndexesCount * 4; - if (posxxxx > buffer.writerIndex()) { + posxxxxx += VarInt.length(buffer, posxxxxx); + posxxxxx += tagIndexesCount * 4; + if (posxxxxx > buffer.writerIndex()) { return ValidationResult.error("Buffer overflow reading TagIndexes"); } } @@ -574,6 +689,8 @@ public class Fluid { copy.opacity = this.opacity; copy.shaderEffect = this.shaderEffect != null ? Arrays.copyOf(this.shaderEffect, this.shaderEffect.length) : null; copy.light = this.light != null ? this.light.clone() : null; + copy.particles = this.particles != null ? Arrays.stream(this.particles).map(e -> e.clone()).toArray(ModelParticle[]::new) : null; + copy.drawType = this.drawType; copy.fluidFXIndex = this.fluidFXIndex; copy.blockSoundSetIndex = this.blockSoundSetIndex; copy.blockParticleSetId = this.blockParticleSetId; @@ -596,6 +713,8 @@ public class Fluid { && Objects.equals(this.opacity, other.opacity) && Arrays.equals((Object[])this.shaderEffect, (Object[])other.shaderEffect) && Objects.equals(this.light, other.light) + && Arrays.equals((Object[])this.particles, (Object[])other.particles) + && Objects.equals(this.drawType, other.drawType) && this.fluidFXIndex == other.fluidFXIndex && this.blockSoundSetIndex == other.blockSoundSetIndex && Objects.equals(this.blockParticleSetId, other.blockParticleSetId) @@ -614,6 +733,8 @@ public class Fluid { result = 31 * result + Objects.hashCode(this.opacity); result = 31 * result + Arrays.hashCode((Object[])this.shaderEffect); result = 31 * result + Objects.hashCode(this.light); + result = 31 * result + Arrays.hashCode((Object[])this.particles); + result = 31 * result + Objects.hashCode(this.drawType); result = 31 * result + Integer.hashCode(this.fluidFXIndex); result = 31 * result + Integer.hashCode(this.blockSoundSetIndex); result = 31 * result + Objects.hashCode(this.blockParticleSetId); diff --git a/src/com/hypixel/hytale/protocol/FluidDrawType.java b/src/com/hypixel/hytale/protocol/FluidDrawType.java new file mode 100644 index 00000000..dea9bbdf --- /dev/null +++ b/src/com/hypixel/hytale/protocol/FluidDrawType.java @@ -0,0 +1,27 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ProtocolException; + +public enum FluidDrawType { + None(0), + Liquid(1); + + public static final FluidDrawType[] VALUES = values(); + private final int value; + + private FluidDrawType(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } + + public static FluidDrawType fromValue(int value) { + if (value >= 0 && value < VALUES.length) { + return VALUES[value]; + } else { + throw ProtocolException.invalidEnumValue("FluidDrawType", value); + } + } +} diff --git a/src/com/hypixel/hytale/protocol/HitboxCollisionUpdate.java b/src/com/hypixel/hytale/protocol/HitboxCollisionUpdate.java new file mode 100644 index 00000000..afd4cc40 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/HitboxCollisionUpdate.java @@ -0,0 +1,73 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; + +public class HitboxCollisionUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 4; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 4; + public static final int MAX_SIZE = 4; + public int hitboxCollisionConfigIndex; + + public HitboxCollisionUpdate() { + } + + public HitboxCollisionUpdate(int hitboxCollisionConfigIndex) { + this.hitboxCollisionConfigIndex = hitboxCollisionConfigIndex; + } + + public HitboxCollisionUpdate(@Nonnull HitboxCollisionUpdate other) { + this.hitboxCollisionConfigIndex = other.hitboxCollisionConfigIndex; + } + + @Nonnull + public static HitboxCollisionUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + HitboxCollisionUpdate obj = new HitboxCollisionUpdate(); + obj.hitboxCollisionConfigIndex = buf.getIntLE(offset + 0); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 4; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + buf.writeIntLE(this.hitboxCollisionConfigIndex); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 4; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 4 ? ValidationResult.error("Buffer too small: expected at least 4 bytes") : ValidationResult.OK; + } + + public HitboxCollisionUpdate clone() { + HitboxCollisionUpdate copy = new HitboxCollisionUpdate(); + copy.hitboxCollisionConfigIndex = this.hitboxCollisionConfigIndex; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof HitboxCollisionUpdate other ? this.hitboxCollisionConfigIndex == other.hitboxCollisionConfigIndex : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.hitboxCollisionConfigIndex); + } +} diff --git a/src/com/hypixel/hytale/protocol/IntangibleUpdate.java b/src/com/hypixel/hytale/protocol/IntangibleUpdate.java new file mode 100644 index 00000000..a8a40ddb --- /dev/null +++ b/src/com/hypixel/hytale/protocol/IntangibleUpdate.java @@ -0,0 +1,51 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import javax.annotation.Nonnull; + +public class IntangibleUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 0; + + @Nonnull + public static IntangibleUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + return new IntangibleUpdate(); + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 0; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 0; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK; + } + + public IntangibleUpdate clone() { + return new IntangibleUpdate(); + } + + @Override + public boolean equals(Object obj) { + return this == obj ? true : obj instanceof IntangibleUpdate other; + } + + @Override + public int hashCode() { + return 0; + } +} diff --git a/src/com/hypixel/hytale/protocol/Nameplate.java b/src/com/hypixel/hytale/protocol/InteractableUpdate.java similarity index 51% rename from src/com/hypixel/hytale/protocol/Nameplate.java rename to src/com/hypixel/hytale/protocol/InteractableUpdate.java index 1055645e..bc9f101f 100644 --- a/src/com/hypixel/hytale/protocol/Nameplate.java +++ b/src/com/hypixel/hytale/protocol/InteractableUpdate.java @@ -9,44 +9,44 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class Nameplate { +public class InteractableUpdate extends ComponentUpdate { public static final int NULLABLE_BIT_FIELD_SIZE = 1; public static final int FIXED_BLOCK_SIZE = 1; public static final int VARIABLE_FIELD_COUNT = 1; public static final int VARIABLE_BLOCK_START = 1; public static final int MAX_SIZE = 16384006; @Nullable - public String text; + public String interactionHint; - public Nameplate() { + public InteractableUpdate() { } - public Nameplate(@Nullable String text) { - this.text = text; + public InteractableUpdate(@Nullable String interactionHint) { + this.interactionHint = interactionHint; } - public Nameplate(@Nonnull Nameplate other) { - this.text = other.text; + public InteractableUpdate(@Nonnull InteractableUpdate other) { + this.interactionHint = other.interactionHint; } @Nonnull - public static Nameplate deserialize(@Nonnull ByteBuf buf, int offset) { - Nameplate obj = new Nameplate(); + public static InteractableUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + InteractableUpdate obj = new InteractableUpdate(); byte nullBits = buf.getByte(offset); int pos = offset + 1; if ((nullBits & 1) != 0) { - int textLen = VarInt.peek(buf, pos); - if (textLen < 0) { - throw ProtocolException.negativeLength("Text", textLen); + int interactionHintLen = VarInt.peek(buf, pos); + if (interactionHintLen < 0) { + throw ProtocolException.negativeLength("InteractionHint", interactionHintLen); } - if (textLen > 4096000) { - throw ProtocolException.stringTooLong("Text", textLen, 4096000); + if (interactionHintLen > 4096000) { + throw ProtocolException.stringTooLong("InteractionHint", interactionHintLen, 4096000); } - int textVarLen = VarInt.length(buf, pos); - obj.text = PacketIO.readVarString(buf, pos, PacketIO.UTF8); - pos += textVarLen + textLen; + int interactionHintVarLen = VarInt.length(buf, pos); + obj.interactionHint = PacketIO.readVarString(buf, pos, PacketIO.UTF8); + pos += interactionHintVarLen + interactionHintLen; } return obj; @@ -63,22 +63,27 @@ public class Nameplate { return pos - offset; } - public void serialize(@Nonnull ByteBuf buf) { + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); byte nullBits = 0; - if (this.text != null) { + if (this.interactionHint != null) { nullBits = (byte)(nullBits | 1); } buf.writeByte(nullBits); - if (this.text != null) { - PacketIO.writeVarString(buf, this.text, 4096000); + if (this.interactionHint != null) { + PacketIO.writeVarString(buf, this.interactionHint, 4096000); } + + return buf.writerIndex() - startPos; } + @Override public int computeSize() { int size = 1; - if (this.text != null) { - size += PacketIO.stringSize(this.text); + if (this.interactionHint != null) { + size += PacketIO.stringSize(this.interactionHint); } return size; @@ -91,19 +96,19 @@ public class Nameplate { byte nullBits = buffer.getByte(offset); int pos = offset + 1; if ((nullBits & 1) != 0) { - int textLen = VarInt.peek(buffer, pos); - if (textLen < 0) { - return ValidationResult.error("Invalid string length for Text"); + int interactionHintLen = VarInt.peek(buffer, pos); + if (interactionHintLen < 0) { + return ValidationResult.error("Invalid string length for InteractionHint"); } - if (textLen > 4096000) { - return ValidationResult.error("Text exceeds max length 4096000"); + if (interactionHintLen > 4096000) { + return ValidationResult.error("InteractionHint exceeds max length 4096000"); } pos += VarInt.length(buffer, pos); - pos += textLen; + pos += interactionHintLen; if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Text"); + return ValidationResult.error("Buffer overflow reading InteractionHint"); } } @@ -111,9 +116,9 @@ public class Nameplate { } } - public Nameplate clone() { - Nameplate copy = new Nameplate(); - copy.text = this.text; + public InteractableUpdate clone() { + InteractableUpdate copy = new InteractableUpdate(); + copy.interactionHint = this.interactionHint; return copy; } @@ -122,12 +127,12 @@ public class Nameplate { if (this == obj) { return true; } else { - return obj instanceof Nameplate other ? Objects.equals(this.text, other.text) : false; + return obj instanceof InteractableUpdate other ? Objects.equals(this.interactionHint, other.interactionHint) : false; } } @Override public int hashCode() { - return Objects.hash(this.text); + return Objects.hash(this.interactionHint); } } diff --git a/src/com/hypixel/hytale/protocol/InteractionsUpdate.java b/src/com/hypixel/hytale/protocol/InteractionsUpdate.java new file mode 100644 index 00000000..e4b1ff8c --- /dev/null +++ b/src/com/hypixel/hytale/protocol/InteractionsUpdate.java @@ -0,0 +1,241 @@ +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.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Map.Entry; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class InteractionsUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 1; + public static final int FIXED_BLOCK_SIZE = 1; + public static final int VARIABLE_FIELD_COUNT = 2; + public static final int VARIABLE_BLOCK_START = 9; + public static final int MAX_SIZE = 36864019; + @Nonnull + public Map interactions = new HashMap<>(); + @Nullable + public String interactionHint; + + public InteractionsUpdate() { + } + + public InteractionsUpdate(@Nonnull Map interactions, @Nullable String interactionHint) { + this.interactions = interactions; + this.interactionHint = interactionHint; + } + + public InteractionsUpdate(@Nonnull InteractionsUpdate other) { + this.interactions = other.interactions; + this.interactionHint = other.interactionHint; + } + + @Nonnull + public static InteractionsUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + InteractionsUpdate obj = new InteractionsUpdate(); + byte nullBits = buf.getByte(offset); + int varPos0 = offset + 9 + buf.getIntLE(offset + 1); + int interactionsCount = VarInt.peek(buf, varPos0); + if (interactionsCount < 0) { + throw ProtocolException.negativeLength("Interactions", interactionsCount); + } else if (interactionsCount > 4096000) { + throw ProtocolException.dictionaryTooLarge("Interactions", interactionsCount, 4096000); + } else { + int varIntLen = VarInt.length(buf, varPos0); + obj.interactions = new HashMap<>(interactionsCount); + int dictPos = varPos0 + varIntLen; + + for (int i = 0; i < interactionsCount; i++) { + InteractionType key = InteractionType.fromValue(buf.getByte(dictPos)); + int val = buf.getIntLE(++dictPos); + dictPos += 4; + if (obj.interactions.put(key, val) != null) { + throw ProtocolException.duplicateKey("interactions", key); + } + } + + if ((nullBits & 1) != 0) { + varPos0 = offset + 9 + buf.getIntLE(offset + 5); + interactionsCount = VarInt.peek(buf, varPos0); + if (interactionsCount < 0) { + throw ProtocolException.negativeLength("InteractionHint", interactionsCount); + } + + if (interactionsCount > 4096000) { + throw ProtocolException.stringTooLong("InteractionHint", interactionsCount, 4096000); + } + + obj.interactionHint = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); + } + + return obj; + } + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + byte nullBits = buf.getByte(offset); + int maxEnd = 9; + int fieldOffset0 = buf.getIntLE(offset + 1); + int pos0 = offset + 9 + fieldOffset0; + int dictLen = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0); + + for (int i = 0; i < dictLen; i++) { + pos0 = ++pos0 + 4; + } + + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; + } + + if ((nullBits & 1) != 0) { + fieldOffset0 = buf.getIntLE(offset + 5); + pos0 = offset + 9 + fieldOffset0; + dictLen = VarInt.peek(buf, pos0); + pos0 += VarInt.length(buf, pos0) + dictLen; + if (pos0 - offset > maxEnd) { + maxEnd = pos0 - offset; + } + } + + return maxEnd; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + byte nullBits = 0; + if (this.interactionHint != null) { + nullBits = (byte)(nullBits | 1); + } + + buf.writeByte(nullBits); + int interactionsOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int interactionHintOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int varBlockStart = buf.writerIndex(); + buf.setIntLE(interactionsOffsetSlot, buf.writerIndex() - varBlockStart); + if (this.interactions.size() > 4096000) { + throw ProtocolException.dictionaryTooLarge("Interactions", this.interactions.size(), 4096000); + } else { + VarInt.write(buf, this.interactions.size()); + + for (Entry e : this.interactions.entrySet()) { + buf.writeByte(e.getKey().getValue()); + buf.writeIntLE(e.getValue()); + } + + if (this.interactionHint != null) { + buf.setIntLE(interactionHintOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.interactionHint, 4096000); + } else { + buf.setIntLE(interactionHintOffsetSlot, -1); + } + + return buf.writerIndex() - startPos; + } + } + + @Override + public int computeSize() { + int size = 9; + size += VarInt.size(this.interactions.size()) + this.interactions.size() * 5; + if (this.interactionHint != null) { + size += PacketIO.stringSize(this.interactionHint); + } + + return size; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 9) { + return ValidationResult.error("Buffer too small: expected at least 9 bytes"); + } else { + byte nullBits = buffer.getByte(offset); + int interactionsOffset = buffer.getIntLE(offset + 1); + if (interactionsOffset < 0) { + return ValidationResult.error("Invalid offset for Interactions"); + } else { + int pos = offset + 9 + interactionsOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for Interactions"); + } else { + int interactionsCount = VarInt.peek(buffer, pos); + if (interactionsCount < 0) { + return ValidationResult.error("Invalid dictionary count for Interactions"); + } else if (interactionsCount > 4096000) { + return ValidationResult.error("Interactions exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + + for (int i = 0; i < interactionsCount; i++) { + pos = ++pos + 4; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading value"); + } + } + + if ((nullBits & 1) != 0) { + interactionsOffset = buffer.getIntLE(offset + 5); + if (interactionsOffset < 0) { + return ValidationResult.error("Invalid offset for InteractionHint"); + } + + pos = offset + 9 + interactionsOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for InteractionHint"); + } + + interactionsCount = VarInt.peek(buffer, pos); + if (interactionsCount < 0) { + return ValidationResult.error("Invalid string length for InteractionHint"); + } + + if (interactionsCount > 4096000) { + return ValidationResult.error("InteractionHint exceeds max length 4096000"); + } + + pos += VarInt.length(buffer, pos); + pos += interactionsCount; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading InteractionHint"); + } + } + + return ValidationResult.OK; + } + } + } + } + } + + public InteractionsUpdate clone() { + InteractionsUpdate copy = new InteractionsUpdate(); + copy.interactions = new HashMap<>(this.interactions); + copy.interactionHint = this.interactionHint; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof InteractionsUpdate other) + ? false + : Objects.equals(this.interactions, other.interactions) && Objects.equals(this.interactionHint, other.interactionHint); + } + } + + @Override + public int hashCode() { + return Objects.hash(this.interactions, this.interactionHint); + } +} diff --git a/src/com/hypixel/hytale/protocol/InvulnerableUpdate.java b/src/com/hypixel/hytale/protocol/InvulnerableUpdate.java new file mode 100644 index 00000000..d09e52e1 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/InvulnerableUpdate.java @@ -0,0 +1,51 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import javax.annotation.Nonnull; + +public class InvulnerableUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 0; + + @Nonnull + public static InvulnerableUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + return new InvulnerableUpdate(); + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 0; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 0; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK; + } + + public InvulnerableUpdate clone() { + return new InvulnerableUpdate(); + } + + @Override + public boolean equals(Object obj) { + return this == obj ? true : obj instanceof InvulnerableUpdate other; + } + + @Override + public int hashCode() { + return 0; + } +} diff --git a/src/com/hypixel/hytale/protocol/ItemUpdate.java b/src/com/hypixel/hytale/protocol/ItemUpdate.java new file mode 100644 index 00000000..4367e454 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/ItemUpdate.java @@ -0,0 +1,96 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; + +public class ItemUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 4; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 4; + public static final int MAX_SIZE = 32768044; + @Nonnull + public ItemWithAllMetadata item = new ItemWithAllMetadata(); + public float entityScale; + + public ItemUpdate() { + } + + public ItemUpdate(@Nonnull ItemWithAllMetadata item, float entityScale) { + this.item = item; + this.entityScale = entityScale; + } + + public ItemUpdate(@Nonnull ItemUpdate other) { + this.item = other.item; + this.entityScale = other.entityScale; + } + + @Nonnull + public static ItemUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + ItemUpdate obj = new ItemUpdate(); + obj.entityScale = buf.getFloatLE(offset + 0); + int pos = offset + 4; + obj.item = ItemWithAllMetadata.deserialize(buf, pos); + pos += ItemWithAllMetadata.computeBytesConsumed(buf, pos); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int pos = offset + 4; + pos += ItemWithAllMetadata.computeBytesConsumed(buf, pos); + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + buf.writeFloatLE(this.entityScale); + this.item.serialize(buf); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + int size = 4; + return size + this.item.computeSize(); + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 4) { + return ValidationResult.error("Buffer too small: expected at least 4 bytes"); + } else { + int pos = offset + 4; + ValidationResult itemResult = ItemWithAllMetadata.validateStructure(buffer, pos); + if (!itemResult.isValid()) { + return ValidationResult.error("Invalid Item: " + itemResult.error()); + } else { + pos += ItemWithAllMetadata.computeBytesConsumed(buffer, pos); + return ValidationResult.OK; + } + } + } + + public ItemUpdate clone() { + ItemUpdate copy = new ItemUpdate(); + copy.item = this.item.clone(); + copy.entityScale = this.entityScale; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof ItemUpdate other) ? false : Objects.equals(this.item, other.item) && this.entityScale == other.entityScale; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.item, this.entityScale); + } +} diff --git a/src/com/hypixel/hytale/protocol/Model.java b/src/com/hypixel/hytale/protocol/Model.java index c84a02d8..09270fd6 100644 --- a/src/com/hypixel/hytale/protocol/Model.java +++ b/src/com/hypixel/hytale/protocol/Model.java @@ -15,9 +15,9 @@ import javax.annotation.Nullable; public class Model { public static final int NULLABLE_BIT_FIELD_SIZE = 2; - public static final int FIXED_BLOCK_SIZE = 43; + public static final int FIXED_BLOCK_SIZE = 51; public static final int VARIABLE_FIELD_COUNT = 12; - public static final int VARIABLE_BLOCK_START = 91; + public static final int VARIABLE_BLOCK_START = 99; public static final int MAX_SIZE = 1677721600; @Nullable public String assetId; @@ -34,6 +34,8 @@ public class Model { public float scale; public float eyeHeight; public float crouchOffset; + public float sittingOffset; + public float sleepingOffset; @Nullable public Map animationSets; @Nullable @@ -66,6 +68,8 @@ public class Model { float scale, float eyeHeight, float crouchOffset, + float sittingOffset, + float sleepingOffset, @Nullable Map animationSets, @Nullable ModelAttachment[] attachments, @Nullable Hitbox hitbox, @@ -85,6 +89,8 @@ public class Model { this.scale = scale; this.eyeHeight = eyeHeight; this.crouchOffset = crouchOffset; + this.sittingOffset = sittingOffset; + this.sleepingOffset = sleepingOffset; this.animationSets = animationSets; this.attachments = attachments; this.hitbox = hitbox; @@ -106,6 +112,8 @@ public class Model { this.scale = other.scale; this.eyeHeight = other.eyeHeight; this.crouchOffset = other.crouchOffset; + this.sittingOffset = other.sittingOffset; + this.sleepingOffset = other.sleepingOffset; this.animationSets = other.animationSets; this.attachments = other.attachments; this.hitbox = other.hitbox; @@ -124,17 +132,19 @@ public class Model { obj.scale = buf.getFloatLE(offset + 2); obj.eyeHeight = buf.getFloatLE(offset + 6); obj.crouchOffset = buf.getFloatLE(offset + 10); + obj.sittingOffset = buf.getFloatLE(offset + 14); + obj.sleepingOffset = buf.getFloatLE(offset + 18); if ((nullBits[0] & 1) != 0) { - obj.hitbox = Hitbox.deserialize(buf, offset + 14); + obj.hitbox = Hitbox.deserialize(buf, offset + 22); } if ((nullBits[0] & 2) != 0) { - obj.light = ColorLight.deserialize(buf, offset + 38); + obj.light = ColorLight.deserialize(buf, offset + 46); } - obj.phobia = Phobia.fromValue(buf.getByte(offset + 42)); + obj.phobia = Phobia.fromValue(buf.getByte(offset + 50)); if ((nullBits[0] & 4) != 0) { - int varPos0 = offset + 91 + buf.getIntLE(offset + 43); + int varPos0 = offset + 99 + buf.getIntLE(offset + 51); int assetIdLen = VarInt.peek(buf, varPos0); if (assetIdLen < 0) { throw ProtocolException.negativeLength("AssetId", assetIdLen); @@ -148,7 +158,7 @@ public class Model { } if ((nullBits[0] & 8) != 0) { - int varPos1 = offset + 91 + buf.getIntLE(offset + 47); + int varPos1 = offset + 99 + buf.getIntLE(offset + 55); int pathLen = VarInt.peek(buf, varPos1); if (pathLen < 0) { throw ProtocolException.negativeLength("Path", pathLen); @@ -162,7 +172,7 @@ public class Model { } if ((nullBits[0] & 16) != 0) { - int varPos2 = offset + 91 + buf.getIntLE(offset + 51); + int varPos2 = offset + 99 + buf.getIntLE(offset + 59); int textureLen = VarInt.peek(buf, varPos2); if (textureLen < 0) { throw ProtocolException.negativeLength("Texture", textureLen); @@ -176,7 +186,7 @@ public class Model { } if ((nullBits[0] & 32) != 0) { - int varPos3 = offset + 91 + buf.getIntLE(offset + 55); + int varPos3 = offset + 99 + buf.getIntLE(offset + 63); int gradientSetLen = VarInt.peek(buf, varPos3); if (gradientSetLen < 0) { throw ProtocolException.negativeLength("GradientSet", gradientSetLen); @@ -190,7 +200,7 @@ public class Model { } if ((nullBits[0] & 64) != 0) { - int varPos4 = offset + 91 + buf.getIntLE(offset + 59); + int varPos4 = offset + 99 + buf.getIntLE(offset + 67); int gradientIdLen = VarInt.peek(buf, varPos4); if (gradientIdLen < 0) { throw ProtocolException.negativeLength("GradientId", gradientIdLen); @@ -204,12 +214,12 @@ public class Model { } if ((nullBits[0] & 128) != 0) { - int varPos5 = offset + 91 + buf.getIntLE(offset + 63); + int varPos5 = offset + 99 + buf.getIntLE(offset + 71); obj.camera = CameraSettings.deserialize(buf, varPos5); } if ((nullBits[1] & 1) != 0) { - int varPos6 = offset + 91 + buf.getIntLE(offset + 67); + int varPos6 = offset + 99 + buf.getIntLE(offset + 75); int animationSetsCount = VarInt.peek(buf, varPos6); if (animationSetsCount < 0) { throw ProtocolException.negativeLength("AnimationSets", animationSetsCount); @@ -245,7 +255,7 @@ public class Model { } if ((nullBits[1] & 2) != 0) { - int varPos7 = offset + 91 + buf.getIntLE(offset + 71); + int varPos7 = offset + 99 + buf.getIntLE(offset + 79); int attachmentsCount = VarInt.peek(buf, varPos7); if (attachmentsCount < 0) { throw ProtocolException.negativeLength("Attachments", attachmentsCount); @@ -270,7 +280,7 @@ public class Model { } if ((nullBits[1] & 4) != 0) { - int varPos8 = offset + 91 + buf.getIntLE(offset + 75); + int varPos8 = offset + 99 + buf.getIntLE(offset + 83); int particlesCount = VarInt.peek(buf, varPos8); if (particlesCount < 0) { throw ProtocolException.negativeLength("Particles", particlesCount); @@ -295,7 +305,7 @@ public class Model { } if ((nullBits[1] & 8) != 0) { - int varPos9 = offset + 91 + buf.getIntLE(offset + 79); + int varPos9 = offset + 99 + buf.getIntLE(offset + 87); int trailsCount = VarInt.peek(buf, varPos9); if (trailsCount < 0) { throw ProtocolException.negativeLength("Trails", trailsCount); @@ -320,7 +330,7 @@ public class Model { } if ((nullBits[1] & 16) != 0) { - int varPos10 = offset + 91 + buf.getIntLE(offset + 83); + int varPos10 = offset + 99 + buf.getIntLE(offset + 91); int detailBoxesCount = VarInt.peek(buf, varPos10); if (detailBoxesCount < 0) { throw ProtocolException.negativeLength("DetailBoxes", detailBoxesCount); @@ -376,7 +386,7 @@ public class Model { } if ((nullBits[1] & 32) != 0) { - int varPos11 = offset + 91 + buf.getIntLE(offset + 87); + int varPos11 = offset + 99 + buf.getIntLE(offset + 95); obj.phobiaModel = deserialize(buf, varPos11); } @@ -385,10 +395,10 @@ public class Model { public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte[] nullBits = PacketIO.readBytes(buf, offset, 2); - int maxEnd = 91; + int maxEnd = 99; if ((nullBits[0] & 4) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 43); - int pos0 = offset + 91 + fieldOffset0; + int fieldOffset0 = buf.getIntLE(offset + 51); + int pos0 = offset + 99 + fieldOffset0; int sl = VarInt.peek(buf, pos0); pos0 += VarInt.length(buf, pos0) + sl; if (pos0 - offset > maxEnd) { @@ -397,8 +407,8 @@ public class Model { } if ((nullBits[0] & 8) != 0) { - int fieldOffset1 = buf.getIntLE(offset + 47); - int pos1 = offset + 91 + fieldOffset1; + int fieldOffset1 = buf.getIntLE(offset + 55); + int pos1 = offset + 99 + fieldOffset1; int sl = VarInt.peek(buf, pos1); pos1 += VarInt.length(buf, pos1) + sl; if (pos1 - offset > maxEnd) { @@ -407,8 +417,8 @@ public class Model { } if ((nullBits[0] & 16) != 0) { - int fieldOffset2 = buf.getIntLE(offset + 51); - int pos2 = offset + 91 + fieldOffset2; + int fieldOffset2 = buf.getIntLE(offset + 59); + int pos2 = offset + 99 + fieldOffset2; int sl = VarInt.peek(buf, pos2); pos2 += VarInt.length(buf, pos2) + sl; if (pos2 - offset > maxEnd) { @@ -417,8 +427,8 @@ public class Model { } if ((nullBits[0] & 32) != 0) { - int fieldOffset3 = buf.getIntLE(offset + 55); - int pos3 = offset + 91 + fieldOffset3; + int fieldOffset3 = buf.getIntLE(offset + 63); + int pos3 = offset + 99 + fieldOffset3; int sl = VarInt.peek(buf, pos3); pos3 += VarInt.length(buf, pos3) + sl; if (pos3 - offset > maxEnd) { @@ -427,8 +437,8 @@ public class Model { } if ((nullBits[0] & 64) != 0) { - int fieldOffset4 = buf.getIntLE(offset + 59); - int pos4 = offset + 91 + fieldOffset4; + int fieldOffset4 = buf.getIntLE(offset + 67); + int pos4 = offset + 99 + fieldOffset4; int sl = VarInt.peek(buf, pos4); pos4 += VarInt.length(buf, pos4) + sl; if (pos4 - offset > maxEnd) { @@ -437,8 +447,8 @@ public class Model { } if ((nullBits[0] & 128) != 0) { - int fieldOffset5 = buf.getIntLE(offset + 63); - int pos5 = offset + 91 + fieldOffset5; + int fieldOffset5 = buf.getIntLE(offset + 71); + int pos5 = offset + 99 + fieldOffset5; pos5 += CameraSettings.computeBytesConsumed(buf, pos5); if (pos5 - offset > maxEnd) { maxEnd = pos5 - offset; @@ -446,8 +456,8 @@ public class Model { } if ((nullBits[1] & 1) != 0) { - int fieldOffset6 = buf.getIntLE(offset + 67); - int pos6 = offset + 91 + fieldOffset6; + int fieldOffset6 = buf.getIntLE(offset + 75); + int pos6 = offset + 99 + fieldOffset6; int dictLen = VarInt.peek(buf, pos6); pos6 += VarInt.length(buf, pos6); @@ -463,8 +473,8 @@ public class Model { } if ((nullBits[1] & 2) != 0) { - int fieldOffset7 = buf.getIntLE(offset + 71); - int pos7 = offset + 91 + fieldOffset7; + int fieldOffset7 = buf.getIntLE(offset + 79); + int pos7 = offset + 99 + fieldOffset7; int arrLen = VarInt.peek(buf, pos7); pos7 += VarInt.length(buf, pos7); @@ -478,8 +488,8 @@ public class Model { } if ((nullBits[1] & 4) != 0) { - int fieldOffset8 = buf.getIntLE(offset + 75); - int pos8 = offset + 91 + fieldOffset8; + int fieldOffset8 = buf.getIntLE(offset + 83); + int pos8 = offset + 99 + fieldOffset8; int arrLen = VarInt.peek(buf, pos8); pos8 += VarInt.length(buf, pos8); @@ -493,8 +503,8 @@ public class Model { } if ((nullBits[1] & 8) != 0) { - int fieldOffset9 = buf.getIntLE(offset + 79); - int pos9 = offset + 91 + fieldOffset9; + int fieldOffset9 = buf.getIntLE(offset + 87); + int pos9 = offset + 99 + fieldOffset9; int arrLen = VarInt.peek(buf, pos9); pos9 += VarInt.length(buf, pos9); @@ -508,8 +518,8 @@ public class Model { } if ((nullBits[1] & 16) != 0) { - int fieldOffset10 = buf.getIntLE(offset + 83); - int pos10 = offset + 91 + fieldOffset10; + int fieldOffset10 = buf.getIntLE(offset + 91); + int pos10 = offset + 99 + fieldOffset10; int dictLen = VarInt.peek(buf, pos10); pos10 += VarInt.length(buf, pos10); @@ -530,8 +540,8 @@ public class Model { } if ((nullBits[1] & 32) != 0) { - int fieldOffset11 = buf.getIntLE(offset + 87); - int pos11 = offset + 91 + fieldOffset11; + int fieldOffset11 = buf.getIntLE(offset + 95); + int pos11 = offset + 99 + fieldOffset11; pos11 += computeBytesConsumed(buf, pos11); if (pos11 - offset > maxEnd) { maxEnd = pos11 - offset; @@ -604,6 +614,8 @@ public class Model { buf.writeFloatLE(this.scale); buf.writeFloatLE(this.eyeHeight); buf.writeFloatLE(this.crouchOffset); + buf.writeFloatLE(this.sittingOffset); + buf.writeFloatLE(this.sleepingOffset); if (this.hitbox != null) { this.hitbox.serialize(buf); } else { @@ -774,7 +786,7 @@ public class Model { } public int computeSize() { - int size = 91; + int size = 99; if (this.assetId != null) { size += PacketIO.stringSize(this.assetId); } @@ -857,17 +869,17 @@ public class Model { } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 91) { - return ValidationResult.error("Buffer too small: expected at least 91 bytes"); + if (buffer.readableBytes() - offset < 99) { + return ValidationResult.error("Buffer too small: expected at least 99 bytes"); } else { byte[] nullBits = PacketIO.readBytes(buffer, offset, 2); if ((nullBits[0] & 4) != 0) { - int assetIdOffset = buffer.getIntLE(offset + 43); + int assetIdOffset = buffer.getIntLE(offset + 51); if (assetIdOffset < 0) { return ValidationResult.error("Invalid offset for AssetId"); } - int pos = offset + 91 + assetIdOffset; + int pos = offset + 99 + assetIdOffset; if (pos >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for AssetId"); } @@ -889,12 +901,12 @@ public class Model { } if ((nullBits[0] & 8) != 0) { - int pathOffset = buffer.getIntLE(offset + 47); + int pathOffset = buffer.getIntLE(offset + 55); if (pathOffset < 0) { return ValidationResult.error("Invalid offset for Path"); } - int posx = offset + 91 + pathOffset; + int posx = offset + 99 + pathOffset; if (posx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Path"); } @@ -916,12 +928,12 @@ public class Model { } if ((nullBits[0] & 16) != 0) { - int textureOffset = buffer.getIntLE(offset + 51); + int textureOffset = buffer.getIntLE(offset + 59); if (textureOffset < 0) { return ValidationResult.error("Invalid offset for Texture"); } - int posxx = offset + 91 + textureOffset; + int posxx = offset + 99 + textureOffset; if (posxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Texture"); } @@ -943,12 +955,12 @@ public class Model { } if ((nullBits[0] & 32) != 0) { - int gradientSetOffset = buffer.getIntLE(offset + 55); + int gradientSetOffset = buffer.getIntLE(offset + 63); if (gradientSetOffset < 0) { return ValidationResult.error("Invalid offset for GradientSet"); } - int posxxx = offset + 91 + gradientSetOffset; + int posxxx = offset + 99 + gradientSetOffset; if (posxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for GradientSet"); } @@ -970,12 +982,12 @@ public class Model { } if ((nullBits[0] & 64) != 0) { - int gradientIdOffset = buffer.getIntLE(offset + 59); + int gradientIdOffset = buffer.getIntLE(offset + 67); if (gradientIdOffset < 0) { return ValidationResult.error("Invalid offset for GradientId"); } - int posxxxx = offset + 91 + gradientIdOffset; + int posxxxx = offset + 99 + gradientIdOffset; if (posxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for GradientId"); } @@ -997,12 +1009,12 @@ public class Model { } if ((nullBits[0] & 128) != 0) { - int cameraOffset = buffer.getIntLE(offset + 63); + int cameraOffset = buffer.getIntLE(offset + 71); if (cameraOffset < 0) { return ValidationResult.error("Invalid offset for Camera"); } - int posxxxxx = offset + 91 + cameraOffset; + int posxxxxx = offset + 99 + cameraOffset; if (posxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Camera"); } @@ -1016,12 +1028,12 @@ public class Model { } if ((nullBits[1] & 1) != 0) { - int animationSetsOffset = buffer.getIntLE(offset + 67); + int animationSetsOffset = buffer.getIntLE(offset + 75); if (animationSetsOffset < 0) { return ValidationResult.error("Invalid offset for AnimationSets"); } - int posxxxxxx = offset + 91 + animationSetsOffset; + int posxxxxxx = offset + 99 + animationSetsOffset; if (posxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for AnimationSets"); } @@ -1058,12 +1070,12 @@ public class Model { } if ((nullBits[1] & 2) != 0) { - int attachmentsOffset = buffer.getIntLE(offset + 71); + int attachmentsOffset = buffer.getIntLE(offset + 79); if (attachmentsOffset < 0) { return ValidationResult.error("Invalid offset for Attachments"); } - int posxxxxxxx = offset + 91 + attachmentsOffset; + int posxxxxxxx = offset + 99 + attachmentsOffset; if (posxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Attachments"); } @@ -1090,12 +1102,12 @@ public class Model { } if ((nullBits[1] & 4) != 0) { - int particlesOffset = buffer.getIntLE(offset + 75); + int particlesOffset = buffer.getIntLE(offset + 83); if (particlesOffset < 0) { return ValidationResult.error("Invalid offset for Particles"); } - int posxxxxxxxx = offset + 91 + particlesOffset; + int posxxxxxxxx = offset + 99 + particlesOffset; if (posxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Particles"); } @@ -1122,12 +1134,12 @@ public class Model { } if ((nullBits[1] & 8) != 0) { - int trailsOffset = buffer.getIntLE(offset + 79); + int trailsOffset = buffer.getIntLE(offset + 87); if (trailsOffset < 0) { return ValidationResult.error("Invalid offset for Trails"); } - int posxxxxxxxxx = offset + 91 + trailsOffset; + int posxxxxxxxxx = offset + 99 + trailsOffset; if (posxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Trails"); } @@ -1154,12 +1166,12 @@ public class Model { } if ((nullBits[1] & 16) != 0) { - int detailBoxesOffset = buffer.getIntLE(offset + 83); + int detailBoxesOffset = buffer.getIntLE(offset + 91); if (detailBoxesOffset < 0) { return ValidationResult.error("Invalid offset for DetailBoxes"); } - int posxxxxxxxxxx = offset + 91 + detailBoxesOffset; + int posxxxxxxxxxx = offset + 99 + detailBoxesOffset; if (posxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for DetailBoxes"); } @@ -1205,12 +1217,12 @@ public class Model { } if ((nullBits[1] & 32) != 0) { - int phobiaModelOffset = buffer.getIntLE(offset + 87); + int phobiaModelOffset = buffer.getIntLE(offset + 95); if (phobiaModelOffset < 0) { return ValidationResult.error("Invalid offset for PhobiaModel"); } - int posxxxxxxxxxxx = offset + 91 + phobiaModelOffset; + int posxxxxxxxxxxx = offset + 99 + phobiaModelOffset; if (posxxxxxxxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for PhobiaModel"); } @@ -1238,6 +1250,8 @@ public class Model { copy.scale = this.scale; copy.eyeHeight = this.eyeHeight; copy.crouchOffset = this.crouchOffset; + copy.sittingOffset = this.sittingOffset; + copy.sleepingOffset = this.sleepingOffset; if (this.animationSets != null) { Map m = new HashMap<>(); @@ -1284,6 +1298,8 @@ public class Model { && this.scale == other.scale && this.eyeHeight == other.eyeHeight && this.crouchOffset == other.crouchOffset + && this.sittingOffset == other.sittingOffset + && this.sleepingOffset == other.sleepingOffset && Objects.equals(this.animationSets, other.animationSets) && Arrays.equals((Object[])this.attachments, (Object[])other.attachments) && Objects.equals(this.hitbox, other.hitbox) @@ -1308,6 +1324,8 @@ public class Model { result = 31 * result + Float.hashCode(this.scale); result = 31 * result + Float.hashCode(this.eyeHeight); result = 31 * result + Float.hashCode(this.crouchOffset); + result = 31 * result + Float.hashCode(this.sittingOffset); + result = 31 * result + Float.hashCode(this.sleepingOffset); result = 31 * result + Objects.hashCode(this.animationSets); result = 31 * result + Arrays.hashCode((Object[])this.attachments); result = 31 * result + Objects.hashCode(this.hitbox); diff --git a/src/com/hypixel/hytale/protocol/ModelUpdate.java b/src/com/hypixel/hytale/protocol/ModelUpdate.java new file mode 100644 index 00000000..c8b67a39 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/ModelUpdate.java @@ -0,0 +1,122 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ModelUpdate extends ComponentUpdate { + 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 = 1677721600; + @Nullable + public Model model; + public float entityScale; + + public ModelUpdate() { + } + + public ModelUpdate(@Nullable Model model, float entityScale) { + this.model = model; + this.entityScale = entityScale; + } + + public ModelUpdate(@Nonnull ModelUpdate other) { + this.model = other.model; + this.entityScale = other.entityScale; + } + + @Nonnull + public static ModelUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + ModelUpdate obj = new ModelUpdate(); + byte nullBits = buf.getByte(offset); + obj.entityScale = buf.getFloatLE(offset + 1); + int pos = offset + 5; + if ((nullBits & 1) != 0) { + obj.model = Model.deserialize(buf, pos); + pos += Model.computeBytesConsumed(buf, pos); + } + + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + byte nullBits = buf.getByte(offset); + int pos = offset + 5; + if ((nullBits & 1) != 0) { + pos += Model.computeBytesConsumed(buf, pos); + } + + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + byte nullBits = 0; + if (this.model != null) { + nullBits = (byte)(nullBits | 1); + } + + buf.writeByte(nullBits); + buf.writeFloatLE(this.entityScale); + if (this.model != null) { + this.model.serialize(buf); + } + + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + int size = 5; + if (this.model != null) { + size += this.model.computeSize(); + } + + 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) { + ValidationResult modelResult = Model.validateStructure(buffer, pos); + if (!modelResult.isValid()) { + return ValidationResult.error("Invalid Model: " + modelResult.error()); + } + + pos += Model.computeBytesConsumed(buffer, pos); + } + + return ValidationResult.OK; + } + } + + public ModelUpdate clone() { + ModelUpdate copy = new ModelUpdate(); + copy.model = this.model != null ? this.model.clone() : null; + copy.entityScale = this.entityScale; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof ModelUpdate other) ? false : Objects.equals(this.model, other.model) && this.entityScale == other.entityScale; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.model, this.entityScale); + } +} diff --git a/src/com/hypixel/hytale/protocol/MountedUpdate.java b/src/com/hypixel/hytale/protocol/MountedUpdate.java index 31d35e1d..22332a03 100644 --- a/src/com/hypixel/hytale/protocol/MountedUpdate.java +++ b/src/com/hypixel/hytale/protocol/MountedUpdate.java @@ -6,7 +6,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class MountedUpdate { +public class MountedUpdate extends ComponentUpdate { public static final int NULLABLE_BIT_FIELD_SIZE = 1; public static final int FIXED_BLOCK_SIZE = 48; public static final int VARIABLE_FIELD_COUNT = 0; @@ -58,7 +58,9 @@ public class MountedUpdate { return 48; } - public void serialize(@Nonnull ByteBuf buf) { + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); byte nullBits = 0; if (this.attachmentOffset != null) { nullBits = (byte)(nullBits | 1); @@ -82,8 +84,11 @@ public class MountedUpdate { } else { buf.writeZero(30); } + + return buf.writerIndex() - startPos; } + @Override public int computeSize() { return 48; } diff --git a/src/com/hypixel/hytale/protocol/MovementStatesUpdate.java b/src/com/hypixel/hytale/protocol/MovementStatesUpdate.java new file mode 100644 index 00000000..0ef57666 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/MovementStatesUpdate.java @@ -0,0 +1,74 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; + +public class MovementStatesUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 22; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 22; + public static final int MAX_SIZE = 22; + @Nonnull + public MovementStates movementStates = new MovementStates(); + + public MovementStatesUpdate() { + } + + public MovementStatesUpdate(@Nonnull MovementStates movementStates) { + this.movementStates = movementStates; + } + + public MovementStatesUpdate(@Nonnull MovementStatesUpdate other) { + this.movementStates = other.movementStates; + } + + @Nonnull + public static MovementStatesUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + MovementStatesUpdate obj = new MovementStatesUpdate(); + obj.movementStates = MovementStates.deserialize(buf, offset + 0); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 22; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + this.movementStates.serialize(buf); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 22; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 22 ? ValidationResult.error("Buffer too small: expected at least 22 bytes") : ValidationResult.OK; + } + + public MovementStatesUpdate clone() { + MovementStatesUpdate copy = new MovementStatesUpdate(); + copy.movementStates = this.movementStates.clone(); + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof MovementStatesUpdate other ? Objects.equals(this.movementStates, other.movementStates) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.movementStates); + } +} diff --git a/src/com/hypixel/hytale/protocol/NameplateUpdate.java b/src/com/hypixel/hytale/protocol/NameplateUpdate.java new file mode 100644 index 00000000..69de5d1f --- /dev/null +++ b/src/com/hypixel/hytale/protocol/NameplateUpdate.java @@ -0,0 +1,105 @@ +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; + +public class NameplateUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 16384005; + @Nonnull + public String text = ""; + + public NameplateUpdate() { + } + + public NameplateUpdate(@Nonnull String text) { + this.text = text; + } + + public NameplateUpdate(@Nonnull NameplateUpdate other) { + this.text = other.text; + } + + @Nonnull + public static NameplateUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + NameplateUpdate obj = new NameplateUpdate(); + int pos = offset + 0; + int textLen = VarInt.peek(buf, pos); + if (textLen < 0) { + throw ProtocolException.negativeLength("Text", textLen); + } else if (textLen > 4096000) { + throw ProtocolException.stringTooLong("Text", textLen, 4096000); + } else { + int textVarLen = VarInt.length(buf, pos); + obj.text = PacketIO.readVarString(buf, pos, PacketIO.UTF8); + pos += textVarLen + textLen; + return obj; + } + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int pos = offset + 0; + int sl = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos) + sl; + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + PacketIO.writeVarString(buf, this.text, 4096000); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + int size = 0; + return size + PacketIO.stringSize(this.text); + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 0) { + return ValidationResult.error("Buffer too small: expected at least 0 bytes"); + } else { + int pos = offset + 0; + int textLen = VarInt.peek(buffer, pos); + if (textLen < 0) { + return ValidationResult.error("Invalid string length for Text"); + } else if (textLen > 4096000) { + return ValidationResult.error("Text exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + pos += textLen; + return pos > buffer.writerIndex() ? ValidationResult.error("Buffer overflow reading Text") : ValidationResult.OK; + } + } + } + + public NameplateUpdate clone() { + NameplateUpdate copy = new NameplateUpdate(); + copy.text = this.text; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof NameplateUpdate other ? Objects.equals(this.text, other.text) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.text); + } +} diff --git a/src/com/hypixel/hytale/protocol/NetworkChannel.java b/src/com/hypixel/hytale/protocol/NetworkChannel.java new file mode 100644 index 00000000..c605e321 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/NetworkChannel.java @@ -0,0 +1,27 @@ +package com.hypixel.hytale.protocol; + +public enum NetworkChannel { + Default(0), + Chunks(1), + WorldMap(2); + + public static final NetworkChannel[] VALUES = values(); + public static final int COUNT = VALUES.length; + private final int value; + + private NetworkChannel(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } + + public static NetworkChannel fromValue(int value) { + if (value >= 0 && value < VALUES.length) { + return VALUES[value]; + } else { + throw new IllegalArgumentException("Invalid network channel: " + value); + } + } +} diff --git a/src/com/hypixel/hytale/protocol/NewSpawnUpdate.java b/src/com/hypixel/hytale/protocol/NewSpawnUpdate.java new file mode 100644 index 00000000..09a0de4d --- /dev/null +++ b/src/com/hypixel/hytale/protocol/NewSpawnUpdate.java @@ -0,0 +1,51 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import javax.annotation.Nonnull; + +public class NewSpawnUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 0; + + @Nonnull + public static NewSpawnUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + return new NewSpawnUpdate(); + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 0; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 0; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK; + } + + public NewSpawnUpdate clone() { + return new NewSpawnUpdate(); + } + + @Override + public boolean equals(Object obj) { + return this == obj ? true : obj instanceof NewSpawnUpdate other; + } + + @Override + public int hashCode() { + return 0; + } +} 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/Packet.java b/src/com/hypixel/hytale/protocol/Packet.java index 673767ab..bd23ee0d 100644 --- a/src/com/hypixel/hytale/protocol/Packet.java +++ b/src/com/hypixel/hytale/protocol/Packet.java @@ -6,6 +6,8 @@ import javax.annotation.Nonnull; public interface Packet { int getId(); + NetworkChannel getChannel(); + void serialize(@Nonnull ByteBuf var1); int computeSize(); diff --git a/src/com/hypixel/hytale/protocol/PacketRegistry.java b/src/com/hypixel/hytale/protocol/PacketRegistry.java index e3e8d3bd..2e06be79 100644 --- a/src/com/hypixel/hytale/protocol/PacketRegistry.java +++ b/src/com/hypixel/hytale/protocol/PacketRegistry.java @@ -15,7 +15,6 @@ import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorDeleteAsset; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorDeleteAssetPack; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorDeleteDirectory; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorDiscardChanges; -import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorEnableAssetPack; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorExportAssetFinalize; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorExportAssetInitialize; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorExportAssetPart; @@ -34,7 +33,6 @@ import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorJsonAssetUpdat import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorLastModifiedAssets; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorModifiedAssetsCount; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorPopupNotification; -import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorRebuildCaches; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorRedoChanges; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorRenameAsset; import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorRenameDirectory; @@ -111,7 +109,6 @@ import com.hypixel.hytale.protocol.packets.auth.PasswordAccepted; import com.hypixel.hytale.protocol.packets.auth.PasswordRejected; import com.hypixel.hytale.protocol.packets.auth.PasswordResponse; import com.hypixel.hytale.protocol.packets.auth.ServerAuthToken; -import com.hypixel.hytale.protocol.packets.auth.Status; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolArgUpdate; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolEntityAction; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolExtrudeAction; @@ -126,6 +123,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; @@ -172,6 +170,7 @@ import com.hypixel.hytale.protocol.packets.interface_.ServerInfo; import com.hypixel.hytale.protocol.packets.interface_.ServerMessage; import com.hypixel.hytale.protocol.packets.interface_.SetPage; import com.hypixel.hytale.protocol.packets.interface_.ShowEventTitle; +import com.hypixel.hytale.protocol.packets.interface_.UpdateAnchorUI; import com.hypixel.hytale.protocol.packets.interface_.UpdateKnownRecipes; import com.hypixel.hytale.protocol.packets.interface_.UpdateLanguage; import com.hypixel.hytale.protocol.packets.interface_.UpdatePortal; @@ -264,6 +263,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; @@ -279,6 +279,8 @@ import javax.annotation.Nullable; public final class PacketRegistry { private static final Map BY_ID = new HashMap<>(); + private static final Map TO_SERVER_BY_ID = new HashMap<>(); + private static final Map TO_CLIENT_BY_ID = new HashMap<>(); private static final Map BY_ID_UNMODIFIABLE = Collections.unmodifiableMap(BY_ID); private static final Map, Integer> BY_TYPE = new HashMap<>(); @@ -286,6 +288,8 @@ public final class PacketRegistry { } private static void register( + PacketRegistry.PacketDirection direction, + NetworkChannel channel, int id, String name, Class type, @@ -299,15 +303,32 @@ public final class PacketRegistry { if (existing != null) { throw new IllegalStateException("Duplicate packet ID " + id + ": '" + name + "' conflicts with '" + existing.name() + "'"); } else { - PacketRegistry.PacketInfo info = new PacketRegistry.PacketInfo(id, name, type, fixedBlockSize, maxSize, compressed, validate, deserialize); + PacketRegistry.PacketInfo info = new PacketRegistry.PacketInfo(id, name, channel, type, fixedBlockSize, maxSize, compressed, validate, deserialize); + switch (direction) { + case ToServer: + TO_SERVER_BY_ID.put(id, info); + break; + case ToClient: + TO_CLIENT_BY_ID.put(id, info); + break; + case Both: + TO_SERVER_BY_ID.put(id, info); + TO_CLIENT_BY_ID.put(id, info); + } + BY_ID.put(id, info); BY_TYPE.put(type, id); } } @Nullable - public static PacketRegistry.PacketInfo getById(int id) { - return BY_ID.get(id); + public static PacketRegistry.PacketInfo getToServerPacketById(int id) { + return TO_SERVER_BY_ID.get(id); + } + + @Nullable + public static PacketRegistry.PacketInfo getToClientPacketById(int id) { + return TO_CLIENT_BY_ID.get(id); } @Nullable @@ -321,28 +342,231 @@ public final class PacketRegistry { } static { - register(0, "Connect", Connect.class, 46, 38013, false, Connect::validateStructure, Connect::deserialize); - register(1, "Disconnect", Disconnect.class, 2, 16384007, false, Disconnect::validateStructure, Disconnect::deserialize); - register(2, "Ping", Ping.class, 29, 29, false, Ping::validateStructure, Ping::deserialize); - register(3, "Pong", Pong.class, 20, 20, false, Pong::validateStructure, Pong::deserialize); - register(10, "Status", Status.class, 9, 2587, false, Status::validateStructure, Status::deserialize); - register(11, "AuthGrant", AuthGrant.class, 1, 49171, false, AuthGrant::validateStructure, AuthGrant::deserialize); - register(12, "AuthToken", AuthToken.class, 1, 49171, false, AuthToken::validateStructure, AuthToken::deserialize); - register(13, "ServerAuthToken", ServerAuthToken.class, 1, 32851, false, ServerAuthToken::validateStructure, ServerAuthToken::deserialize); - register(14, "ConnectAccept", ConnectAccept.class, 1, 70, false, ConnectAccept::validateStructure, ConnectAccept::deserialize); - register(15, "PasswordResponse", PasswordResponse.class, 1, 70, false, PasswordResponse::validateStructure, PasswordResponse::deserialize); - register(16, "PasswordAccepted", PasswordAccepted.class, 0, 0, false, PasswordAccepted::validateStructure, PasswordAccepted::deserialize); - 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(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); - register(25, "AssetPart", AssetPart.class, 1, 4096006, true, AssetPart::validateStructure, AssetPart::deserialize); - register(26, "AssetFinalize", AssetFinalize.class, 0, 0, false, AssetFinalize::validateStructure, AssetFinalize::deserialize); - register(27, "RemoveAssets", RemoveAssets.class, 1, 1677721600, false, RemoveAssets::validateStructure, RemoveAssets::deserialize); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 0, + "Connect", + Connect.class, + 46, + 38013, + false, + Connect::validateStructure, + Connect::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 1, + "Disconnect", + Disconnect.class, + 2, + 16384007, + false, + Disconnect::validateStructure, + Disconnect::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, NetworkChannel.Default, 2, "Ping", Ping.class, 29, 29, false, Ping::validateStructure, Ping::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, NetworkChannel.Default, 3, "Pong", Pong.class, 20, 20, false, Pong::validateStructure, Pong::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 11, + "AuthGrant", + AuthGrant.class, + 1, + 49171, + false, + AuthGrant::validateStructure, + AuthGrant::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 12, + "AuthToken", + AuthToken.class, + 1, + 49171, + false, + AuthToken::validateStructure, + AuthToken::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 13, + "ServerAuthToken", + ServerAuthToken.class, + 1, + 32851, + false, + ServerAuthToken::validateStructure, + ServerAuthToken::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 14, + "ConnectAccept", + ConnectAccept.class, + 1, + 70, + false, + ConnectAccept::validateStructure, + ConnectAccept::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 15, + "PasswordResponse", + PasswordResponse.class, + 1, + 70, + false, + PasswordResponse::validateStructure, + PasswordResponse::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 16, + "PasswordAccepted", + PasswordAccepted.class, + 0, + 0, + false, + PasswordAccepted::validateStructure, + PasswordAccepted::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 17, + "PasswordRejected", + PasswordRejected.class, + 5, + 74, + false, + PasswordRejected::validateStructure, + PasswordRejected::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 18, + "ClientReferral", + ClientReferral.class, + 1, + 5141, + false, + ClientReferral::validateStructure, + ClientReferral::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 20, + "WorldSettings", + WorldSettings.class, + 5, + 1677721600, + true, + WorldSettings::validateStructure, + WorldSettings::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 21, + "WorldLoadProgress", + WorldLoadProgress.class, + 9, + 1677721600, + false, + WorldLoadProgress::validateStructure, + WorldLoadProgress::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 22, + "WorldLoadFinished", + WorldLoadFinished.class, + 0, + 0, + false, + WorldLoadFinished::validateStructure, + WorldLoadFinished::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 23, + "RequestAssets", + RequestAssets.class, + 1, + 1677721600, + true, + RequestAssets::validateStructure, + RequestAssets::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 24, + "AssetInitialize", + AssetInitialize.class, + 4, + 2121, + false, + AssetInitialize::validateStructure, + AssetInitialize::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 25, + "AssetPart", + AssetPart.class, + 1, + 4096006, + true, + AssetPart::validateStructure, + AssetPart::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 26, + "AssetFinalize", + AssetFinalize.class, + 0, + 0, + false, + AssetFinalize::validateStructure, + AssetFinalize::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 27, + "RemoveAssets", + RemoveAssets.class, + 1, + 1677721600, + false, + RemoveAssets::validateStructure, + RemoveAssets::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 28, "RequestCommonAssetsRebuild", RequestCommonAssetsRebuild.class, @@ -352,17 +576,105 @@ public final class PacketRegistry { RequestCommonAssetsRebuild::validateStructure, RequestCommonAssetsRebuild::deserialize ); - register(29, "SetUpdateRate", SetUpdateRate.class, 4, 4, false, SetUpdateRate::validateStructure, SetUpdateRate::deserialize); - register(30, "SetTimeDilation", SetTimeDilation.class, 4, 4, false, SetTimeDilation::validateStructure, SetTimeDilation::deserialize); - register(31, "UpdateFeatures", UpdateFeatures.class, 1, 8192006, false, UpdateFeatures::validateStructure, UpdateFeatures::deserialize); - register(32, "ViewRadius", ViewRadius.class, 4, 4, false, ViewRadius::validateStructure, ViewRadius::deserialize); - register(33, "PlayerOptions", PlayerOptions.class, 1, 327680184, false, PlayerOptions::validateStructure, PlayerOptions::deserialize); - register(34, "ServerTags", ServerTags.class, 1, 1677721600, false, ServerTags::validateStructure, ServerTags::deserialize); - register(40, "UpdateBlockTypes", UpdateBlockTypes.class, 10, 1677721600, true, UpdateBlockTypes::validateStructure, UpdateBlockTypes::deserialize); register( - 41, "UpdateBlockHitboxes", UpdateBlockHitboxes.class, 6, 1677721600, true, UpdateBlockHitboxes::validateStructure, UpdateBlockHitboxes::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 29, + "SetUpdateRate", + SetUpdateRate.class, + 4, + 4, + false, + SetUpdateRate::validateStructure, + SetUpdateRate::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 30, + "SetTimeDilation", + SetTimeDilation.class, + 4, + 4, + false, + SetTimeDilation::validateStructure, + SetTimeDilation::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 31, + "UpdateFeatures", + UpdateFeatures.class, + 1, + 8192006, + false, + UpdateFeatures::validateStructure, + UpdateFeatures::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 32, + "ViewRadius", + ViewRadius.class, + 4, + 4, + false, + ViewRadius::validateStructure, + ViewRadius::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 33, + "PlayerOptions", + PlayerOptions.class, + 1, + 327680184, + false, + PlayerOptions::validateStructure, + PlayerOptions::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 34, + "ServerTags", + ServerTags.class, + 1, + 1677721600, + false, + ServerTags::validateStructure, + ServerTags::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 40, + "UpdateBlockTypes", + UpdateBlockTypes.class, + 10, + 1677721600, + true, + UpdateBlockTypes::validateStructure, + UpdateBlockTypes::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 41, + "UpdateBlockHitboxes", + UpdateBlockHitboxes.class, + 6, + 1677721600, + true, + UpdateBlockHitboxes::validateStructure, + UpdateBlockHitboxes::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 42, "UpdateBlockSoundSets", UpdateBlockSoundSets.class, @@ -373,9 +685,20 @@ public final class PacketRegistry { UpdateBlockSoundSets::deserialize ); register( - 43, "UpdateItemSoundSets", UpdateItemSoundSets.class, 6, 1677721600, true, UpdateItemSoundSets::validateStructure, UpdateItemSoundSets::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 43, + "UpdateItemSoundSets", + UpdateItemSoundSets.class, + 6, + 1677721600, + true, + UpdateItemSoundSets::validateStructure, + UpdateItemSoundSets::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 44, "UpdateBlockParticleSets", UpdateBlockParticleSets.class, @@ -386,6 +709,8 @@ public final class PacketRegistry { UpdateBlockParticleSets::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 45, "UpdateBlockBreakingDecals", UpdateBlockBreakingDecals.class, @@ -395,10 +720,45 @@ public final class PacketRegistry { UpdateBlockBreakingDecals::validateStructure, UpdateBlockBreakingDecals::deserialize ); - register(46, "UpdateBlockSets", UpdateBlockSets.class, 2, 1677721600, true, UpdateBlockSets::validateStructure, UpdateBlockSets::deserialize); - register(47, "UpdateWeathers", UpdateWeathers.class, 6, 1677721600, true, UpdateWeathers::validateStructure, UpdateWeathers::deserialize); - register(48, "UpdateTrails", UpdateTrails.class, 2, 1677721600, true, UpdateTrails::validateStructure, UpdateTrails::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 46, + "UpdateBlockSets", + UpdateBlockSets.class, + 2, + 1677721600, + true, + UpdateBlockSets::validateStructure, + UpdateBlockSets::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 47, + "UpdateWeathers", + UpdateWeathers.class, + 6, + 1677721600, + true, + UpdateWeathers::validateStructure, + UpdateWeathers::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 48, + "UpdateTrails", + UpdateTrails.class, + 2, + 1677721600, + true, + UpdateTrails::validateStructure, + UpdateTrails::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 49, "UpdateParticleSystems", UpdateParticleSystems.class, @@ -409,6 +769,8 @@ public final class PacketRegistry { UpdateParticleSystems::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 50, "UpdateParticleSpawners", UpdateParticleSpawners.class, @@ -419,9 +781,20 @@ public final class PacketRegistry { UpdateParticleSpawners::deserialize ); register( - 51, "UpdateEntityEffects", UpdateEntityEffects.class, 6, 1677721600, true, UpdateEntityEffects::validateStructure, UpdateEntityEffects::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 51, + "UpdateEntityEffects", + UpdateEntityEffects.class, + 6, + 1677721600, + true, + UpdateEntityEffects::validateStructure, + UpdateEntityEffects::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 52, "UpdateItemPlayerAnimations", UpdateItemPlayerAnimations.class, @@ -431,12 +804,45 @@ public final class PacketRegistry { UpdateItemPlayerAnimations::validateStructure, UpdateItemPlayerAnimations::deserialize ); - register(53, "UpdateModelvfxs", UpdateModelvfxs.class, 6, 1677721600, true, UpdateModelvfxs::validateStructure, UpdateModelvfxs::deserialize); - register(54, "UpdateItems", UpdateItems.class, 4, 1677721600, true, UpdateItems::validateStructure, UpdateItems::deserialize); register( - 55, "UpdateItemQualities", UpdateItemQualities.class, 6, 1677721600, true, UpdateItemQualities::validateStructure, UpdateItemQualities::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 53, + "UpdateModelvfxs", + UpdateModelvfxs.class, + 6, + 1677721600, + true, + UpdateModelvfxs::validateStructure, + UpdateModelvfxs::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 54, + "UpdateItems", + UpdateItems.class, + 4, + 1677721600, + true, + UpdateItems::validateStructure, + UpdateItems::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 55, + "UpdateItemQualities", + UpdateItemQualities.class, + 6, + 1677721600, + true, + UpdateItemQualities::validateStructure, + UpdateItemQualities::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 56, "UpdateItemCategories", UpdateItemCategories.class, @@ -446,8 +852,21 @@ public final class PacketRegistry { UpdateItemCategories::validateStructure, UpdateItemCategories::deserialize ); - register(57, "UpdateItemReticles", UpdateItemReticles.class, 6, 1677721600, true, UpdateItemReticles::validateStructure, UpdateItemReticles::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 57, + "UpdateItemReticles", + UpdateItemReticles.class, + 6, + 1677721600, + true, + UpdateItemReticles::validateStructure, + UpdateItemReticles::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 58, "UpdateFieldcraftCategories", UpdateFieldcraftCategories.class, @@ -458,16 +877,104 @@ public final class PacketRegistry { UpdateFieldcraftCategories::deserialize ); register( - 59, "UpdateResourceTypes", UpdateResourceTypes.class, 2, 1677721600, true, UpdateResourceTypes::validateStructure, UpdateResourceTypes::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 59, + "UpdateResourceTypes", + UpdateResourceTypes.class, + 2, + 1677721600, + true, + UpdateResourceTypes::validateStructure, + UpdateResourceTypes::deserialize ); - register(60, "UpdateRecipes", UpdateRecipes.class, 2, 1677721600, true, UpdateRecipes::validateStructure, UpdateRecipes::deserialize); - register(61, "UpdateEnvironments", UpdateEnvironments.class, 7, 1677721600, true, UpdateEnvironments::validateStructure, UpdateEnvironments::deserialize); - register(62, "UpdateAmbienceFX", UpdateAmbienceFX.class, 6, 1677721600, true, UpdateAmbienceFX::validateStructure, UpdateAmbienceFX::deserialize); - register(63, "UpdateFluidFX", UpdateFluidFX.class, 6, 1677721600, true, UpdateFluidFX::validateStructure, UpdateFluidFX::deserialize); - register(64, "UpdateTranslations", UpdateTranslations.class, 2, 1677721600, true, UpdateTranslations::validateStructure, UpdateTranslations::deserialize); - register(65, "UpdateSoundEvents", UpdateSoundEvents.class, 6, 1677721600, true, UpdateSoundEvents::validateStructure, UpdateSoundEvents::deserialize); - register(66, "UpdateInteractions", UpdateInteractions.class, 6, 1677721600, true, UpdateInteractions::validateStructure, UpdateInteractions::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 60, + "UpdateRecipes", + UpdateRecipes.class, + 2, + 1677721600, + true, + UpdateRecipes::validateStructure, + UpdateRecipes::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 61, + "UpdateEnvironments", + UpdateEnvironments.class, + 7, + 1677721600, + true, + UpdateEnvironments::validateStructure, + UpdateEnvironments::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 62, + "UpdateAmbienceFX", + UpdateAmbienceFX.class, + 6, + 1677721600, + true, + UpdateAmbienceFX::validateStructure, + UpdateAmbienceFX::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 63, + "UpdateFluidFX", + UpdateFluidFX.class, + 6, + 1677721600, + true, + UpdateFluidFX::validateStructure, + UpdateFluidFX::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 64, + "UpdateTranslations", + UpdateTranslations.class, + 2, + 1677721600, + true, + UpdateTranslations::validateStructure, + UpdateTranslations::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 65, + "UpdateSoundEvents", + UpdateSoundEvents.class, + 6, + 1677721600, + true, + UpdateSoundEvents::validateStructure, + UpdateSoundEvents::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 66, + "UpdateInteractions", + UpdateInteractions.class, + 6, + 1677721600, + true, + UpdateInteractions::validateStructure, + UpdateInteractions::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 67, "UpdateRootInteractions", UpdateRootInteractions.class, @@ -478,6 +985,8 @@ public final class PacketRegistry { UpdateRootInteractions::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 68, "UpdateUnarmedInteractions", UpdateUnarmedInteractions.class, @@ -488,6 +997,8 @@ public final class PacketRegistry { UpdateUnarmedInteractions::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 69, "TrackOrUpdateObjective", TrackOrUpdateObjective.class, @@ -497,11 +1008,33 @@ public final class PacketRegistry { TrackOrUpdateObjective::validateStructure, TrackOrUpdateObjective::deserialize ); - register(70, "UntrackObjective", UntrackObjective.class, 16, 16, false, UntrackObjective::validateStructure, UntrackObjective::deserialize); register( - 71, "UpdateObjectiveTask", UpdateObjectiveTask.class, 21, 16384035, false, UpdateObjectiveTask::validateStructure, UpdateObjectiveTask::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 70, + "UntrackObjective", + UntrackObjective.class, + 16, + 16, + false, + UntrackObjective::validateStructure, + UntrackObjective::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 71, + "UpdateObjectiveTask", + UpdateObjectiveTask.class, + 21, + 1677721600, + false, + UpdateObjectiveTask::validateStructure, + UpdateObjectiveTask::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 72, "UpdateEntityStatTypes", UpdateEntityStatTypes.class, @@ -512,6 +1045,8 @@ public final class PacketRegistry { UpdateEntityStatTypes::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 73, "UpdateEntityUIComponents", UpdateEntityUIComponents.class, @@ -522,6 +1057,8 @@ public final class PacketRegistry { UpdateEntityUIComponents::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 74, "UpdateHitboxCollisionConfig", UpdateHitboxCollisionConfig.class, @@ -532,6 +1069,8 @@ public final class PacketRegistry { UpdateHitboxCollisionConfig::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 75, "UpdateRepulsionConfig", UpdateRepulsionConfig.class, @@ -541,11 +1080,57 @@ public final class PacketRegistry { UpdateRepulsionConfig::validateStructure, UpdateRepulsionConfig::deserialize ); - register(76, "UpdateViewBobbing", UpdateViewBobbing.class, 2, 1677721600, true, UpdateViewBobbing::validateStructure, UpdateViewBobbing::deserialize); - register(77, "UpdateCameraShake", UpdateCameraShake.class, 2, 1677721600, true, UpdateCameraShake::validateStructure, UpdateCameraShake::deserialize); - register(78, "UpdateBlockGroups", UpdateBlockGroups.class, 2, 1677721600, true, UpdateBlockGroups::validateStructure, UpdateBlockGroups::deserialize); - register(79, "UpdateSoundSets", UpdateSoundSets.class, 6, 1677721600, true, UpdateSoundSets::validateStructure, UpdateSoundSets::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 76, + "UpdateViewBobbing", + UpdateViewBobbing.class, + 2, + 1677721600, + true, + UpdateViewBobbing::validateStructure, + UpdateViewBobbing::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 77, + "UpdateCameraShake", + UpdateCameraShake.class, + 2, + 1677721600, + true, + UpdateCameraShake::validateStructure, + UpdateCameraShake::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 78, + "UpdateBlockGroups", + UpdateBlockGroups.class, + 2, + 1677721600, + true, + UpdateBlockGroups::validateStructure, + UpdateBlockGroups::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 79, + "UpdateSoundSets", + UpdateSoundSets.class, + 6, + 1677721600, + true, + UpdateSoundSets::validateStructure, + UpdateSoundSets::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 80, "UpdateAudioCategories", UpdateAudioCategories.class, @@ -556,9 +1141,20 @@ public final class PacketRegistry { UpdateAudioCategories::deserialize ); register( - 81, "UpdateReverbEffects", UpdateReverbEffects.class, 6, 1677721600, true, UpdateReverbEffects::validateStructure, UpdateReverbEffects::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 81, + "UpdateReverbEffects", + UpdateReverbEffects.class, + 6, + 1677721600, + true, + UpdateReverbEffects::validateStructure, + UpdateReverbEffects::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 82, "UpdateEqualizerEffects", UpdateEqualizerEffects.class, @@ -568,9 +1164,33 @@ public final class PacketRegistry { UpdateEqualizerEffects::validateStructure, UpdateEqualizerEffects::deserialize ); - register(83, "UpdateFluids", UpdateFluids.class, 6, 1677721600, true, UpdateFluids::validateStructure, UpdateFluids::deserialize); - register(84, "UpdateTagPatterns", UpdateTagPatterns.class, 6, 1677721600, true, UpdateTagPatterns::validateStructure, UpdateTagPatterns::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 83, + "UpdateFluids", + UpdateFluids.class, + 6, + 1677721600, + true, + UpdateFluids::validateStructure, + UpdateFluids::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 84, + "UpdateTagPatterns", + UpdateTagPatterns.class, + 6, + 1677721600, + true, + UpdateTagPatterns::validateStructure, + UpdateTagPatterns::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 85, "UpdateProjectileConfigs", UpdateProjectileConfigs.class, @@ -580,10 +1200,45 @@ public final class PacketRegistry { UpdateProjectileConfigs::validateStructure, UpdateProjectileConfigs::deserialize ); - register(100, "SetClientId", SetClientId.class, 4, 4, false, SetClientId::validateStructure, SetClientId::deserialize); - register(101, "SetGameMode", SetGameMode.class, 1, 1, false, SetGameMode::validateStructure, SetGameMode::deserialize); - register(102, "SetMovementStates", SetMovementStates.class, 2, 2, false, SetMovementStates::validateStructure, SetMovementStates::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 100, + "SetClientId", + SetClientId.class, + 4, + 4, + false, + SetClientId::validateStructure, + SetClientId::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 101, + "SetGameMode", + SetGameMode.class, + 1, + 1, + false, + SetGameMode::validateStructure, + SetGameMode::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 102, + "SetMovementStates", + SetMovementStates.class, + 2, + 2, + false, + SetMovementStates::validateStructure, + SetMovementStates::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 103, "SetBlockPlacementOverride", SetBlockPlacementOverride.class, @@ -593,13 +1248,81 @@ public final class PacketRegistry { SetBlockPlacementOverride::validateStructure, SetBlockPlacementOverride::deserialize ); - register(104, "JoinWorld", JoinWorld.class, 18, 18, false, JoinWorld::validateStructure, JoinWorld::deserialize); - register(105, "ClientReady", ClientReady.class, 2, 2, false, ClientReady::validateStructure, ClientReady::deserialize); - register(106, "LoadHotbar", LoadHotbar.class, 1, 1, false, LoadHotbar::validateStructure, LoadHotbar::deserialize); - register(107, "SaveHotbar", SaveHotbar.class, 1, 1, false, SaveHotbar::validateStructure, SaveHotbar::deserialize); - register(108, "ClientMovement", ClientMovement.class, 153, 153, false, ClientMovement::validateStructure, ClientMovement::deserialize); - register(109, "ClientTeleport", ClientTeleport.class, 52, 52, false, ClientTeleport::validateStructure, ClientTeleport::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 104, + "JoinWorld", + JoinWorld.class, + 18, + 18, + false, + JoinWorld::validateStructure, + JoinWorld::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 105, + "ClientReady", + ClientReady.class, + 2, + 2, + false, + ClientReady::validateStructure, + ClientReady::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 106, + "LoadHotbar", + LoadHotbar.class, + 1, + 1, + false, + LoadHotbar::validateStructure, + LoadHotbar::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 107, + "SaveHotbar", + SaveHotbar.class, + 1, + 1, + false, + SaveHotbar::validateStructure, + SaveHotbar::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 108, + "ClientMovement", + ClientMovement.class, + 153, + 153, + false, + ClientMovement::validateStructure, + ClientMovement::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 109, + "ClientTeleport", + ClientTeleport.class, + 52, + 52, + false, + ClientTeleport::validateStructure, + ClientTeleport::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 110, "UpdateMovementSettings", UpdateMovementSettings.class, @@ -609,16 +1332,93 @@ public final class PacketRegistry { UpdateMovementSettings::validateStructure, UpdateMovementSettings::deserialize ); - register(111, "MouseInteraction", MouseInteraction.class, 44, 20480071, false, MouseInteraction::validateStructure, MouseInteraction::deserialize); - register(112, "DamageInfo", DamageInfo.class, 29, 32768048, false, DamageInfo::validateStructure, DamageInfo::deserialize); - register(113, "ReticleEvent", ReticleEvent.class, 4, 4, false, ReticleEvent::validateStructure, ReticleEvent::deserialize); - register(114, "DisplayDebug", DisplayDebug.class, 19, 32768037, false, DisplayDebug::validateStructure, DisplayDebug::deserialize); - register(115, "ClearDebugShapes", ClearDebugShapes.class, 0, 0, false, ClearDebugShapes::validateStructure, ClearDebugShapes::deserialize); register( - 116, "SyncPlayerPreferences", SyncPlayerPreferences.class, 12, 12, false, SyncPlayerPreferences::validateStructure, SyncPlayerPreferences::deserialize + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 111, + "MouseInteraction", + MouseInteraction.class, + 44, + 20480071, + false, + MouseInteraction::validateStructure, + MouseInteraction::deserialize ); - register(117, "ClientPlaceBlock", ClientPlaceBlock.class, 20, 20, false, ClientPlaceBlock::validateStructure, ClientPlaceBlock::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 112, + "DamageInfo", + DamageInfo.class, + 29, + 32768048, + false, + DamageInfo::validateStructure, + DamageInfo::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 113, + "ReticleEvent", + ReticleEvent.class, + 4, + 4, + false, + ReticleEvent::validateStructure, + ReticleEvent::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 114, + "DisplayDebug", + DisplayDebug.class, + 23, + 32768041, + false, + DisplayDebug::validateStructure, + DisplayDebug::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 115, + "ClearDebugShapes", + ClearDebugShapes.class, + 0, + 0, + false, + ClearDebugShapes::validateStructure, + ClearDebugShapes::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 116, + "SyncPlayerPreferences", + SyncPlayerPreferences.class, + 12, + 12, + false, + SyncPlayerPreferences::validateStructure, + SyncPlayerPreferences::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 117, + "ClientPlaceBlock", + ClientPlaceBlock.class, + 20, + 20, + false, + ClientPlaceBlock::validateStructure, + ClientPlaceBlock::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 118, "UpdateMemoriesFeatureStatus", UpdateMemoriesFeatureStatus.class, @@ -628,23 +1428,177 @@ public final class PacketRegistry { UpdateMemoriesFeatureStatus::validateStructure, UpdateMemoriesFeatureStatus::deserialize ); - register(119, "RemoveMapMarker", RemoveMapMarker.class, 1, 16384006, false, RemoveMapMarker::validateStructure, RemoveMapMarker::deserialize); - register(131, "SetChunk", SetChunk.class, 13, 12288040, true, SetChunk::validateStructure, SetChunk::deserialize); - register(132, "SetChunkHeightmap", SetChunkHeightmap.class, 9, 4096014, true, SetChunkHeightmap::validateStructure, SetChunkHeightmap::deserialize); - register(133, "SetChunkTintmap", SetChunkTintmap.class, 9, 4096014, true, SetChunkTintmap::validateStructure, SetChunkTintmap::deserialize); register( - 134, "SetChunkEnvironments", SetChunkEnvironments.class, 9, 4096014, true, SetChunkEnvironments::validateStructure, SetChunkEnvironments::deserialize + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 119, + "RemoveMapMarker", + RemoveMapMarker.class, + 1, + 16384006, + false, + RemoveMapMarker::validateStructure, + RemoveMapMarker::deserialize ); - register(135, "UnloadChunk", UnloadChunk.class, 8, 8, false, UnloadChunk::validateStructure, UnloadChunk::deserialize); - register(136, "SetFluids", SetFluids.class, 13, 4096018, true, SetFluids::validateStructure, SetFluids::deserialize); - register(140, "ServerSetBlock", ServerSetBlock.class, 19, 19, false, ServerSetBlock::validateStructure, ServerSetBlock::deserialize); - register(141, "ServerSetBlocks", ServerSetBlocks.class, 12, 36864017, false, ServerSetBlocks::validateStructure, ServerSetBlocks::deserialize); - register(142, "ServerSetFluid", ServerSetFluid.class, 17, 17, false, ServerSetFluid::validateStructure, ServerSetFluid::deserialize); - register(143, "ServerSetFluids", ServerSetFluids.class, 12, 28672017, false, ServerSetFluids::validateStructure, ServerSetFluids::deserialize); - register(144, "UpdateBlockDamage", UpdateBlockDamage.class, 21, 21, false, UpdateBlockDamage::validateStructure, UpdateBlockDamage::deserialize); - register(145, "UpdateTimeSettings", UpdateTimeSettings.class, 10, 10, false, UpdateTimeSettings::validateStructure, UpdateTimeSettings::deserialize); - register(146, "UpdateTime", UpdateTime.class, 13, 13, false, UpdateTime::validateStructure, UpdateTime::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 131, + "SetChunk", + SetChunk.class, + 13, + 12288040, + true, + SetChunk::validateStructure, + SetChunk::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 132, + "SetChunkHeightmap", + SetChunkHeightmap.class, + 9, + 4096014, + true, + SetChunkHeightmap::validateStructure, + SetChunkHeightmap::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 133, + "SetChunkTintmap", + SetChunkTintmap.class, + 9, + 4096014, + true, + SetChunkTintmap::validateStructure, + SetChunkTintmap::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 134, + "SetChunkEnvironments", + SetChunkEnvironments.class, + 9, + 4096014, + true, + SetChunkEnvironments::validateStructure, + SetChunkEnvironments::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 135, + "UnloadChunk", + UnloadChunk.class, + 8, + 8, + false, + UnloadChunk::validateStructure, + UnloadChunk::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 136, + "SetFluids", + SetFluids.class, + 13, + 4096018, + true, + SetFluids::validateStructure, + SetFluids::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 140, + "ServerSetBlock", + ServerSetBlock.class, + 19, + 19, + false, + ServerSetBlock::validateStructure, + ServerSetBlock::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 141, + "ServerSetBlocks", + ServerSetBlocks.class, + 12, + 36864017, + false, + ServerSetBlocks::validateStructure, + ServerSetBlocks::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 142, + "ServerSetFluid", + ServerSetFluid.class, + 17, + 17, + false, + ServerSetFluid::validateStructure, + ServerSetFluid::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 143, + "ServerSetFluids", + ServerSetFluids.class, + 12, + 28672017, + false, + ServerSetFluids::validateStructure, + ServerSetFluids::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Chunks, + 144, + "UpdateBlockDamage", + UpdateBlockDamage.class, + 21, + 21, + false, + UpdateBlockDamage::validateStructure, + UpdateBlockDamage::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 145, + "UpdateTimeSettings", + UpdateTimeSettings.class, + 10, + 10, + false, + UpdateTimeSettings::validateStructure, + UpdateTimeSettings::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 146, + "UpdateTime", + UpdateTime.class, + 13, + 13, + false, + UpdateTime::validateStructure, + UpdateTime::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 147, "UpdateEditorTimeOverride", UpdateEditorTimeOverride.class, @@ -655,6 +1609,8 @@ public final class PacketRegistry { UpdateEditorTimeOverride::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 148, "ClearEditorTimeOverride", ClearEditorTimeOverride.class, @@ -664,8 +1620,21 @@ public final class PacketRegistry { ClearEditorTimeOverride::validateStructure, ClearEditorTimeOverride::deserialize ); - register(149, "UpdateWeather", UpdateWeather.class, 8, 8, false, UpdateWeather::validateStructure, UpdateWeather::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 149, + "UpdateWeather", + UpdateWeather.class, + 8, + 8, + false, + UpdateWeather::validateStructure, + UpdateWeather::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 150, "UpdateEditorWeatherOverride", UpdateEditorWeatherOverride.class, @@ -676,6 +1645,8 @@ public final class PacketRegistry { UpdateEditorWeatherOverride::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 151, "UpdateEnvironmentMusic", UpdateEnvironmentMusic.class, @@ -686,9 +1657,20 @@ public final class PacketRegistry { UpdateEnvironmentMusic::deserialize ); register( - 152, "SpawnParticleSystem", SpawnParticleSystem.class, 44, 16384049, false, SpawnParticleSystem::validateStructure, SpawnParticleSystem::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 152, + "SpawnParticleSystem", + SpawnParticleSystem.class, + 44, + 16384049, + false, + SpawnParticleSystem::validateStructure, + SpawnParticleSystem::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 153, "SpawnBlockParticleSystem", SpawnBlockParticleSystem.class, @@ -698,24 +1680,165 @@ public final class PacketRegistry { SpawnBlockParticleSystem::validateStructure, SpawnBlockParticleSystem::deserialize ); - register(154, "PlaySoundEvent2D", PlaySoundEvent2D.class, 13, 13, false, PlaySoundEvent2D::validateStructure, PlaySoundEvent2D::deserialize); - register(155, "PlaySoundEvent3D", PlaySoundEvent3D.class, 38, 38, false, PlaySoundEvent3D::validateStructure, PlaySoundEvent3D::deserialize); register( - 156, "PlaySoundEventEntity", PlaySoundEventEntity.class, 16, 16, false, PlaySoundEventEntity::validateStructure, PlaySoundEventEntity::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 154, + "PlaySoundEvent2D", + PlaySoundEvent2D.class, + 13, + 13, + false, + PlaySoundEvent2D::validateStructure, + PlaySoundEvent2D::deserialize ); - register(157, "UpdateSleepState", UpdateSleepState.class, 36, 65536050, false, UpdateSleepState::validateStructure, UpdateSleepState::deserialize); - register(158, "SetPaused", SetPaused.class, 1, 1, false, SetPaused::validateStructure, SetPaused::deserialize); - register(159, "ServerSetPaused", ServerSetPaused.class, 1, 1, false, ServerSetPaused::validateStructure, ServerSetPaused::deserialize); - register(160, "SetEntitySeed", SetEntitySeed.class, 4, 4, false, SetEntitySeed::validateStructure, SetEntitySeed::deserialize); - register(161, "EntityUpdates", EntityUpdates.class, 1, 1677721600, true, EntityUpdates::validateStructure, EntityUpdates::deserialize); - register(162, "PlayAnimation", PlayAnimation.class, 6, 32768024, false, PlayAnimation::validateStructure, PlayAnimation::deserialize); - register(163, "ChangeVelocity", ChangeVelocity.class, 35, 35, false, ChangeVelocity::validateStructure, ChangeVelocity::deserialize); - register(164, "ApplyKnockback", ApplyKnockback.class, 38, 38, false, ApplyKnockback::validateStructure, ApplyKnockback::deserialize); register( - 165, "SpawnModelParticles", SpawnModelParticles.class, 5, 1677721600, false, SpawnModelParticles::validateStructure, SpawnModelParticles::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 155, + "PlaySoundEvent3D", + PlaySoundEvent3D.class, + 38, + 38, + false, + PlaySoundEvent3D::validateStructure, + PlaySoundEvent3D::deserialize ); - register(166, "MountMovement", MountMovement.class, 59, 59, false, MountMovement::validateStructure, MountMovement::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 156, + "PlaySoundEventEntity", + PlaySoundEventEntity.class, + 16, + 16, + false, + PlaySoundEventEntity::validateStructure, + PlaySoundEventEntity::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 157, + "UpdateSleepState", + UpdateSleepState.class, + 36, + 65536050, + false, + UpdateSleepState::validateStructure, + UpdateSleepState::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 158, + "SetPaused", + SetPaused.class, + 1, + 1, + false, + SetPaused::validateStructure, + SetPaused::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 159, + "ServerSetPaused", + ServerSetPaused.class, + 1, + 1, + false, + ServerSetPaused::validateStructure, + ServerSetPaused::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 160, + "SetEntitySeed", + SetEntitySeed.class, + 4, + 4, + false, + SetEntitySeed::validateStructure, + SetEntitySeed::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 161, + "EntityUpdates", + EntityUpdates.class, + 1, + 1677721600, + true, + EntityUpdates::validateStructure, + EntityUpdates::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 162, + "PlayAnimation", + PlayAnimation.class, + 6, + 32768024, + false, + PlayAnimation::validateStructure, + PlayAnimation::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 163, + "ChangeVelocity", + ChangeVelocity.class, + 35, + 35, + false, + ChangeVelocity::validateStructure, + ChangeVelocity::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 164, + "ApplyKnockback", + ApplyKnockback.class, + 38, + 38, + false, + ApplyKnockback::validateStructure, + ApplyKnockback::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 165, + "SpawnModelParticles", + SpawnModelParticles.class, + 5, + 1677721600, + false, + SpawnModelParticles::validateStructure, + SpawnModelParticles::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 166, + "MountMovement", + MountMovement.class, + 59, + 59, + false, + MountMovement::validateStructure, + MountMovement::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 170, "UpdatePlayerInventory", UpdatePlayerInventory.class, @@ -725,9 +1848,33 @@ public final class PacketRegistry { UpdatePlayerInventory::validateStructure, UpdatePlayerInventory::deserialize ); - register(171, "SetCreativeItem", SetCreativeItem.class, 9, 16384019, false, SetCreativeItem::validateStructure, SetCreativeItem::deserialize); - register(172, "DropCreativeItem", DropCreativeItem.class, 0, 16384010, false, DropCreativeItem::validateStructure, DropCreativeItem::deserialize); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 171, + "SetCreativeItem", + SetCreativeItem.class, + 9, + 16384019, + false, + SetCreativeItem::validateStructure, + SetCreativeItem::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 172, + "DropCreativeItem", + DropCreativeItem.class, + 0, + 16384010, + false, + DropCreativeItem::validateStructure, + DropCreativeItem::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 173, "SmartGiveCreativeItem", SmartGiveCreativeItem.class, @@ -737,11 +1884,57 @@ public final class PacketRegistry { SmartGiveCreativeItem::validateStructure, SmartGiveCreativeItem::deserialize ); - register(174, "DropItemStack", DropItemStack.class, 12, 12, false, DropItemStack::validateStructure, DropItemStack::deserialize); - register(175, "MoveItemStack", MoveItemStack.class, 20, 20, false, MoveItemStack::validateStructure, MoveItemStack::deserialize); - register(176, "SmartMoveItemStack", SmartMoveItemStack.class, 13, 13, false, SmartMoveItemStack::validateStructure, SmartMoveItemStack::deserialize); - register(177, "SetActiveSlot", SetActiveSlot.class, 8, 8, false, SetActiveSlot::validateStructure, SetActiveSlot::deserialize); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 174, + "DropItemStack", + DropItemStack.class, + 12, + 12, + false, + DropItemStack::validateStructure, + DropItemStack::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 175, + "MoveItemStack", + MoveItemStack.class, + 20, + 20, + false, + MoveItemStack::validateStructure, + MoveItemStack::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 176, + "SmartMoveItemStack", + SmartMoveItemStack.class, + 13, + 13, + false, + SmartMoveItemStack::validateStructure, + SmartMoveItemStack::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 177, + "SetActiveSlot", + SetActiveSlot.class, + 8, + 8, + false, + SetActiveSlot::validateStructure, + SetActiveSlot::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 178, "SwitchHotbarBlockSet", SwitchHotbarBlockSet.class, @@ -751,25 +1944,225 @@ public final class PacketRegistry { SwitchHotbarBlockSet::validateStructure, SwitchHotbarBlockSet::deserialize ); - register(179, "InventoryAction", InventoryAction.class, 6, 6, false, InventoryAction::validateStructure, InventoryAction::deserialize); - register(200, "OpenWindow", OpenWindow.class, 6, 1677721600, true, OpenWindow::validateStructure, OpenWindow::deserialize); - register(201, "UpdateWindow", UpdateWindow.class, 5, 1677721600, true, UpdateWindow::validateStructure, UpdateWindow::deserialize); - register(202, "CloseWindow", CloseWindow.class, 4, 4, false, CloseWindow::validateStructure, CloseWindow::deserialize); - register(203, "SendWindowAction", SendWindowAction.class, 4, 32768027, false, SendWindowAction::validateStructure, SendWindowAction::deserialize); - register(204, "ClientOpenWindow", ClientOpenWindow.class, 1, 1, false, ClientOpenWindow::validateStructure, ClientOpenWindow::deserialize); - register(210, "ServerMessage", ServerMessage.class, 2, 1677721600, false, ServerMessage::validateStructure, ServerMessage::deserialize); - register(211, "ChatMessage", ChatMessage.class, 1, 16384006, false, ChatMessage::validateStructure, ChatMessage::deserialize); - register(212, "Notification", Notification.class, 2, 1677721600, false, Notification::validateStructure, Notification::deserialize); - register(213, "KillFeedMessage", KillFeedMessage.class, 1, 1677721600, false, KillFeedMessage::validateStructure, KillFeedMessage::deserialize); - register(214, "ShowEventTitle", ShowEventTitle.class, 14, 1677721600, false, ShowEventTitle::validateStructure, ShowEventTitle::deserialize); - register(215, "HideEventTitle", HideEventTitle.class, 4, 4, false, HideEventTitle::validateStructure, HideEventTitle::deserialize); - register(216, "SetPage", SetPage.class, 2, 2, false, SetPage::validateStructure, SetPage::deserialize); - register(217, "CustomHud", CustomHud.class, 2, 1677721600, true, CustomHud::validateStructure, CustomHud::deserialize); - register(218, "CustomPage", CustomPage.class, 4, 1677721600, true, CustomPage::validateStructure, CustomPage::deserialize); - register(219, "CustomPageEvent", CustomPageEvent.class, 2, 16384007, false, CustomPageEvent::validateStructure, CustomPageEvent::deserialize); - register(222, "EditorBlocksChange", EditorBlocksChange.class, 30, 139264048, true, EditorBlocksChange::validateStructure, EditorBlocksChange::deserialize); - register(223, "ServerInfo", ServerInfo.class, 5, 32768023, false, ServerInfo::validateStructure, ServerInfo::deserialize); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 179, + "InventoryAction", + InventoryAction.class, + 6, + 6, + false, + InventoryAction::validateStructure, + InventoryAction::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 200, + "OpenWindow", + OpenWindow.class, + 6, + 1677721600, + true, + OpenWindow::validateStructure, + OpenWindow::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 201, + "UpdateWindow", + UpdateWindow.class, + 5, + 1677721600, + true, + UpdateWindow::validateStructure, + UpdateWindow::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 202, + "CloseWindow", + CloseWindow.class, + 4, + 4, + false, + CloseWindow::validateStructure, + CloseWindow::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 203, + "SendWindowAction", + SendWindowAction.class, + 4, + 32768027, + false, + SendWindowAction::validateStructure, + SendWindowAction::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 204, + "ClientOpenWindow", + ClientOpenWindow.class, + 1, + 1, + false, + ClientOpenWindow::validateStructure, + ClientOpenWindow::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 210, + "ServerMessage", + ServerMessage.class, + 2, + 1677721600, + false, + ServerMessage::validateStructure, + ServerMessage::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 211, + "ChatMessage", + ChatMessage.class, + 1, + 16384006, + false, + ChatMessage::validateStructure, + ChatMessage::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 212, + "Notification", + Notification.class, + 2, + 1677721600, + false, + Notification::validateStructure, + Notification::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 213, + "KillFeedMessage", + KillFeedMessage.class, + 1, + 1677721600, + false, + KillFeedMessage::validateStructure, + KillFeedMessage::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 214, + "ShowEventTitle", + ShowEventTitle.class, + 14, + 1677721600, + false, + ShowEventTitle::validateStructure, + ShowEventTitle::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 215, + "HideEventTitle", + HideEventTitle.class, + 4, + 4, + false, + HideEventTitle::validateStructure, + HideEventTitle::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 216, + "SetPage", + SetPage.class, + 2, + 2, + false, + SetPage::validateStructure, + SetPage::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 217, + "CustomHud", + CustomHud.class, + 2, + 1677721600, + true, + CustomHud::validateStructure, + CustomHud::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 218, + "CustomPage", + CustomPage.class, + 4, + 1677721600, + true, + CustomPage::validateStructure, + CustomPage::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 219, + "CustomPageEvent", + CustomPageEvent.class, + 2, + 16384007, + false, + CustomPageEvent::validateStructure, + CustomPageEvent::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 222, + "EditorBlocksChange", + EditorBlocksChange.class, + 30, + 139264048, + true, + EditorBlocksChange::validateStructure, + EditorBlocksChange::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 223, + "ServerInfo", + ServerInfo.class, + 5, + 32768023, + false, + ServerInfo::validateStructure, + ServerInfo::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 224, "AddToServerPlayerList", AddToServerPlayerList.class, @@ -780,6 +2173,8 @@ public final class PacketRegistry { AddToServerPlayerList::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 225, "RemoveFromServerPlayerList", RemoveFromServerPlayerList.class, @@ -790,6 +2185,8 @@ public final class PacketRegistry { RemoveFromServerPlayerList::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 226, "UpdateServerPlayerList", UpdateServerPlayerList.class, @@ -800,6 +2197,8 @@ public final class PacketRegistry { UpdateServerPlayerList::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 227, "UpdateServerPlayerListPing", UpdateServerPlayerListPing.class, @@ -810,10 +2209,32 @@ public final class PacketRegistry { UpdateServerPlayerListPing::deserialize ); register( - 228, "UpdateKnownRecipes", UpdateKnownRecipes.class, 1, 1677721600, false, UpdateKnownRecipes::validateStructure, UpdateKnownRecipes::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 228, + "UpdateKnownRecipes", + UpdateKnownRecipes.class, + 1, + 1677721600, + false, + UpdateKnownRecipes::validateStructure, + UpdateKnownRecipes::deserialize ); - register(229, "UpdatePortal", UpdatePortal.class, 6, 16384020, false, UpdatePortal::validateStructure, UpdatePortal::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 229, + "UpdatePortal", + UpdatePortal.class, + 6, + 16384020, + false, + UpdatePortal::validateStructure, + UpdatePortal::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 230, "UpdateVisibleHudComponents", UpdateVisibleHudComponents.class, @@ -824,6 +2245,8 @@ public final class PacketRegistry { UpdateVisibleHudComponents::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 231, "ResetUserInterfaceState", ResetUserInterfaceState.class, @@ -833,27 +2256,105 @@ public final class PacketRegistry { ResetUserInterfaceState::validateStructure, ResetUserInterfaceState::deserialize ); - register(232, "UpdateLanguage", UpdateLanguage.class, 1, 16384006, false, UpdateLanguage::validateStructure, UpdateLanguage::deserialize); - register(233, "WorldSavingStatus", WorldSavingStatus.class, 1, 1, false, WorldSavingStatus::validateStructure, WorldSavingStatus::deserialize); register( - 234, "OpenChatWithCommand", OpenChatWithCommand.class, 1, 16384006, false, OpenChatWithCommand::validateStructure, OpenChatWithCommand::deserialize + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 232, + "UpdateLanguage", + UpdateLanguage.class, + 1, + 16384006, + false, + UpdateLanguage::validateStructure, + UpdateLanguage::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 233, + "WorldSavingStatus", + WorldSavingStatus.class, + 1, + 1, + false, + WorldSavingStatus::validateStructure, + WorldSavingStatus::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 234, + "OpenChatWithCommand", + OpenChatWithCommand.class, + 1, + 16384006, + false, + OpenChatWithCommand::validateStructure, + OpenChatWithCommand::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 235, + "UpdateAnchorUI", + UpdateAnchorUI.class, + 2, + 1677721600, + true, + UpdateAnchorUI::validateStructure, + UpdateAnchorUI::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 240, "UpdateWorldMapSettings", UpdateWorldMapSettings.class, - 16, + 20, 1677721600, false, UpdateWorldMapSettings::validateStructure, UpdateWorldMapSettings::deserialize ); - register(241, "UpdateWorldMap", UpdateWorldMap.class, 1, 1677721600, true, UpdateWorldMap::validateStructure, UpdateWorldMap::deserialize); - register(242, "ClearWorldMap", ClearWorldMap.class, 0, 0, false, ClearWorldMap::validateStructure, ClearWorldMap::deserialize); register( - 243, "UpdateWorldMapVisible", UpdateWorldMapVisible.class, 1, 1, false, UpdateWorldMapVisible::validateStructure, UpdateWorldMapVisible::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.WorldMap, + 241, + "UpdateWorldMap", + UpdateWorldMap.class, + 1, + 1677721600, + true, + UpdateWorldMap::validateStructure, + UpdateWorldMap::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.WorldMap, + 242, + "ClearWorldMap", + ClearWorldMap.class, + 0, + 0, + false, + ClearWorldMap::validateStructure, + ClearWorldMap::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 243, + "UpdateWorldMapVisible", + UpdateWorldMapVisible.class, + 1, + 1, + false, + UpdateWorldMapVisible::validateStructure, + UpdateWorldMapVisible::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 244, "TeleportToWorldMapMarker", TeleportToWorldMapMarker.class, @@ -864,6 +2365,8 @@ public final class PacketRegistry { TeleportToWorldMapMarker::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 245, "TeleportToWorldMapPosition", TeleportToWorldMapPosition.class, @@ -873,12 +2376,57 @@ public final class PacketRegistry { TeleportToWorldMapPosition::validateStructure, TeleportToWorldMapPosition::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 + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 246, + "CreateUserMarker", + CreateUserMarker.class, + 13, + 32768031, + false, + CreateUserMarker::validateStructure, + CreateUserMarker::deserialize ); - register(252, "SetServerAccess", SetServerAccess.class, 2, 16384007, false, SetServerAccess::validateStructure, SetServerAccess::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 250, + "RequestServerAccess", + RequestServerAccess.class, + 3, + 3, + false, + RequestServerAccess::validateStructure, + RequestServerAccess::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 251, + "UpdateServerAccess", + UpdateServerAccess.class, + 2, + 1677721600, + false, + UpdateServerAccess::validateStructure, + UpdateServerAccess::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 252, + "SetServerAccess", + SetServerAccess.class, + 2, + 16384007, + false, + SetServerAccess::validateStructure, + SetServerAccess::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 260, "RequestMachinimaActorModel", RequestMachinimaActorModel.class, @@ -889,6 +2437,8 @@ public final class PacketRegistry { RequestMachinimaActorModel::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 261, "SetMachinimaActorModel", SetMachinimaActorModel.class, @@ -899,13 +2449,68 @@ public final class PacketRegistry { SetMachinimaActorModel::deserialize ); register( - 262, "UpdateMachinimaScene", UpdateMachinimaScene.class, 6, 36864033, true, UpdateMachinimaScene::validateStructure, UpdateMachinimaScene::deserialize + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 262, + "UpdateMachinimaScene", + UpdateMachinimaScene.class, + 6, + 36864033, + true, + UpdateMachinimaScene::validateStructure, + UpdateMachinimaScene::deserialize ); - register(280, "SetServerCamera", SetServerCamera.class, 157, 157, false, SetServerCamera::validateStructure, SetServerCamera::deserialize); - register(281, "CameraShakeEffect", CameraShakeEffect.class, 9, 9, false, CameraShakeEffect::validateStructure, CameraShakeEffect::deserialize); - register(282, "RequestFlyCameraMode", RequestFlyCameraMode.class, 1, 1, false, RequestFlyCameraMode::validateStructure, RequestFlyCameraMode::deserialize); - register(283, "SetFlyCameraMode", SetFlyCameraMode.class, 1, 1, false, SetFlyCameraMode::validateStructure, SetFlyCameraMode::deserialize); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 280, + "SetServerCamera", + SetServerCamera.class, + 157, + 157, + false, + SetServerCamera::validateStructure, + SetServerCamera::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 281, + "CameraShakeEffect", + CameraShakeEffect.class, + 9, + 9, + false, + CameraShakeEffect::validateStructure, + CameraShakeEffect::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 282, + "RequestFlyCameraMode", + RequestFlyCameraMode.class, + 1, + 1, + false, + RequestFlyCameraMode::validateStructure, + RequestFlyCameraMode::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 283, + "SetFlyCameraMode", + SetFlyCameraMode.class, + 1, + 1, + false, + SetFlyCameraMode::validateStructure, + SetFlyCameraMode::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, 290, "SyncInteractionChains", SyncInteractionChains.class, @@ -916,6 +2521,8 @@ public final class PacketRegistry { SyncInteractionChains::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 291, "CancelInteractionChain", CancelInteractionChain.class, @@ -925,15 +2532,81 @@ public final class PacketRegistry { CancelInteractionChain::validateStructure, CancelInteractionChain::deserialize ); - register(292, "PlayInteractionFor", PlayInteractionFor.class, 19, 16385065, false, PlayInteractionFor::validateStructure, PlayInteractionFor::deserialize); - register(293, "MountNPC", MountNPC.class, 16, 16, false, MountNPC::validateStructure, MountNPC::deserialize); - register(294, "DismountNPC", DismountNPC.class, 0, 0, false, DismountNPC::validateStructure, DismountNPC::deserialize); - register(300, "FailureReply", FailureReply.class, 5, 1677721600, false, FailureReply::validateStructure, FailureReply::deserialize); - register(301, "SuccessReply", SuccessReply.class, 5, 1677721600, false, SuccessReply::validateStructure, SuccessReply::deserialize); register( - 302, "AssetEditorInitialize", AssetEditorInitialize.class, 0, 0, false, AssetEditorInitialize::validateStructure, AssetEditorInitialize::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 292, + "PlayInteractionFor", + PlayInteractionFor.class, + 19, + 16385065, + false, + PlayInteractionFor::validateStructure, + PlayInteractionFor::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 293, + "MountNPC", + MountNPC.class, + 16, + 16, + false, + MountNPC::validateStructure, + MountNPC::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 294, + "DismountNPC", + DismountNPC.class, + 0, + 0, + false, + DismountNPC::validateStructure, + DismountNPC::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 300, + "FailureReply", + FailureReply.class, + 5, + 1677721600, + false, + FailureReply::validateStructure, + FailureReply::deserialize + ); + register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, + 301, + "SuccessReply", + SuccessReply.class, + 5, + 1677721600, + false, + SuccessReply::validateStructure, + SuccessReply::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 302, + "AssetEditorInitialize", + AssetEditorInitialize.class, + 0, + 0, + false, + AssetEditorInitialize::validateStructure, + AssetEditorInitialize::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 303, "AssetEditorAuthorization", AssetEditorAuthorization.class, @@ -944,6 +2617,8 @@ public final class PacketRegistry { AssetEditorAuthorization::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 304, "AssetEditorCapabilities", AssetEditorCapabilities.class, @@ -954,6 +2629,8 @@ public final class PacketRegistry { AssetEditorCapabilities::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 305, "AssetEditorSetupSchemas", AssetEditorSetupSchemas.class, @@ -964,6 +2641,8 @@ public final class PacketRegistry { AssetEditorSetupSchemas::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 306, "AssetEditorSetupAssetTypes", AssetEditorSetupAssetTypes.class, @@ -974,6 +2653,8 @@ public final class PacketRegistry { AssetEditorSetupAssetTypes::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 307, "AssetEditorCreateDirectory", AssetEditorCreateDirectory.class, @@ -984,6 +2665,8 @@ public final class PacketRegistry { AssetEditorCreateDirectory::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 308, "AssetEditorDeleteDirectory", AssetEditorDeleteDirectory.class, @@ -994,6 +2677,8 @@ public final class PacketRegistry { AssetEditorDeleteDirectory::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 309, "AssetEditorRenameDirectory", AssetEditorRenameDirectory.class, @@ -1004,6 +2689,8 @@ public final class PacketRegistry { AssetEditorRenameDirectory::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 310, "AssetEditorFetchAsset", AssetEditorFetchAsset.class, @@ -1014,6 +2701,8 @@ public final class PacketRegistry { AssetEditorFetchAsset::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 311, "AssetEditorFetchJsonAssetWithParents", AssetEditorFetchJsonAssetWithParents.class, @@ -1024,6 +2713,8 @@ public final class PacketRegistry { AssetEditorFetchJsonAssetWithParents::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 312, "AssetEditorFetchAssetReply", AssetEditorFetchAssetReply.class, @@ -1034,6 +2725,8 @@ public final class PacketRegistry { AssetEditorFetchAssetReply::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 313, "AssetEditorFetchJsonAssetWithParentsReply", AssetEditorFetchJsonAssetWithParentsReply.class, @@ -1044,6 +2737,8 @@ public final class PacketRegistry { AssetEditorFetchJsonAssetWithParentsReply::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 314, "AssetEditorAssetPackSetup", AssetEditorAssetPackSetup.class, @@ -1054,6 +2749,8 @@ public final class PacketRegistry { AssetEditorAssetPackSetup::deserialize ); register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, 315, "AssetEditorUpdateAssetPack", AssetEditorUpdateAssetPack.class, @@ -1064,6 +2761,8 @@ public final class PacketRegistry { AssetEditorUpdateAssetPack::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 316, "AssetEditorCreateAssetPack", AssetEditorCreateAssetPack.class, @@ -1074,6 +2773,8 @@ public final class PacketRegistry { AssetEditorCreateAssetPack::deserialize ); register( + PacketRegistry.PacketDirection.Both, + NetworkChannel.Default, 317, "AssetEditorDeleteAssetPack", AssetEditorDeleteAssetPack.class, @@ -1084,16 +2785,8 @@ public final class PacketRegistry { AssetEditorDeleteAssetPack::deserialize ); register( - 318, - "AssetEditorEnableAssetPack", - AssetEditorEnableAssetPack.class, - 2, - 16384007, - false, - AssetEditorEnableAssetPack::validateStructure, - AssetEditorEnableAssetPack::deserialize - ); - register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 319, "AssetEditorAssetListSetup", AssetEditorAssetListSetup.class, @@ -1104,6 +2797,8 @@ public final class PacketRegistry { AssetEditorAssetListSetup::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 320, "AssetEditorAssetListUpdate", AssetEditorAssetListUpdate.class, @@ -1114,6 +2809,8 @@ public final class PacketRegistry { AssetEditorAssetListUpdate::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 321, "AssetEditorRequestChildrenList", AssetEditorRequestChildrenList.class, @@ -1124,6 +2821,8 @@ public final class PacketRegistry { AssetEditorRequestChildrenList::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 322, "AssetEditorRequestChildrenListReply", AssetEditorRequestChildrenListReply.class, @@ -1134,6 +2833,8 @@ public final class PacketRegistry { AssetEditorRequestChildrenListReply::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 323, "AssetEditorUpdateJsonAsset", AssetEditorUpdateJsonAsset.class, @@ -1144,6 +2845,8 @@ public final class PacketRegistry { AssetEditorUpdateJsonAsset::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 324, "AssetEditorUpdateAsset", AssetEditorUpdateAsset.class, @@ -1154,6 +2857,8 @@ public final class PacketRegistry { AssetEditorUpdateAsset::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 325, "AssetEditorJsonAssetUpdated", AssetEditorJsonAssetUpdated.class, @@ -1164,6 +2869,8 @@ public final class PacketRegistry { AssetEditorJsonAssetUpdated::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 326, "AssetEditorAssetUpdated", AssetEditorAssetUpdated.class, @@ -1174,6 +2881,8 @@ public final class PacketRegistry { AssetEditorAssetUpdated::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 327, "AssetEditorCreateAsset", AssetEditorCreateAsset.class, @@ -1184,6 +2893,8 @@ public final class PacketRegistry { AssetEditorCreateAsset::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 328, "AssetEditorRenameAsset", AssetEditorRenameAsset.class, @@ -1194,6 +2905,8 @@ public final class PacketRegistry { AssetEditorRenameAsset::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 329, "AssetEditorDeleteAsset", AssetEditorDeleteAsset.class, @@ -1204,6 +2917,8 @@ public final class PacketRegistry { AssetEditorDeleteAsset::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 330, "AssetEditorDiscardChanges", AssetEditorDiscardChanges.class, @@ -1214,6 +2929,8 @@ public final class PacketRegistry { AssetEditorDiscardChanges::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 331, "AssetEditorFetchAutoCompleteData", AssetEditorFetchAutoCompleteData.class, @@ -1224,6 +2941,8 @@ public final class PacketRegistry { AssetEditorFetchAutoCompleteData::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 332, "AssetEditorFetchAutoCompleteDataReply", AssetEditorFetchAutoCompleteDataReply.class, @@ -1234,6 +2953,8 @@ public final class PacketRegistry { AssetEditorFetchAutoCompleteDataReply::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 333, "AssetEditorRequestDataset", AssetEditorRequestDataset.class, @@ -1244,6 +2965,8 @@ public final class PacketRegistry { AssetEditorRequestDataset::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 334, "AssetEditorRequestDatasetReply", AssetEditorRequestDatasetReply.class, @@ -1254,6 +2977,8 @@ public final class PacketRegistry { AssetEditorRequestDatasetReply::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 335, "AssetEditorActivateButton", AssetEditorActivateButton.class, @@ -1264,6 +2989,8 @@ public final class PacketRegistry { AssetEditorActivateButton::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 336, "AssetEditorSelectAsset", AssetEditorSelectAsset.class, @@ -1274,6 +3001,8 @@ public final class PacketRegistry { AssetEditorSelectAsset::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 337, "AssetEditorPopupNotification", AssetEditorPopupNotification.class, @@ -1284,6 +3013,8 @@ public final class PacketRegistry { AssetEditorPopupNotification::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 338, "AssetEditorFetchLastModifiedAssets", AssetEditorFetchLastModifiedAssets.class, @@ -1294,6 +3025,8 @@ public final class PacketRegistry { AssetEditorFetchLastModifiedAssets::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 339, "AssetEditorLastModifiedAssets", AssetEditorLastModifiedAssets.class, @@ -1304,6 +3037,8 @@ public final class PacketRegistry { AssetEditorLastModifiedAssets::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 340, "AssetEditorModifiedAssetsCount", AssetEditorModifiedAssetsCount.class, @@ -1314,6 +3049,8 @@ public final class PacketRegistry { AssetEditorModifiedAssetsCount::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 341, "AssetEditorSubscribeModifiedAssetsChanges", AssetEditorSubscribeModifiedAssetsChanges.class, @@ -1324,6 +3061,8 @@ public final class PacketRegistry { AssetEditorSubscribeModifiedAssetsChanges::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 342, "AssetEditorExportAssets", AssetEditorExportAssets.class, @@ -1334,6 +3073,8 @@ public final class PacketRegistry { AssetEditorExportAssets::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 343, "AssetEditorExportAssetInitialize", AssetEditorExportAssetInitialize.class, @@ -1344,6 +3085,8 @@ public final class PacketRegistry { AssetEditorExportAssetInitialize::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 344, "AssetEditorExportAssetPart", AssetEditorExportAssetPart.class, @@ -1354,6 +3097,8 @@ public final class PacketRegistry { AssetEditorExportAssetPart::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 345, "AssetEditorExportAssetFinalize", AssetEditorExportAssetFinalize.class, @@ -1364,6 +3109,8 @@ public final class PacketRegistry { AssetEditorExportAssetFinalize::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 346, "AssetEditorExportDeleteAssets", AssetEditorExportDeleteAssets.class, @@ -1374,6 +3121,8 @@ public final class PacketRegistry { AssetEditorExportDeleteAssets::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 347, "AssetEditorExportComplete", AssetEditorExportComplete.class, @@ -1384,16 +3133,8 @@ public final class PacketRegistry { AssetEditorExportComplete::deserialize ); register( - 348, - "AssetEditorRebuildCaches", - AssetEditorRebuildCaches.class, - 5, - 5, - false, - AssetEditorRebuildCaches::validateStructure, - AssetEditorRebuildCaches::deserialize - ); - register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 349, "AssetEditorUndoChanges", AssetEditorUndoChanges.class, @@ -1404,6 +3145,8 @@ public final class PacketRegistry { AssetEditorUndoChanges::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 350, "AssetEditorRedoChanges", AssetEditorRedoChanges.class, @@ -1414,6 +3157,8 @@ public final class PacketRegistry { AssetEditorRedoChanges::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 351, "AssetEditorUndoRedoReply", AssetEditorUndoRedoReply.class, @@ -1424,6 +3169,8 @@ public final class PacketRegistry { AssetEditorUndoRedoReply::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 352, "AssetEditorSetGameTime", AssetEditorSetGameTime.class, @@ -1434,6 +3181,8 @@ public final class PacketRegistry { AssetEditorSetGameTime::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 353, "AssetEditorUpdateSecondsPerGameDay", AssetEditorUpdateSecondsPerGameDay.class, @@ -1444,6 +3193,8 @@ public final class PacketRegistry { AssetEditorUpdateSecondsPerGameDay::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 354, "AssetEditorUpdateWeatherPreviewLock", AssetEditorUpdateWeatherPreviewLock.class, @@ -1454,6 +3205,8 @@ public final class PacketRegistry { AssetEditorUpdateWeatherPreviewLock::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 355, "AssetEditorUpdateModelPreview", AssetEditorUpdateModelPreview.class, @@ -1463,11 +3216,33 @@ public final class PacketRegistry { AssetEditorUpdateModelPreview::validateStructure, AssetEditorUpdateModelPreview::deserialize ); - register(360, "UpdateSunSettings", UpdateSunSettings.class, 8, 8, false, UpdateSunSettings::validateStructure, UpdateSunSettings::deserialize); register( - 361, "UpdatePostFxSettings", UpdatePostFxSettings.class, 20, 20, false, UpdatePostFxSettings::validateStructure, UpdatePostFxSettings::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 360, + "UpdateSunSettings", + UpdateSunSettings.class, + 8, + 8, + false, + UpdateSunSettings::validateStructure, + UpdateSunSettings::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 361, + "UpdatePostFxSettings", + UpdatePostFxSettings.class, + 20, + 20, + false, + UpdatePostFxSettings::validateStructure, + UpdatePostFxSettings::deserialize + ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 400, "BuilderToolArgUpdate", BuilderToolArgUpdate.class, @@ -1478,6 +3253,8 @@ public final class PacketRegistry { BuilderToolArgUpdate::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 401, "BuilderToolEntityAction", BuilderToolEntityAction.class, @@ -1488,6 +3265,8 @@ public final class PacketRegistry { BuilderToolEntityAction::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 402, "BuilderToolSetEntityTransform", BuilderToolSetEntityTransform.class, @@ -1498,6 +3277,8 @@ public final class PacketRegistry { BuilderToolSetEntityTransform::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 403, "BuilderToolExtrudeAction", BuilderToolExtrudeAction.class, @@ -1508,19 +3289,32 @@ public final class PacketRegistry { BuilderToolExtrudeAction::deserialize ); register( - 404, "BuilderToolStackArea", BuilderToolStackArea.class, 41, 41, false, BuilderToolStackArea::validateStructure, BuilderToolStackArea::deserialize + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 404, + "BuilderToolStackArea", + BuilderToolStackArea.class, + 41, + 41, + false, + BuilderToolStackArea::validateStructure, + BuilderToolStackArea::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 405, "BuilderToolSelectionTransform", BuilderToolSelectionTransform.class, - 52, - 16384057, + 80, + 80, false, BuilderToolSelectionTransform::validateStructure, BuilderToolSelectionTransform::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 406, "BuilderToolRotateClipboard", BuilderToolRotateClipboard.class, @@ -1531,6 +3325,8 @@ public final class PacketRegistry { BuilderToolRotateClipboard::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 407, "BuilderToolPasteClipboard", BuilderToolPasteClipboard.class, @@ -1541,6 +3337,8 @@ public final class PacketRegistry { BuilderToolPasteClipboard::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 408, "BuilderToolSetTransformationModeState", BuilderToolSetTransformationModeState.class, @@ -1551,6 +3349,8 @@ public final class PacketRegistry { BuilderToolSetTransformationModeState::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 409, "BuilderToolSelectionUpdate", BuilderToolSelectionUpdate.class, @@ -1561,6 +3361,8 @@ public final class PacketRegistry { BuilderToolSelectionUpdate::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 410, "BuilderToolSelectionToolAskForClipboard", BuilderToolSelectionToolAskForClipboard.class, @@ -1571,6 +3373,8 @@ public final class PacketRegistry { BuilderToolSelectionToolAskForClipboard::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 411, "BuilderToolSelectionToolReplyWithClipboard", BuilderToolSelectionToolReplyWithClipboard.class, @@ -1581,6 +3385,8 @@ public final class PacketRegistry { BuilderToolSelectionToolReplyWithClipboard::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 412, "BuilderToolGeneralAction", BuilderToolGeneralAction.class, @@ -1591,6 +3397,8 @@ public final class PacketRegistry { BuilderToolGeneralAction::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 413, "BuilderToolOnUseInteraction", BuilderToolOnUseInteraction.class, @@ -1601,12 +3409,32 @@ public final class PacketRegistry { BuilderToolOnUseInteraction::deserialize ); register( - 414, "BuilderToolLineAction", BuilderToolLineAction.class, 24, 24, false, BuilderToolLineAction::validateStructure, BuilderToolLineAction::deserialize + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 414, + "BuilderToolLineAction", + BuilderToolLineAction.class, + 24, + 24, + false, + BuilderToolLineAction::validateStructure, + BuilderToolLineAction::deserialize ); register( - 415, "BuilderToolShowAnchor", BuilderToolShowAnchor.class, 12, 12, false, BuilderToolShowAnchor::validateStructure, BuilderToolShowAnchor::deserialize + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, + 415, + "BuilderToolShowAnchor", + BuilderToolShowAnchor.class, + 12, + 12, + false, + BuilderToolShowAnchor::validateStructure, + BuilderToolShowAnchor::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 416, "BuilderToolHideAnchors", BuilderToolHideAnchors.class, @@ -1616,8 +3444,21 @@ public final class PacketRegistry { BuilderToolHideAnchors::validateStructure, BuilderToolHideAnchors::deserialize ); - register(417, "PrefabUnselectPrefab", PrefabUnselectPrefab.class, 0, 0, false, PrefabUnselectPrefab::validateStructure, PrefabUnselectPrefab::deserialize); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 417, + "PrefabUnselectPrefab", + PrefabUnselectPrefab.class, + 0, + 0, + false, + PrefabUnselectPrefab::validateStructure, + PrefabUnselectPrefab::deserialize + ); + register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 418, "BuilderToolsSetSoundSet", BuilderToolsSetSoundSet.class, @@ -1628,6 +3469,8 @@ public final class PacketRegistry { BuilderToolsSetSoundSet::deserialize ); register( + PacketRegistry.PacketDirection.ToClient, + NetworkChannel.Default, 419, "BuilderToolLaserPointer", BuilderToolLaserPointer.class, @@ -1638,6 +3481,8 @@ public final class PacketRegistry { BuilderToolLaserPointer::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 420, "BuilderToolSetEntityScale", BuilderToolSetEntityScale.class, @@ -1648,6 +3493,8 @@ public final class PacketRegistry { BuilderToolSetEntityScale::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 421, "BuilderToolSetEntityPickupEnabled", BuilderToolSetEntityPickupEnabled.class, @@ -1658,6 +3505,8 @@ public final class PacketRegistry { BuilderToolSetEntityPickupEnabled::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 422, "BuilderToolSetEntityLight", BuilderToolSetEntityLight.class, @@ -1668,6 +3517,8 @@ public final class PacketRegistry { BuilderToolSetEntityLight::deserialize ); register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, 423, "BuilderToolSetNPCDebug", BuilderToolSetNPCDebug.class, @@ -1677,11 +3528,30 @@ public final class PacketRegistry { BuilderToolSetNPCDebug::validateStructure, BuilderToolSetNPCDebug::deserialize ); + register( + PacketRegistry.PacketDirection.ToServer, + NetworkChannel.Default, + 425, + "BuilderToolSetEntityCollision", + BuilderToolSetEntityCollision.class, + 5, + 16384010, + false, + BuilderToolSetEntityCollision::validateStructure, + BuilderToolSetEntityCollision::deserialize + ); + } + + public static enum PacketDirection { + ToServer, + ToClient, + Both; } public record PacketInfo( int id, @Nonnull String name, + @Nonnull NetworkChannel channel, @Nonnull Class type, int fixedBlockSize, int maxSize, diff --git a/src/com/hypixel/hytale/protocol/PickupLocation.java b/src/com/hypixel/hytale/protocol/PickupLocation.java index 14a5f75e..f78b70a8 100644 --- a/src/com/hypixel/hytale/protocol/PickupLocation.java +++ b/src/com/hypixel/hytale/protocol/PickupLocation.java @@ -4,7 +4,8 @@ import com.hypixel.hytale.protocol.io.ProtocolException; public enum PickupLocation { Hotbar(0), - Storage(1); + Storage(1), + Backpack(2); public static final PickupLocation[] VALUES = values(); private final int value; diff --git a/src/com/hypixel/hytale/protocol/PlayerSkinUpdate.java b/src/com/hypixel/hytale/protocol/PlayerSkinUpdate.java new file mode 100644 index 00000000..ff5d9183 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/PlayerSkinUpdate.java @@ -0,0 +1,116 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class PlayerSkinUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 1; + public static final int FIXED_BLOCK_SIZE = 1; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 1; + public static final int MAX_SIZE = 327680184; + @Nullable + public PlayerSkin skin; + + public PlayerSkinUpdate() { + } + + public PlayerSkinUpdate(@Nullable PlayerSkin skin) { + this.skin = skin; + } + + public PlayerSkinUpdate(@Nonnull PlayerSkinUpdate other) { + this.skin = other.skin; + } + + @Nonnull + public static PlayerSkinUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + PlayerSkinUpdate obj = new PlayerSkinUpdate(); + byte nullBits = buf.getByte(offset); + int pos = offset + 1; + if ((nullBits & 1) != 0) { + obj.skin = PlayerSkin.deserialize(buf, pos); + pos += PlayerSkin.computeBytesConsumed(buf, pos); + } + + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + byte nullBits = buf.getByte(offset); + int pos = offset + 1; + if ((nullBits & 1) != 0) { + pos += PlayerSkin.computeBytesConsumed(buf, pos); + } + + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + byte nullBits = 0; + if (this.skin != null) { + nullBits = (byte)(nullBits | 1); + } + + buf.writeByte(nullBits); + if (this.skin != null) { + this.skin.serialize(buf); + } + + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + int size = 1; + if (this.skin != null) { + size += this.skin.computeSize(); + } + + return size; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 1) { + return ValidationResult.error("Buffer too small: expected at least 1 bytes"); + } else { + byte nullBits = buffer.getByte(offset); + int pos = offset + 1; + if ((nullBits & 1) != 0) { + ValidationResult skinResult = PlayerSkin.validateStructure(buffer, pos); + if (!skinResult.isValid()) { + return ValidationResult.error("Invalid Skin: " + skinResult.error()); + } + + pos += PlayerSkin.computeBytesConsumed(buffer, pos); + } + + return ValidationResult.OK; + } + } + + public PlayerSkinUpdate clone() { + PlayerSkinUpdate copy = new PlayerSkinUpdate(); + copy.skin = this.skin != null ? this.skin.clone() : null; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof PlayerSkinUpdate other ? Objects.equals(this.skin, other.skin) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.skin); + } +} diff --git a/src/com/hypixel/hytale/protocol/PredictionUpdate.java b/src/com/hypixel/hytale/protocol/PredictionUpdate.java new file mode 100644 index 00000000..9687a9d0 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/PredictionUpdate.java @@ -0,0 +1,76 @@ +package com.hypixel.hytale.protocol; + +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 PredictionUpdate extends ComponentUpdate { + 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 predictionId = new UUID(0L, 0L); + + public PredictionUpdate() { + } + + public PredictionUpdate(@Nonnull UUID predictionId) { + this.predictionId = predictionId; + } + + public PredictionUpdate(@Nonnull PredictionUpdate other) { + this.predictionId = other.predictionId; + } + + @Nonnull + public static PredictionUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + PredictionUpdate obj = new PredictionUpdate(); + obj.predictionId = 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.predictionId); + 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 PredictionUpdate clone() { + PredictionUpdate copy = new PredictionUpdate(); + copy.predictionId = this.predictionId; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof PredictionUpdate other ? Objects.equals(this.predictionId, other.predictionId) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.predictionId); + } +} diff --git a/src/com/hypixel/hytale/protocol/PropUpdate.java b/src/com/hypixel/hytale/protocol/PropUpdate.java new file mode 100644 index 00000000..1892e9f7 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/PropUpdate.java @@ -0,0 +1,51 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import javax.annotation.Nonnull; + +public class PropUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 0; + + @Nonnull + public static PropUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + return new PropUpdate(); + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 0; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 0; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK; + } + + public PropUpdate clone() { + return new PropUpdate(); + } + + @Override + public boolean equals(Object obj) { + return this == obj ? true : obj instanceof PropUpdate other; + } + + @Override + public int hashCode() { + return 0; + } +} diff --git a/src/com/hypixel/hytale/protocol/ProtocolSettings.java b/src/com/hypixel/hytale/protocol/ProtocolSettings.java index 13f2c489..d535f3b1 100644 --- a/src/com/hypixel/hytale/protocol/ProtocolSettings.java +++ b/src/com/hypixel/hytale/protocol/ProtocolSettings.java @@ -1,18 +1,18 @@ package com.hypixel.hytale.protocol; public final class ProtocolSettings { - public static final int PROTOCOL_CRC = 1789265863; + public static final int PROTOCOL_CRC = -1356075132; public static final int PROTOCOL_VERSION = 2; - public static final int PROTOCOL_BUILD_NUMBER = 2; + public static final int PROTOCOL_BUILD_NUMBER = 20; public static final int PACKET_COUNT = 268; - public static final int STRUCT_COUNT = 314; - public static final int ENUM_COUNT = 136; + public static final int STRUCT_COUNT = 339; + public static final int ENUM_COUNT = 137; public static final int MAX_PACKET_SIZE = 1677721600; private ProtocolSettings() { } public static boolean validateCrc(int crc) { - return 1789265863 == crc; + return -1356075132 == crc; } } diff --git a/src/com/hypixel/hytale/protocol/RepulsionUpdate.java b/src/com/hypixel/hytale/protocol/RepulsionUpdate.java new file mode 100644 index 00000000..fb01b04f --- /dev/null +++ b/src/com/hypixel/hytale/protocol/RepulsionUpdate.java @@ -0,0 +1,73 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; + +public class RepulsionUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 4; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 4; + public static final int MAX_SIZE = 4; + public int repulsionConfigIndex; + + public RepulsionUpdate() { + } + + public RepulsionUpdate(int repulsionConfigIndex) { + this.repulsionConfigIndex = repulsionConfigIndex; + } + + public RepulsionUpdate(@Nonnull RepulsionUpdate other) { + this.repulsionConfigIndex = other.repulsionConfigIndex; + } + + @Nonnull + public static RepulsionUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + RepulsionUpdate obj = new RepulsionUpdate(); + obj.repulsionConfigIndex = buf.getIntLE(offset + 0); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 4; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + buf.writeIntLE(this.repulsionConfigIndex); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 4; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 4 ? ValidationResult.error("Buffer too small: expected at least 4 bytes") : ValidationResult.OK; + } + + public RepulsionUpdate clone() { + RepulsionUpdate copy = new RepulsionUpdate(); + copy.repulsionConfigIndex = this.repulsionConfigIndex; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof RepulsionUpdate other ? this.repulsionConfigIndex == other.repulsionConfigIndex : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.repulsionConfigIndex); + } +} diff --git a/src/com/hypixel/hytale/protocol/RespondToHitUpdate.java b/src/com/hypixel/hytale/protocol/RespondToHitUpdate.java new file mode 100644 index 00000000..23bbd078 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/RespondToHitUpdate.java @@ -0,0 +1,51 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import javax.annotation.Nonnull; + +public class RespondToHitUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 0; + + @Nonnull + public static RespondToHitUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + return new RespondToHitUpdate(); + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 0; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 0; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK; + } + + public RespondToHitUpdate clone() { + return new RespondToHitUpdate(); + } + + @Override + public boolean equals(Object obj) { + return this == obj ? true : obj instanceof RespondToHitUpdate other; + } + + @Override + public int hashCode() { + return 0; + } +} diff --git a/src/com/hypixel/hytale/protocol/ToClientPacket.java b/src/com/hypixel/hytale/protocol/ToClientPacket.java new file mode 100644 index 00000000..f8d8d45a --- /dev/null +++ b/src/com/hypixel/hytale/protocol/ToClientPacket.java @@ -0,0 +1,4 @@ +package com.hypixel.hytale.protocol; + +public interface ToClientPacket extends Packet { +} diff --git a/src/com/hypixel/hytale/protocol/ToServerPacket.java b/src/com/hypixel/hytale/protocol/ToServerPacket.java new file mode 100644 index 00000000..7b552893 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/ToServerPacket.java @@ -0,0 +1,4 @@ +package com.hypixel.hytale.protocol; + +public interface ToServerPacket extends Packet { +} diff --git a/src/com/hypixel/hytale/protocol/TransformUpdate.java b/src/com/hypixel/hytale/protocol/TransformUpdate.java new file mode 100644 index 00000000..111907ed --- /dev/null +++ b/src/com/hypixel/hytale/protocol/TransformUpdate.java @@ -0,0 +1,74 @@ +package com.hypixel.hytale.protocol; + +import com.hypixel.hytale.protocol.io.ValidationResult; +import io.netty.buffer.ByteBuf; +import java.util.Objects; +import javax.annotation.Nonnull; + +public class TransformUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 49; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 49; + public static final int MAX_SIZE = 49; + @Nonnull + public ModelTransform transform = new ModelTransform(); + + public TransformUpdate() { + } + + public TransformUpdate(@Nonnull ModelTransform transform) { + this.transform = transform; + } + + public TransformUpdate(@Nonnull TransformUpdate other) { + this.transform = other.transform; + } + + @Nonnull + public static TransformUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + TransformUpdate obj = new TransformUpdate(); + obj.transform = ModelTransform.deserialize(buf, offset + 0); + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + return 49; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + this.transform.serialize(buf); + return buf.writerIndex() - startPos; + } + + @Override + public int computeSize() { + return 49; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + return buffer.readableBytes() - offset < 49 ? ValidationResult.error("Buffer too small: expected at least 49 bytes") : ValidationResult.OK; + } + + public TransformUpdate clone() { + TransformUpdate copy = new TransformUpdate(); + copy.transform = this.transform.clone(); + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof TransformUpdate other ? Objects.equals(this.transform, other.transform) : false; + } + } + + @Override + public int hashCode() { + return Objects.hash(this.transform); + } +} diff --git a/src/com/hypixel/hytale/protocol/UIComponentsUpdate.java b/src/com/hypixel/hytale/protocol/UIComponentsUpdate.java new file mode 100644 index 00000000..aa3a6077 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/UIComponentsUpdate.java @@ -0,0 +1,124 @@ +package com.hypixel.hytale.protocol; + +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.Arrays; +import javax.annotation.Nonnull; + +public class UIComponentsUpdate extends ComponentUpdate { + public static final int NULLABLE_BIT_FIELD_SIZE = 0; + public static final int FIXED_BLOCK_SIZE = 0; + public static final int VARIABLE_FIELD_COUNT = 1; + public static final int VARIABLE_BLOCK_START = 0; + public static final int MAX_SIZE = 16384005; + @Nonnull + public int[] components = new int[0]; + + public UIComponentsUpdate() { + } + + public UIComponentsUpdate(@Nonnull int[] components) { + this.components = components; + } + + public UIComponentsUpdate(@Nonnull UIComponentsUpdate other) { + this.components = other.components; + } + + @Nonnull + public static UIComponentsUpdate deserialize(@Nonnull ByteBuf buf, int offset) { + UIComponentsUpdate obj = new UIComponentsUpdate(); + int pos = offset + 0; + int componentsCount = VarInt.peek(buf, pos); + if (componentsCount < 0) { + throw ProtocolException.negativeLength("Components", componentsCount); + } else if (componentsCount > 4096000) { + throw ProtocolException.arrayTooLong("Components", componentsCount, 4096000); + } else { + int componentsVarLen = VarInt.size(componentsCount); + if (pos + componentsVarLen + componentsCount * 4L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("Components", pos + componentsVarLen + componentsCount * 4, buf.readableBytes()); + } else { + pos += componentsVarLen; + obj.components = new int[componentsCount]; + + for (int i = 0; i < componentsCount; i++) { + obj.components[i] = buf.getIntLE(pos + i * 4); + } + + pos += componentsCount * 4; + return obj; + } + } + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + int pos = offset + 0; + int arrLen = VarInt.peek(buf, pos); + pos += VarInt.length(buf, pos) + arrLen * 4; + return pos - offset; + } + + @Override + public int serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + if (this.components.length > 4096000) { + throw ProtocolException.arrayTooLong("Components", this.components.length, 4096000); + } else { + VarInt.write(buf, this.components.length); + + for (int item : this.components) { + buf.writeIntLE(item); + } + + return buf.writerIndex() - startPos; + } + } + + @Override + public int computeSize() { + int size = 0; + return size + VarInt.size(this.components.length) + this.components.length * 4; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 0) { + return ValidationResult.error("Buffer too small: expected at least 0 bytes"); + } else { + int pos = offset + 0; + int componentsCount = VarInt.peek(buffer, pos); + if (componentsCount < 0) { + return ValidationResult.error("Invalid array count for Components"); + } else if (componentsCount > 4096000) { + return ValidationResult.error("Components exceeds max length 4096000"); + } else { + pos += VarInt.length(buffer, pos); + pos += componentsCount * 4; + return pos > buffer.writerIndex() ? ValidationResult.error("Buffer overflow reading Components") : ValidationResult.OK; + } + } + } + + public UIComponentsUpdate clone() { + UIComponentsUpdate copy = new UIComponentsUpdate(); + copy.components = Arrays.copyOf(this.components, this.components.length); + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return obj instanceof UIComponentsUpdate other ? Arrays.equals(this.components, other.components) : false; + } + } + + @Override + public int hashCode() { + int result = 1; + return 31 * result + Arrays.hashCode(this.components); + } +} diff --git a/src/com/hypixel/hytale/protocol/io/PacketIO.java b/src/com/hypixel/hytale/protocol/io/PacketIO.java index 9e45dda6..623553de 100644 --- a/src/com/hypixel/hytale/protocol/io/PacketIO.java +++ b/src/com/hypixel/hytale/protocol/io/PacketIO.java @@ -305,7 +305,7 @@ public final class PacketIO { if (id == null) { throw new ProtocolException("Unknown packet type: " + packetClass.getName()); } else { - PacketRegistry.PacketInfo info = PacketRegistry.getById(id); + PacketRegistry.PacketInfo info = PacketRegistry.getToClientPacketById(id); int lengthIndex = out.writerIndex(); out.writeIntLE(0); out.writeIntLE(id); @@ -351,7 +351,7 @@ public final class PacketIO { @Nonnull public static Packet readFramedPacket(@Nonnull ByteBuf in, int payloadLength, @Nonnull PacketStatsRecorder statsRecorder) { int packetId = in.readIntLE(); - PacketRegistry.PacketInfo info = PacketRegistry.getById(packetId); + PacketRegistry.PacketInfo info = PacketRegistry.getToServerPacketById(packetId); if (info == null) { in.skipBytes(payloadLength); throw new ProtocolException("Unknown packet ID: " + packetId); diff --git a/src/com/hypixel/hytale/protocol/io/netty/PacketDecoder.java b/src/com/hypixel/hytale/protocol/io/netty/PacketDecoder.java index 2f840bae..ad16d87d 100644 --- a/src/com/hypixel/hytale/protocol/io/netty/PacketDecoder.java +++ b/src/com/hypixel/hytale/protocol/io/netty/PacketDecoder.java @@ -1,5 +1,6 @@ package com.hypixel.hytale.protocol.io.netty; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.PacketRegistry; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.PacketStatsRecorder; @@ -80,30 +81,36 @@ public class PacketDecoder extends ByteToMessageDecoder { int payloadLength = in.readIntLE(); if (payloadLength >= 0 && payloadLength <= 1677721600) { int packetId = in.readIntLE(); - PacketRegistry.PacketInfo packetInfo = PacketRegistry.getById(packetId); + PacketRegistry.PacketInfo packetInfo = PacketRegistry.getToServerPacketById(packetId); if (packetInfo == null) { in.skipBytes(in.readableBytes()); ProtocolUtil.closeConnection(ctx.channel()); } else if (payloadLength > packetInfo.maxSize()) { in.skipBytes(in.readableBytes()); ProtocolUtil.closeConnection(ctx.channel()); - } else if (in.readableBytes() < payloadLength) { - in.resetReaderIndex(); } else { - PacketStatsRecorder statsRecorder = ctx.channel().attr(PacketStatsRecorder.CHANNEL_KEY).get(); - if (statsRecorder == null) { - statsRecorder = PacketStatsRecorder.NOOP; - } + NetworkChannel channelVal = ctx.channel().attr(ProtocolUtil.STREAM_CHANNEL_KEY).get(); + if (channelVal != null && channelVal != packetInfo.channel()) { + in.skipBytes(in.readableBytes()); + ProtocolUtil.closeConnection(ctx.channel()); + } else if (in.readableBytes() < payloadLength) { + in.resetReaderIndex(); + } else { + PacketStatsRecorder statsRecorder = ctx.channel().attr(PacketStatsRecorder.CHANNEL_KEY).get(); + if (statsRecorder == null) { + statsRecorder = PacketStatsRecorder.NOOP; + } - try { - out.add(PacketIO.readFramedPacketWithInfo(in, payloadLength, packetInfo, statsRecorder)); - this.lastPacketTimeNanos = System.nanoTime(); - } catch (ProtocolException var9) { - in.skipBytes(in.readableBytes()); - ProtocolUtil.closeConnection(ctx.channel()); - } catch (IndexOutOfBoundsException var10) { - in.skipBytes(in.readableBytes()); - ProtocolUtil.closeConnection(ctx.channel()); + try { + out.add(PacketIO.readFramedPacketWithInfo(in, payloadLength, packetInfo, statsRecorder)); + this.lastPacketTimeNanos = System.nanoTime(); + } catch (ProtocolException var10) { + in.skipBytes(in.readableBytes()); + ProtocolUtil.closeConnection(ctx.channel()); + } catch (IndexOutOfBoundsException var11) { + in.skipBytes(in.readableBytes()); + ProtocolUtil.closeConnection(ctx.channel()); + } } } } else { diff --git a/src/com/hypixel/hytale/protocol/io/netty/PacketEncoder.java b/src/com/hypixel/hytale/protocol/io/netty/PacketEncoder.java index 15129808..36ee862d 100644 --- a/src/com/hypixel/hytale/protocol/io/netty/PacketEncoder.java +++ b/src/com/hypixel/hytale/protocol/io/netty/PacketEncoder.java @@ -1,6 +1,7 @@ package com.hypixel.hytale.protocol.io.netty; import com.hypixel.hytale.protocol.CachedPacket; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.PacketStatsRecorder; @@ -20,11 +21,16 @@ public class PacketEncoder extends MessageToByteEncoder { packetClass = (Class)packet.getClass(); } - PacketStatsRecorder statsRecorder = ctx.channel().attr(PacketStatsRecorder.CHANNEL_KEY).get(); - if (statsRecorder == null) { - statsRecorder = PacketStatsRecorder.NOOP; - } + NetworkChannel channelAttr = ctx.channel().attr(ProtocolUtil.STREAM_CHANNEL_KEY).get(); + if (channelAttr != null && channelAttr != packet.getChannel()) { + throw new IllegalArgumentException("Packet channel " + packet.getChannel() + " does not match stream channel " + channelAttr); + } else { + PacketStatsRecorder statsRecorder = ctx.channel().attr(PacketStatsRecorder.CHANNEL_KEY).get(); + if (statsRecorder == null) { + statsRecorder = PacketStatsRecorder.NOOP; + } - PacketIO.writeFramedPacket(packet, packetClass, out, statsRecorder); + PacketIO.writeFramedPacket(packet, packetClass, out, statsRecorder); + } } } diff --git a/src/com/hypixel/hytale/protocol/io/netty/ProtocolUtil.java b/src/com/hypixel/hytale/protocol/io/netty/ProtocolUtil.java index 8d1db800..2c7a80c2 100644 --- a/src/com/hypixel/hytale/protocol/io/netty/ProtocolUtil.java +++ b/src/com/hypixel/hytale/protocol/io/netty/ProtocolUtil.java @@ -1,5 +1,6 @@ package com.hypixel.hytale.protocol.io.netty; +import com.hypixel.hytale.protocol.NetworkChannel; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; @@ -13,6 +14,7 @@ import java.time.Duration; import javax.annotation.Nonnull; public final class ProtocolUtil { + public static final AttributeKey STREAM_CHANNEL_KEY = AttributeKey.newInstance("STREAM_CHANNEL_ID"); public static final AttributeKey PACKET_TIMEOUT_KEY = AttributeKey.newInstance("PACKET_TIMEOUT"); public static final int APPLICATION_NO_ERROR = 0; public static final int APPLICATION_RATE_LIMITED = 1; diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorActivateButton.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorActivateButton.java index 2285387c..d170e778 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorActivateButton.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorActivateButton.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorActivateButton implements Packet { +public class AssetEditorActivateButton implements Packet, ToServerPacket { public static final int PACKET_ID = 335; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class AssetEditorActivateButton implements Packet { return 335; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorActivateButton() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetListSetup.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetListSetup.java index f65a3dba..1b128a50 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetListSetup.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetListSetup.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorAssetListSetup implements Packet { +public class AssetEditorAssetListSetup implements Packet, ToClientPacket { public static final int PACKET_ID = 319; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class AssetEditorAssetListSetup implements Packet { return 319; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorAssetListSetup() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetListUpdate.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetListUpdate.java index 33bb225a..ee19d5ae 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetListUpdate.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetListUpdate.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorAssetListUpdate implements Packet { +public class AssetEditorAssetListUpdate implements Packet, ToClientPacket { public static final int PACKET_ID = 320; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -31,6 +33,11 @@ public class AssetEditorAssetListUpdate implements Packet { return 320; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorAssetListUpdate() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetPackSetup.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetPackSetup.java index 57ae324d..f0c64314 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetPackSetup.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetPackSetup.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -13,7 +15,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorAssetPackSetup implements Packet { +public class AssetEditorAssetPackSetup implements Packet, ToClientPacket { public static final int PACKET_ID = 314; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class AssetEditorAssetPackSetup implements Packet { return 314; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorAssetPackSetup() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetUpdated.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetUpdated.java index 1198f8e6..0dc79b40 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetUpdated.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAssetUpdated.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorAssetUpdated implements Packet { +public class AssetEditorAssetUpdated implements Packet, ToClientPacket { public static final int PACKET_ID = 326; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class AssetEditorAssetUpdated implements Packet { return 326; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorAssetUpdated() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAuthorization.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAuthorization.java index 8ce5f448..97b9c3e9 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAuthorization.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorAuthorization.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class AssetEditorAuthorization implements Packet { +public class AssetEditorAuthorization implements Packet, ToClientPacket { public static final int PACKET_ID = 303; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class AssetEditorAuthorization implements Packet { return 303; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorAuthorization() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCapabilities.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCapabilities.java index cea7bd59..fed1e2bc 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCapabilities.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCapabilities.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class AssetEditorCapabilities implements Packet { +public class AssetEditorCapabilities implements Packet, ToClientPacket { public static final int PACKET_ID = 304; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -25,6 +27,11 @@ public class AssetEditorCapabilities implements Packet { return 304; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorCapabilities() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateAsset.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateAsset.java index 2f29509c..36f4a20f 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateAsset.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateAsset.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorCreateAsset implements Packet { +public class AssetEditorCreateAsset implements Packet, ToServerPacket { public static final int PACKET_ID = 327; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -34,6 +36,11 @@ public class AssetEditorCreateAsset implements Packet { return 327; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorCreateAsset() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateAssetPack.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateAssetPack.java index 065c6fa5..48617296 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateAssetPack.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateAssetPack.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorCreateAssetPack implements Packet { +public class AssetEditorCreateAssetPack implements Packet, ToServerPacket { public static final int PACKET_ID = 316; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class AssetEditorCreateAssetPack implements Packet { return 316; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorCreateAssetPack() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateDirectory.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateDirectory.java index 81d8810c..6aa5c436 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateDirectory.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorCreateDirectory.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorCreateDirectory implements Packet { +public class AssetEditorCreateDirectory implements Packet, ToServerPacket { public static final int PACKET_ID = 307; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class AssetEditorCreateDirectory implements Packet { return 307; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorCreateDirectory() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteAsset.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteAsset.java index 12e6cf90..3a3930fe 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteAsset.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteAsset.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorDeleteAsset implements Packet { +public class AssetEditorDeleteAsset implements Packet, ToServerPacket { public static final int PACKET_ID = 329; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class AssetEditorDeleteAsset implements Packet { return 329; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorDeleteAsset() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteAssetPack.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteAssetPack.java index cf3c7069..1fa57061 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteAssetPack.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteAssetPack.java @@ -1,6 +1,9 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorDeleteAssetPack implements Packet { +public class AssetEditorDeleteAssetPack implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 317; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +29,11 @@ public class AssetEditorDeleteAssetPack implements Packet { return 317; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorDeleteAssetPack() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteDirectory.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteDirectory.java index 42154672..d15087f9 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteDirectory.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDeleteDirectory.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorDeleteDirectory implements Packet { +public class AssetEditorDeleteDirectory implements Packet, ToServerPacket { public static final int PACKET_ID = 308; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class AssetEditorDeleteDirectory implements Packet { return 308; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorDeleteDirectory() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDiscardChanges.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDiscardChanges.java index 94e49ac2..919db322 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDiscardChanges.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorDiscardChanges.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorDiscardChanges implements Packet { +public class AssetEditorDiscardChanges implements Packet, ToServerPacket { public static final int PACKET_ID = 330; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorDiscardChanges implements Packet { return 330; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorDiscardChanges() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorEnableAssetPack.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorEnableAssetPack.java deleted file mode 100644 index d1e6585c..00000000 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorEnableAssetPack.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.hypixel.hytale.protocol.packets.asseteditor; - -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 AssetEditorEnableAssetPack implements Packet { - public static final int PACKET_ID = 318; - public static final boolean IS_COMPRESSED = false; - public static final int NULLABLE_BIT_FIELD_SIZE = 1; - public static final int FIXED_BLOCK_SIZE = 2; - public static final int VARIABLE_FIELD_COUNT = 1; - public static final int VARIABLE_BLOCK_START = 2; - public static final int MAX_SIZE = 16384007; - @Nullable - public String id; - public boolean enabled; - - @Override - public int getId() { - return 318; - } - - public AssetEditorEnableAssetPack() { - } - - public AssetEditorEnableAssetPack(@Nullable String id, boolean enabled) { - this.id = id; - this.enabled = enabled; - } - - public AssetEditorEnableAssetPack(@Nonnull AssetEditorEnableAssetPack other) { - this.id = other.id; - this.enabled = other.enabled; - } - - @Nonnull - public static AssetEditorEnableAssetPack deserialize(@Nonnull ByteBuf buf, int offset) { - AssetEditorEnableAssetPack obj = new AssetEditorEnableAssetPack(); - byte nullBits = buf.getByte(offset); - obj.enabled = buf.getByte(offset + 1) != 0; - int pos = offset + 2; - if ((nullBits & 1) != 0) { - int idLen = VarInt.peek(buf, pos); - if (idLen < 0) { - throw ProtocolException.negativeLength("Id", idLen); - } - - if (idLen > 4096000) { - throw ProtocolException.stringTooLong("Id", idLen, 4096000); - } - - int idVarLen = VarInt.length(buf, pos); - obj.id = PacketIO.readVarString(buf, pos, PacketIO.UTF8); - pos += idVarLen + idLen; - } - - return obj; - } - - public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { - byte nullBits = buf.getByte(offset); - int pos = offset + 2; - 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.id != null) { - nullBits = (byte)(nullBits | 1); - } - - buf.writeByte(nullBits); - buf.writeByte(this.enabled ? 1 : 0); - if (this.id != null) { - PacketIO.writeVarString(buf, this.id, 4096000); - } - } - - @Override - public int computeSize() { - int size = 2; - if (this.id != null) { - size += PacketIO.stringSize(this.id); - } - - return size; - } - - public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 2) { - return ValidationResult.error("Buffer too small: expected at least 2 bytes"); - } else { - byte nullBits = buffer.getByte(offset); - int pos = offset + 2; - if ((nullBits & 1) != 0) { - int idLen = VarInt.peek(buffer, pos); - if (idLen < 0) { - return ValidationResult.error("Invalid string length for Id"); - } - - if (idLen > 4096000) { - return ValidationResult.error("Id exceeds max length 4096000"); - } - - pos += VarInt.length(buffer, pos); - pos += idLen; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Id"); - } - } - - return ValidationResult.OK; - } - } - - public AssetEditorEnableAssetPack clone() { - AssetEditorEnableAssetPack copy = new AssetEditorEnableAssetPack(); - copy.id = this.id; - copy.enabled = this.enabled; - return copy; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } else { - return !(obj instanceof AssetEditorEnableAssetPack other) ? false : Objects.equals(this.id, other.id) && this.enabled == other.enabled; - } - } - - @Override - public int hashCode() { - return Objects.hash(this.id, this.enabled); - } -} diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetFinalize.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetFinalize.java index ad8a7876..e1fee512 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetFinalize.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetFinalize.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class AssetEditorExportAssetFinalize implements Packet { +public class AssetEditorExportAssetFinalize implements Packet, ToClientPacket { public static final int PACKET_ID = 345; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class AssetEditorExportAssetFinalize implements Packet { return 345; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static AssetEditorExportAssetFinalize deserialize(@Nonnull ByteBuf buf, int offset) { return new AssetEditorExportAssetFinalize(); diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetInitialize.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetInitialize.java index 81394c57..809dbf40 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetInitialize.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetInitialize.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorExportAssetInitialize implements Packet { +public class AssetEditorExportAssetInitialize implements Packet, ToClientPacket { public static final int PACKET_ID = 343; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class AssetEditorExportAssetInitialize implements Packet { return 343; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorExportAssetInitialize() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetPart.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetPart.java index 9cf34b02..fcf9cbfa 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetPart.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssetPart.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorExportAssetPart implements Packet { +public class AssetEditorExportAssetPart implements Packet, ToClientPacket { public static final int PACKET_ID = 344; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorExportAssetPart implements Packet { return 344; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorExportAssetPart() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssets.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssets.java index 5cc961ad..d920088a 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssets.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportAssets.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorExportAssets implements Packet { +public class AssetEditorExportAssets implements Packet, ToServerPacket { public static final int PACKET_ID = 342; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorExportAssets implements Packet { return 342; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorExportAssets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportComplete.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportComplete.java index 514e49ec..eddb8431 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportComplete.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportComplete.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorExportComplete implements Packet { +public class AssetEditorExportComplete implements Packet, ToClientPacket { public static final int PACKET_ID = 347; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorExportComplete implements Packet { return 347; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorExportComplete() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportDeleteAssets.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportDeleteAssets.java index 8bac5c26..ca60537c 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportDeleteAssets.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorExportDeleteAssets.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorExportDeleteAssets implements Packet { +public class AssetEditorExportDeleteAssets implements Packet, ToClientPacket { public static final int PACKET_ID = 346; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorExportDeleteAssets implements Packet { return 346; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorExportDeleteAssets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAsset.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAsset.java index faf9a38a..5889a915 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAsset.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAsset.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorFetchAsset implements Packet { +public class AssetEditorFetchAsset implements Packet, ToServerPacket { public static final int PACKET_ID = 310; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorFetchAsset implements Packet { return 310; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorFetchAsset() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAssetReply.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAssetReply.java index d80d9441..35bfaae7 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAssetReply.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAssetReply.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorFetchAssetReply implements Packet { +public class AssetEditorFetchAssetReply implements Packet, ToClientPacket { public static final int PACKET_ID = 312; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class AssetEditorFetchAssetReply implements Packet { return 312; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorFetchAssetReply() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAutoCompleteData.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAutoCompleteData.java index 667664e7..de412387 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAutoCompleteData.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAutoCompleteData.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorFetchAutoCompleteData implements Packet { +public class AssetEditorFetchAutoCompleteData implements Packet, ToServerPacket { public static final int PACKET_ID = 331; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class AssetEditorFetchAutoCompleteData implements Packet { return 331; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorFetchAutoCompleteData() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAutoCompleteDataReply.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAutoCompleteDataReply.java index 4720cd65..95f27b4f 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAutoCompleteDataReply.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchAutoCompleteDataReply.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorFetchAutoCompleteDataReply implements Packet { +public class AssetEditorFetchAutoCompleteDataReply implements Packet, ToClientPacket { public static final int PACKET_ID = 332; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class AssetEditorFetchAutoCompleteDataReply implements Packet { return 332; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorFetchAutoCompleteDataReply() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchJsonAssetWithParents.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchJsonAssetWithParents.java index 349814fc..61a54f68 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchJsonAssetWithParents.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchJsonAssetWithParents.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorFetchJsonAssetWithParents implements Packet { +public class AssetEditorFetchJsonAssetWithParents implements Packet, ToServerPacket { public static final int PACKET_ID = 311; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorFetchJsonAssetWithParents implements Packet { return 311; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorFetchJsonAssetWithParents() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchJsonAssetWithParentsReply.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchJsonAssetWithParentsReply.java index 1d9fb157..3052b8c5 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchJsonAssetWithParentsReply.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchJsonAssetWithParentsReply.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -13,7 +15,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorFetchJsonAssetWithParentsReply implements Packet { +public class AssetEditorFetchJsonAssetWithParentsReply implements Packet, ToClientPacket { public static final int PACKET_ID = 313; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class AssetEditorFetchJsonAssetWithParentsReply implements Packet { return 313; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorFetchJsonAssetWithParentsReply() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchLastModifiedAssets.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchLastModifiedAssets.java index e0b86b98..ac86a20c 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchLastModifiedAssets.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorFetchLastModifiedAssets.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class AssetEditorFetchLastModifiedAssets implements Packet { +public class AssetEditorFetchLastModifiedAssets implements Packet, ToServerPacket { public static final int PACKET_ID = 338; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class AssetEditorFetchLastModifiedAssets implements Packet { return 338; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static AssetEditorFetchLastModifiedAssets deserialize(@Nonnull ByteBuf buf, int offset) { return new AssetEditorFetchLastModifiedAssets(); diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorInitialize.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorInitialize.java index 30884917..b3f99ac1 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorInitialize.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorInitialize.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class AssetEditorInitialize implements Packet { +public class AssetEditorInitialize implements Packet, ToServerPacket { public static final int PACKET_ID = 302; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class AssetEditorInitialize implements Packet { return 302; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static AssetEditorInitialize deserialize(@Nonnull ByteBuf buf, int offset) { return new AssetEditorInitialize(); diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorJsonAssetUpdated.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorJsonAssetUpdated.java index a654f9a8..a7b93808 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorJsonAssetUpdated.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorJsonAssetUpdated.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorJsonAssetUpdated implements Packet { +public class AssetEditorJsonAssetUpdated implements Packet, ToClientPacket { public static final int PACKET_ID = 325; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class AssetEditorJsonAssetUpdated implements Packet { return 325; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorJsonAssetUpdated() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorLastModifiedAssets.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorLastModifiedAssets.java index 32ca9aff..73c2fb8f 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorLastModifiedAssets.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorLastModifiedAssets.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorLastModifiedAssets implements Packet { +public class AssetEditorLastModifiedAssets implements Packet, ToClientPacket { public static final int PACKET_ID = 339; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorLastModifiedAssets implements Packet { return 339; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorLastModifiedAssets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorModifiedAssetsCount.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorModifiedAssetsCount.java index 3a5738cd..56b21588 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorModifiedAssetsCount.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorModifiedAssetsCount.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class AssetEditorModifiedAssetsCount implements Packet { +public class AssetEditorModifiedAssetsCount implements Packet, ToClientPacket { public static final int PACKET_ID = 340; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class AssetEditorModifiedAssetsCount implements Packet { return 340; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorModifiedAssetsCount() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorPopupNotification.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorPopupNotification.java index f8a93c7c..df4d1840 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorPopupNotification.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorPopupNotification.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.asseteditor; import com.hypixel.hytale.protocol.FormattedMessage; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorPopupNotification implements Packet { +public class AssetEditorPopupNotification implements Packet, ToClientPacket { public static final int PACKET_ID = 337; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class AssetEditorPopupNotification implements Packet { return 337; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorPopupNotification() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRebuildCaches.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRebuildCaches.java index 60d2e72a..3f21bfc3 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRebuildCaches.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRebuildCaches.java @@ -1,14 +1,11 @@ package com.hypixel.hytale.protocol.packets.asseteditor; -import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class AssetEditorRebuildCaches implements Packet { - public static final int PACKET_ID = 348; - public static final boolean IS_COMPRESSED = false; +public class AssetEditorRebuildCaches { public static final int NULLABLE_BIT_FIELD_SIZE = 0; public static final int FIXED_BLOCK_SIZE = 5; public static final int VARIABLE_FIELD_COUNT = 0; @@ -20,11 +17,6 @@ public class AssetEditorRebuildCaches implements Packet { public boolean mapGeometry; public boolean itemIcons; - @Override - public int getId() { - return 348; - } - public AssetEditorRebuildCaches() { } @@ -59,7 +51,6 @@ public class AssetEditorRebuildCaches implements Packet { return 5; } - @Override public void serialize(@Nonnull ByteBuf buf) { buf.writeByte(this.blockTextures ? 1 : 0); buf.writeByte(this.models ? 1 : 0); @@ -68,7 +59,6 @@ public class AssetEditorRebuildCaches implements Packet { buf.writeByte(this.itemIcons ? 1 : 0); } - @Override public int computeSize() { return 5; } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRedoChanges.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRedoChanges.java index 03391a52..1578cd41 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRedoChanges.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRedoChanges.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorRedoChanges implements Packet { +public class AssetEditorRedoChanges implements Packet, ToServerPacket { public static final int PACKET_ID = 350; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class AssetEditorRedoChanges implements Packet { return 350; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorRedoChanges() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRenameAsset.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRenameAsset.java index 99c8016b..5d308b08 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRenameAsset.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRenameAsset.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorRenameAsset implements Packet { +public class AssetEditorRenameAsset implements Packet, ToServerPacket { public static final int PACKET_ID = 328; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class AssetEditorRenameAsset implements Packet { return 328; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorRenameAsset() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRenameDirectory.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRenameDirectory.java index 55c3ce02..e07c03a4 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRenameDirectory.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRenameDirectory.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorRenameDirectory implements Packet { +public class AssetEditorRenameDirectory implements Packet, ToServerPacket { public static final int PACKET_ID = 309; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class AssetEditorRenameDirectory implements Packet { return 309; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorRenameDirectory() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestChildrenList.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestChildrenList.java index 4db62797..e2d6e73c 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestChildrenList.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestChildrenList.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorRequestChildrenList implements Packet { +public class AssetEditorRequestChildrenList implements Packet, ToServerPacket { public static final int PACKET_ID = 321; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -23,6 +25,11 @@ public class AssetEditorRequestChildrenList implements Packet { return 321; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorRequestChildrenList() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestChildrenListReply.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestChildrenListReply.java index b6521baf..1d21db7c 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestChildrenListReply.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestChildrenListReply.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorRequestChildrenListReply implements Packet { +public class AssetEditorRequestChildrenListReply implements Packet, ToClientPacket { public static final int PACKET_ID = 322; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class AssetEditorRequestChildrenListReply implements Packet { return 322; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorRequestChildrenListReply() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestDataset.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestDataset.java index 8e76eada..8dc77d61 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestDataset.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestDataset.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorRequestDataset implements Packet { +public class AssetEditorRequestDataset implements Packet, ToServerPacket { public static final int PACKET_ID = 333; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class AssetEditorRequestDataset implements Packet { return 333; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorRequestDataset() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestDatasetReply.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestDatasetReply.java index ee31b2f4..cfe9d75e 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestDatasetReply.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorRequestDatasetReply.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorRequestDatasetReply implements Packet { +public class AssetEditorRequestDatasetReply implements Packet, ToClientPacket { public static final int PACKET_ID = 334; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class AssetEditorRequestDatasetReply implements Packet { return 334; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorRequestDatasetReply() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSelectAsset.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSelectAsset.java index 13a7f8f7..9c1ac256 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSelectAsset.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSelectAsset.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorSelectAsset implements Packet { +public class AssetEditorSelectAsset implements Packet, ToServerPacket { public static final int PACKET_ID = 336; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -23,6 +25,11 @@ public class AssetEditorSelectAsset implements Packet { return 336; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorSelectAsset() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetGameTime.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetGameTime.java index ce876948..5fd2a2a8 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetGameTime.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetGameTime.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.asseteditor; import com.hypixel.hytale.protocol.InstantData; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorSetGameTime implements Packet { +public class AssetEditorSetGameTime implements Packet, ToServerPacket { public static final int PACKET_ID = 352; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorSetGameTime implements Packet { return 352; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorSetGameTime() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetupAssetTypes.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetupAssetTypes.java index c3a45237..07a5d072 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetupAssetTypes.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetupAssetTypes.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorSetupAssetTypes implements Packet { +public class AssetEditorSetupAssetTypes implements Packet, ToClientPacket { public static final int PACKET_ID = 306; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorSetupAssetTypes implements Packet { return 306; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorSetupAssetTypes() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetupSchemas.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetupSchemas.java index 6def1bda..f637cf99 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetupSchemas.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSetupSchemas.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorSetupSchemas implements Packet { +public class AssetEditorSetupSchemas implements Packet, ToClientPacket { public static final int PACKET_ID = 305; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetEditorSetupSchemas implements Packet { return 305; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorSetupSchemas() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSubscribeModifiedAssetsChanges.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSubscribeModifiedAssetsChanges.java index 176f8b11..7e8d10b0 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSubscribeModifiedAssetsChanges.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorSubscribeModifiedAssetsChanges.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class AssetEditorSubscribeModifiedAssetsChanges implements Packet { +public class AssetEditorSubscribeModifiedAssetsChanges implements Packet, ToServerPacket { public static final int PACKET_ID = 341; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class AssetEditorSubscribeModifiedAssetsChanges implements Packet { return 341; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorSubscribeModifiedAssetsChanges() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUndoChanges.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUndoChanges.java index a35b8a24..09197daf 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUndoChanges.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUndoChanges.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorUndoChanges implements Packet { +public class AssetEditorUndoChanges implements Packet, ToServerPacket { public static final int PACKET_ID = 349; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class AssetEditorUndoChanges implements Packet { return 349; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorUndoChanges() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUndoRedoReply.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUndoRedoReply.java index 25bb0dcd..36347d5d 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUndoRedoReply.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUndoRedoReply.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorUndoRedoReply implements Packet { +public class AssetEditorUndoRedoReply implements Packet, ToClientPacket { public static final int PACKET_ID = 351; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class AssetEditorUndoRedoReply implements Packet { return 351; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorUndoRedoReply() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateAsset.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateAsset.java index dd086960..89b37e8b 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateAsset.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateAsset.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorUpdateAsset implements Packet { +public class AssetEditorUpdateAsset implements Packet, ToServerPacket { public static final int PACKET_ID = 324; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class AssetEditorUpdateAsset implements Packet { return 324; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorUpdateAsset() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateAssetPack.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateAssetPack.java index 256d0f80..d62e6128 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateAssetPack.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateAssetPack.java @@ -1,6 +1,9 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorUpdateAssetPack implements Packet { +public class AssetEditorUpdateAssetPack implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 315; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +31,11 @@ public class AssetEditorUpdateAssetPack implements Packet { return 315; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorUpdateAssetPack() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateJsonAsset.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateJsonAsset.java index a612673f..d087aafe 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateJsonAsset.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateJsonAsset.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorUpdateJsonAsset implements Packet { +public class AssetEditorUpdateJsonAsset implements Packet, ToServerPacket { public static final int PACKET_ID = 323; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class AssetEditorUpdateJsonAsset implements Packet { return 323; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorUpdateJsonAsset() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateModelPreview.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateModelPreview.java index 2a2e3880..9afce37c 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateModelPreview.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateModelPreview.java @@ -2,14 +2,16 @@ package com.hypixel.hytale.protocol.packets.asseteditor; import com.hypixel.hytale.protocol.BlockType; import com.hypixel.hytale.protocol.Model; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetEditorUpdateModelPreview implements Packet { +public class AssetEditorUpdateModelPreview implements Packet, ToClientPacket { public static final int PACKET_ID = 355; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -31,6 +33,11 @@ public class AssetEditorUpdateModelPreview implements Packet { return 355; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorUpdateModelPreview() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateSecondsPerGameDay.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateSecondsPerGameDay.java index 6eff03f6..712c89af 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateSecondsPerGameDay.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateSecondsPerGameDay.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class AssetEditorUpdateSecondsPerGameDay implements Packet { +public class AssetEditorUpdateSecondsPerGameDay implements Packet, ToClientPacket { public static final int PACKET_ID = 353; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class AssetEditorUpdateSecondsPerGameDay implements Packet { return 353; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorUpdateSecondsPerGameDay() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateWeatherPreviewLock.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateWeatherPreviewLock.java index e103ddaa..81113e8d 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateWeatherPreviewLock.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetEditorUpdateWeatherPreviewLock.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.asseteditor; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class AssetEditorUpdateWeatherPreviewLock implements Packet { +public class AssetEditorUpdateWeatherPreviewLock implements Packet, ToServerPacket { public static final int PACKET_ID = 354; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class AssetEditorUpdateWeatherPreviewLock implements Packet { return 354; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetEditorUpdateWeatherPreviewLock() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetPackManifest.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetPackManifest.java index 11172d6b..b507b2dd 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetPackManifest.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/AssetPackManifest.java @@ -13,8 +13,8 @@ import javax.annotation.Nullable; public class AssetPackManifest { public static final int NULLABLE_BIT_FIELD_SIZE = 1; public static final int FIXED_BLOCK_SIZE = 1; - public static final int VARIABLE_FIELD_COUNT = 6; - public static final int VARIABLE_BLOCK_START = 25; + public static final int VARIABLE_FIELD_COUNT = 7; + public static final int VARIABLE_BLOCK_START = 29; public static final int MAX_SIZE = 1677721600; @Nullable public String name; @@ -28,6 +28,8 @@ public class AssetPackManifest { public String version; @Nullable public AuthorInfo[] authors; + @Nullable + public String serverVersion; public AssetPackManifest() { } @@ -38,7 +40,8 @@ public class AssetPackManifest { @Nullable String website, @Nullable String description, @Nullable String version, - @Nullable AuthorInfo[] authors + @Nullable AuthorInfo[] authors, + @Nullable String serverVersion ) { this.name = name; this.group = group; @@ -46,6 +49,7 @@ public class AssetPackManifest { this.description = description; this.version = version; this.authors = authors; + this.serverVersion = serverVersion; } public AssetPackManifest(@Nonnull AssetPackManifest other) { @@ -55,6 +59,7 @@ public class AssetPackManifest { this.description = other.description; this.version = other.version; this.authors = other.authors; + this.serverVersion = other.serverVersion; } @Nonnull @@ -62,7 +67,7 @@ public class AssetPackManifest { AssetPackManifest obj = new AssetPackManifest(); byte nullBits = buf.getByte(offset); if ((nullBits & 1) != 0) { - int varPos0 = offset + 25 + buf.getIntLE(offset + 1); + int varPos0 = offset + 29 + buf.getIntLE(offset + 1); int nameLen = VarInt.peek(buf, varPos0); if (nameLen < 0) { throw ProtocolException.negativeLength("Name", nameLen); @@ -76,7 +81,7 @@ public class AssetPackManifest { } if ((nullBits & 2) != 0) { - int varPos1 = offset + 25 + buf.getIntLE(offset + 5); + int varPos1 = offset + 29 + buf.getIntLE(offset + 5); int groupLen = VarInt.peek(buf, varPos1); if (groupLen < 0) { throw ProtocolException.negativeLength("Group", groupLen); @@ -90,7 +95,7 @@ public class AssetPackManifest { } if ((nullBits & 4) != 0) { - int varPos2 = offset + 25 + buf.getIntLE(offset + 9); + int varPos2 = offset + 29 + buf.getIntLE(offset + 9); int websiteLen = VarInt.peek(buf, varPos2); if (websiteLen < 0) { throw ProtocolException.negativeLength("Website", websiteLen); @@ -104,7 +109,7 @@ public class AssetPackManifest { } if ((nullBits & 8) != 0) { - int varPos3 = offset + 25 + buf.getIntLE(offset + 13); + int varPos3 = offset + 29 + buf.getIntLE(offset + 13); int descriptionLen = VarInt.peek(buf, varPos3); if (descriptionLen < 0) { throw ProtocolException.negativeLength("Description", descriptionLen); @@ -118,7 +123,7 @@ public class AssetPackManifest { } if ((nullBits & 16) != 0) { - int varPos4 = offset + 25 + buf.getIntLE(offset + 17); + int varPos4 = offset + 29 + buf.getIntLE(offset + 17); int versionLen = VarInt.peek(buf, varPos4); if (versionLen < 0) { throw ProtocolException.negativeLength("Version", versionLen); @@ -132,7 +137,7 @@ public class AssetPackManifest { } if ((nullBits & 32) != 0) { - int varPos5 = offset + 25 + buf.getIntLE(offset + 21); + int varPos5 = offset + 29 + buf.getIntLE(offset + 21); int authorsCount = VarInt.peek(buf, varPos5); if (authorsCount < 0) { throw ProtocolException.negativeLength("Authors", authorsCount); @@ -156,15 +161,29 @@ public class AssetPackManifest { } } + if ((nullBits & 64) != 0) { + int varPos6 = offset + 29 + buf.getIntLE(offset + 25); + int serverVersionLen = VarInt.peek(buf, varPos6); + if (serverVersionLen < 0) { + throw ProtocolException.negativeLength("ServerVersion", serverVersionLen); + } + + if (serverVersionLen > 4096000) { + throw ProtocolException.stringTooLong("ServerVersion", serverVersionLen, 4096000); + } + + obj.serverVersion = PacketIO.readVarString(buf, varPos6, PacketIO.UTF8); + } + return obj; } public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte nullBits = buf.getByte(offset); - int maxEnd = 25; + int maxEnd = 29; if ((nullBits & 1) != 0) { int fieldOffset0 = buf.getIntLE(offset + 1); - int pos0 = offset + 25 + fieldOffset0; + int pos0 = offset + 29 + fieldOffset0; int sl = VarInt.peek(buf, pos0); pos0 += VarInt.length(buf, pos0) + sl; if (pos0 - offset > maxEnd) { @@ -174,7 +193,7 @@ public class AssetPackManifest { if ((nullBits & 2) != 0) { int fieldOffset1 = buf.getIntLE(offset + 5); - int pos1 = offset + 25 + fieldOffset1; + int pos1 = offset + 29 + fieldOffset1; int sl = VarInt.peek(buf, pos1); pos1 += VarInt.length(buf, pos1) + sl; if (pos1 - offset > maxEnd) { @@ -184,7 +203,7 @@ public class AssetPackManifest { if ((nullBits & 4) != 0) { int fieldOffset2 = buf.getIntLE(offset + 9); - int pos2 = offset + 25 + fieldOffset2; + int pos2 = offset + 29 + fieldOffset2; int sl = VarInt.peek(buf, pos2); pos2 += VarInt.length(buf, pos2) + sl; if (pos2 - offset > maxEnd) { @@ -194,7 +213,7 @@ public class AssetPackManifest { if ((nullBits & 8) != 0) { int fieldOffset3 = buf.getIntLE(offset + 13); - int pos3 = offset + 25 + fieldOffset3; + int pos3 = offset + 29 + fieldOffset3; int sl = VarInt.peek(buf, pos3); pos3 += VarInt.length(buf, pos3) + sl; if (pos3 - offset > maxEnd) { @@ -204,7 +223,7 @@ public class AssetPackManifest { if ((nullBits & 16) != 0) { int fieldOffset4 = buf.getIntLE(offset + 17); - int pos4 = offset + 25 + fieldOffset4; + int pos4 = offset + 29 + fieldOffset4; int sl = VarInt.peek(buf, pos4); pos4 += VarInt.length(buf, pos4) + sl; if (pos4 - offset > maxEnd) { @@ -214,7 +233,7 @@ public class AssetPackManifest { if ((nullBits & 32) != 0) { int fieldOffset5 = buf.getIntLE(offset + 21); - int pos5 = offset + 25 + fieldOffset5; + int pos5 = offset + 29 + fieldOffset5; int arrLen = VarInt.peek(buf, pos5); pos5 += VarInt.length(buf, pos5); @@ -227,6 +246,16 @@ public class AssetPackManifest { } } + if ((nullBits & 64) != 0) { + int fieldOffset6 = buf.getIntLE(offset + 25); + int pos6 = offset + 29 + fieldOffset6; + int sl = VarInt.peek(buf, pos6); + pos6 += VarInt.length(buf, pos6) + sl; + if (pos6 - offset > maxEnd) { + maxEnd = pos6 - offset; + } + } + return maxEnd; } @@ -257,6 +286,10 @@ public class AssetPackManifest { nullBits = (byte)(nullBits | 32); } + if (this.serverVersion != null) { + nullBits = (byte)(nullBits | 64); + } + buf.writeByte(nullBits); int nameOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); @@ -270,6 +303,8 @@ public class AssetPackManifest { buf.writeIntLE(0); int authorsOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); + int serverVersionOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); int varBlockStart = buf.writerIndex(); if (this.name != null) { buf.setIntLE(nameOffsetSlot, buf.writerIndex() - varBlockStart); @@ -320,10 +355,17 @@ public class AssetPackManifest { } else { buf.setIntLE(authorsOffsetSlot, -1); } + + if (this.serverVersion != null) { + buf.setIntLE(serverVersionOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.serverVersion, 4096000); + } else { + buf.setIntLE(serverVersionOffsetSlot, -1); + } } public int computeSize() { - int size = 25; + int size = 29; if (this.name != null) { size += PacketIO.stringSize(this.name); } @@ -354,12 +396,16 @@ public class AssetPackManifest { size += VarInt.size(this.authors.length) + authorsSize; } + if (this.serverVersion != null) { + size += PacketIO.stringSize(this.serverVersion); + } + return size; } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 25) { - return ValidationResult.error("Buffer too small: expected at least 25 bytes"); + if (buffer.readableBytes() - offset < 29) { + return ValidationResult.error("Buffer too small: expected at least 29 bytes"); } else { byte nullBits = buffer.getByte(offset); if ((nullBits & 1) != 0) { @@ -368,7 +414,7 @@ public class AssetPackManifest { return ValidationResult.error("Invalid offset for Name"); } - int pos = offset + 25 + nameOffset; + int pos = offset + 29 + nameOffset; if (pos >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Name"); } @@ -395,7 +441,7 @@ public class AssetPackManifest { return ValidationResult.error("Invalid offset for Group"); } - int posx = offset + 25 + groupOffset; + int posx = offset + 29 + groupOffset; if (posx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Group"); } @@ -422,7 +468,7 @@ public class AssetPackManifest { return ValidationResult.error("Invalid offset for Website"); } - int posxx = offset + 25 + websiteOffset; + int posxx = offset + 29 + websiteOffset; if (posxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Website"); } @@ -449,7 +495,7 @@ public class AssetPackManifest { return ValidationResult.error("Invalid offset for Description"); } - int posxxx = offset + 25 + descriptionOffset; + int posxxx = offset + 29 + descriptionOffset; if (posxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Description"); } @@ -476,7 +522,7 @@ public class AssetPackManifest { return ValidationResult.error("Invalid offset for Version"); } - int posxxxx = offset + 25 + versionOffset; + int posxxxx = offset + 29 + versionOffset; if (posxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Version"); } @@ -503,7 +549,7 @@ public class AssetPackManifest { return ValidationResult.error("Invalid offset for Authors"); } - int posxxxxx = offset + 25 + authorsOffset; + int posxxxxx = offset + 29 + authorsOffset; if (posxxxxx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Authors"); } @@ -529,6 +575,33 @@ public class AssetPackManifest { } } + if ((nullBits & 64) != 0) { + int serverVersionOffset = buffer.getIntLE(offset + 25); + if (serverVersionOffset < 0) { + return ValidationResult.error("Invalid offset for ServerVersion"); + } + + int posxxxxxx = offset + 29 + serverVersionOffset; + if (posxxxxxx >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for ServerVersion"); + } + + int serverVersionLen = VarInt.peek(buffer, posxxxxxx); + if (serverVersionLen < 0) { + return ValidationResult.error("Invalid string length for ServerVersion"); + } + + if (serverVersionLen > 4096000) { + return ValidationResult.error("ServerVersion exceeds max length 4096000"); + } + + posxxxxxx += VarInt.length(buffer, posxxxxxx); + posxxxxxx += serverVersionLen; + if (posxxxxxx > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading ServerVersion"); + } + } + return ValidationResult.OK; } } @@ -541,6 +614,7 @@ public class AssetPackManifest { copy.description = this.description; copy.version = this.version; copy.authors = this.authors != null ? Arrays.stream(this.authors).map(e -> e.clone()).toArray(AuthorInfo[]::new) : null; + copy.serverVersion = this.serverVersion; return copy; } @@ -556,7 +630,8 @@ public class AssetPackManifest { && Objects.equals(this.website, other.website) && Objects.equals(this.description, other.description) && Objects.equals(this.version, other.version) - && Arrays.equals((Object[])this.authors, (Object[])other.authors); + && Arrays.equals((Object[])this.authors, (Object[])other.authors) + && Objects.equals(this.serverVersion, other.serverVersion); } } @@ -568,6 +643,7 @@ public class AssetPackManifest { result = 31 * result + Objects.hashCode(this.website); result = 31 * result + Objects.hashCode(this.description); result = 31 * result + Objects.hashCode(this.version); - return 31 * result + Arrays.hashCode((Object[])this.authors); + result = 31 * result + Arrays.hashCode((Object[])this.authors); + return 31 * result + Objects.hashCode(this.serverVersion); } } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/FailureReply.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/FailureReply.java index 0c1d9a15..474b1e9e 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/FailureReply.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/FailureReply.java @@ -1,14 +1,17 @@ package com.hypixel.hytale.protocol.packets.asseteditor; import com.hypixel.hytale.protocol.FormattedMessage; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class FailureReply implements Packet { +public class FailureReply implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 300; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +28,11 @@ public class FailureReply implements Packet { return 300; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public FailureReply() { } diff --git a/src/com/hypixel/hytale/protocol/packets/asseteditor/SuccessReply.java b/src/com/hypixel/hytale/protocol/packets/asseteditor/SuccessReply.java index 0eaf52ea..bd0e9334 100644 --- a/src/com/hypixel/hytale/protocol/packets/asseteditor/SuccessReply.java +++ b/src/com/hypixel/hytale/protocol/packets/asseteditor/SuccessReply.java @@ -1,14 +1,17 @@ package com.hypixel.hytale.protocol.packets.asseteditor; import com.hypixel.hytale.protocol.FormattedMessage; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SuccessReply implements Packet { +public class SuccessReply implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 301; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +28,11 @@ public class SuccessReply implements Packet { return 301; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SuccessReply() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/TrackOrUpdateObjective.java b/src/com/hypixel/hytale/protocol/packets/assets/TrackOrUpdateObjective.java index 2a037079..bd66420d 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/TrackOrUpdateObjective.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/TrackOrUpdateObjective.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Objective; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class TrackOrUpdateObjective implements Packet { +public class TrackOrUpdateObjective implements Packet, ToClientPacket { public static final int PACKET_ID = 69; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class TrackOrUpdateObjective implements Packet { return 69; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public TrackOrUpdateObjective() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UntrackObjective.java b/src/com/hypixel/hytale/protocol/packets/assets/UntrackObjective.java index b13cd66b..c5981c25 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UntrackObjective.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UntrackObjective.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; @@ -8,7 +10,7 @@ import java.util.Objects; import java.util.UUID; import javax.annotation.Nonnull; -public class UntrackObjective implements Packet { +public class UntrackObjective implements Packet, ToClientPacket { public static final int PACKET_ID = 70; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -24,6 +26,11 @@ public class UntrackObjective implements Packet { return 70; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UntrackObjective() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateAmbienceFX.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateAmbienceFX.java index 590e6c3f..8eff1826 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateAmbienceFX.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateAmbienceFX.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.AmbienceFX; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateAmbienceFX implements Packet { +public class UpdateAmbienceFX implements Packet, ToClientPacket { public static final int PACKET_ID = 62; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateAmbienceFX implements Packet { return 62; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateAmbienceFX() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateAudioCategories.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateAudioCategories.java index 36c3deba..3174f2ad 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateAudioCategories.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateAudioCategories.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.AudioCategory; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateAudioCategories implements Packet { +public class UpdateAudioCategories implements Packet, ToClientPacket { public static final int PACKET_ID = 80; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateAudioCategories implements Packet { return 80; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateAudioCategories() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockBreakingDecals.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockBreakingDecals.java index b5fa7c60..a1ffe042 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockBreakingDecals.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockBreakingDecals.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.BlockBreakingDecal; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateBlockBreakingDecals implements Packet { +public class UpdateBlockBreakingDecals implements Packet, ToClientPacket { public static final int PACKET_ID = 45; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateBlockBreakingDecals implements Packet { return 45; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateBlockBreakingDecals() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockGroups.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockGroups.java index e7931560..da0f71c8 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockGroups.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockGroups.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.BlockGroup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateBlockGroups implements Packet { +public class UpdateBlockGroups implements Packet, ToClientPacket { public static final int PACKET_ID = 78; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateBlockGroups implements Packet { return 78; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateBlockGroups() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockHitboxes.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockHitboxes.java index 486339bc..293cb77a 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockHitboxes.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockHitboxes.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.Hitbox; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateBlockHitboxes implements Packet { +public class UpdateBlockHitboxes implements Packet, ToClientPacket { public static final int PACKET_ID = 41; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -34,6 +36,11 @@ public class UpdateBlockHitboxes implements Packet { return 41; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateBlockHitboxes() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockParticleSets.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockParticleSets.java index 9ff35d9c..93dfb887 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockParticleSets.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockParticleSets.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.BlockParticleSet; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateBlockParticleSets implements Packet { +public class UpdateBlockParticleSets implements Packet, ToClientPacket { public static final int PACKET_ID = 44; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateBlockParticleSets implements Packet { return 44; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateBlockParticleSets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockSets.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockSets.java index b3381777..eeae520e 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockSets.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockSets.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.BlockSet; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateBlockSets implements Packet { +public class UpdateBlockSets implements Packet, ToClientPacket { public static final int PACKET_ID = 46; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateBlockSets implements Packet { return 46; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateBlockSets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockSoundSets.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockSoundSets.java index 500a6ec9..cd2626dd 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockSoundSets.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockSoundSets.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.BlockSoundSet; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateBlockSoundSets implements Packet { +public class UpdateBlockSoundSets implements Packet, ToClientPacket { public static final int PACKET_ID = 42; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateBlockSoundSets implements Packet { return 42; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateBlockSoundSets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockTypes.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockTypes.java index cec9596c..313e52ae 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockTypes.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateBlockTypes.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.BlockType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateBlockTypes implements Packet { +public class UpdateBlockTypes implements Packet, ToClientPacket { public static final int PACKET_ID = 40; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -37,6 +39,11 @@ public class UpdateBlockTypes implements Packet { return 40; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateBlockTypes() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateCameraShake.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateCameraShake.java index ce620b83..e58d0e64 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateCameraShake.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateCameraShake.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.CameraShake; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateCameraShake implements Packet { +public class UpdateCameraShake implements Packet, ToClientPacket { public static final int PACKET_ID = 77; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -32,6 +34,11 @@ public class UpdateCameraShake implements Packet { return 77; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateCameraShake() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityEffects.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityEffects.java index 1b53e62f..ac3a9774 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityEffects.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityEffects.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.EntityEffect; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateEntityEffects implements Packet { +public class UpdateEntityEffects implements Packet, ToClientPacket { public static final int PACKET_ID = 51; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateEntityEffects implements Packet { return 51; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateEntityEffects() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityStatTypes.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityStatTypes.java index 72b948d1..03c95bb1 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityStatTypes.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityStatTypes.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.EntityStatType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateEntityStatTypes implements Packet { +public class UpdateEntityStatTypes implements Packet, ToClientPacket { public static final int PACKET_ID = 72; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateEntityStatTypes implements Packet { return 72; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateEntityStatTypes() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityUIComponents.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityUIComponents.java index 88d56343..1fefe3c4 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityUIComponents.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEntityUIComponents.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.EntityUIComponent; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateEntityUIComponents implements Packet { +public class UpdateEntityUIComponents implements Packet, ToClientPacket { public static final int PACKET_ID = 73; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateEntityUIComponents implements Packet { return 73; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateEntityUIComponents() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEnvironments.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEnvironments.java index a3f3c40e..63722fae 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEnvironments.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEnvironments.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.WorldEnvironment; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateEnvironments implements Packet { +public class UpdateEnvironments implements Packet, ToClientPacket { public static final int PACKET_ID = 61; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -34,6 +36,11 @@ public class UpdateEnvironments implements Packet { return 61; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateEnvironments() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEqualizerEffects.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEqualizerEffects.java index 880850bc..51b0e2d6 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateEqualizerEffects.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateEqualizerEffects.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.EqualizerEffect; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateEqualizerEffects implements Packet { +public class UpdateEqualizerEffects implements Packet, ToClientPacket { public static final int PACKET_ID = 82; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateEqualizerEffects implements Packet { return 82; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateEqualizerEffects() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateFieldcraftCategories.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateFieldcraftCategories.java index 116c2579..23a4497a 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateFieldcraftCategories.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateFieldcraftCategories.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.ItemCategory; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -12,7 +14,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateFieldcraftCategories implements Packet { +public class UpdateFieldcraftCategories implements Packet, ToClientPacket { public static final int PACKET_ID = 58; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class UpdateFieldcraftCategories implements Packet { return 58; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateFieldcraftCategories() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateFluidFX.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateFluidFX.java index 8d7e56b1..70720883 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateFluidFX.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateFluidFX.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.FluidFX; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateFluidFX implements Packet { +public class UpdateFluidFX implements Packet, ToClientPacket { public static final int PACKET_ID = 63; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateFluidFX implements Packet { return 63; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateFluidFX() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateFluids.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateFluids.java index f1023995..64a2f8c4 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateFluids.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateFluids.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.Fluid; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateFluids implements Packet { +public class UpdateFluids implements Packet, ToClientPacket { public static final int PACKET_ID = 83; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateFluids implements Packet { return 83; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateFluids() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateHitboxCollisionConfig.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateHitboxCollisionConfig.java index b3c8d868..6c7044be 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateHitboxCollisionConfig.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateHitboxCollisionConfig.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.HitboxCollisionConfig; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateHitboxCollisionConfig implements Packet { +public class UpdateHitboxCollisionConfig implements Packet, ToClientPacket { public static final int PACKET_ID = 74; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateHitboxCollisionConfig implements Packet { return 74; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateHitboxCollisionConfig() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateInteractions.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateInteractions.java index 7d5df164..c7a53570 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateInteractions.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateInteractions.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.Interaction; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateInteractions implements Packet { +public class UpdateInteractions implements Packet, ToClientPacket { public static final int PACKET_ID = 66; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateInteractions implements Packet { return 66; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateInteractions() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemCategories.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemCategories.java index 944f46f4..1f034175 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemCategories.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemCategories.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.ItemCategory; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -12,7 +14,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateItemCategories implements Packet { +public class UpdateItemCategories implements Packet, ToClientPacket { public static final int PACKET_ID = 56; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class UpdateItemCategories implements Packet { return 56; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateItemCategories() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemPlayerAnimations.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemPlayerAnimations.java index 296e0738..9b91d872 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemPlayerAnimations.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemPlayerAnimations.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.ItemPlayerAnimations; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateItemPlayerAnimations implements Packet { +public class UpdateItemPlayerAnimations implements Packet, ToClientPacket { public static final int PACKET_ID = 52; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateItemPlayerAnimations implements Packet { return 52; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateItemPlayerAnimations() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemQualities.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemQualities.java index 194d5613..65dde823 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemQualities.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemQualities.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.ItemQuality; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateItemQualities implements Packet { +public class UpdateItemQualities implements Packet, ToClientPacket { public static final int PACKET_ID = 55; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateItemQualities implements Packet { return 55; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateItemQualities() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemReticles.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemReticles.java index 3bf2c2fc..db638e17 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemReticles.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemReticles.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.ItemReticleConfig; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateItemReticles implements Packet { +public class UpdateItemReticles implements Packet, ToClientPacket { public static final int PACKET_ID = 57; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateItemReticles implements Packet { return 57; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateItemReticles() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemSoundSets.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemSoundSets.java index ca2a0c36..6d85ae14 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemSoundSets.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItemSoundSets.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.ItemSoundSet; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateItemSoundSets implements Packet { +public class UpdateItemSoundSets implements Packet, ToClientPacket { public static final int PACKET_ID = 43; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateItemSoundSets implements Packet { return 43; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateItemSoundSets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItems.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItems.java index e8cfae55..4c50ffc5 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateItems.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateItems.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.ItemBase; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -16,7 +18,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateItems implements Packet { +public class UpdateItems implements Packet, ToClientPacket { public static final int PACKET_ID = 54; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -38,6 +40,11 @@ public class UpdateItems implements Packet { return 54; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateItems() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateModelvfxs.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateModelvfxs.java index ae366ae9..b3c18635 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateModelvfxs.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateModelvfxs.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.ModelVFX; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateModelvfxs implements Packet { +public class UpdateModelvfxs implements Packet, ToClientPacket { public static final int PACKET_ID = 53; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateModelvfxs implements Packet { return 53; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateModelvfxs() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateObjectiveTask.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateObjectiveTask.java index 0f07666f..eef4b7c2 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateObjectiveTask.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateObjectiveTask.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.ObjectiveTask; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; @@ -10,14 +12,14 @@ import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateObjectiveTask implements Packet { +public class UpdateObjectiveTask implements Packet, ToClientPacket { public static final int PACKET_ID = 71; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; 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; @@ -29,6 +31,11 @@ public class UpdateObjectiveTask implements Packet { return 71; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateObjectiveTask() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateParticleSpawners.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateParticleSpawners.java index e944b678..9a908379 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateParticleSpawners.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateParticleSpawners.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.ParticleSpawner; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -16,7 +18,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateParticleSpawners implements Packet { +public class UpdateParticleSpawners implements Packet, ToClientPacket { public static final int PACKET_ID = 50; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -36,6 +38,11 @@ public class UpdateParticleSpawners implements Packet { return 50; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateParticleSpawners() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateParticleSystems.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateParticleSystems.java index 2b755398..6f28645c 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateParticleSystems.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateParticleSystems.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.ParticleSystem; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -16,7 +18,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateParticleSystems implements Packet { +public class UpdateParticleSystems implements Packet, ToClientPacket { public static final int PACKET_ID = 49; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -36,6 +38,11 @@ public class UpdateParticleSystems implements Packet { return 49; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateParticleSystems() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateProjectileConfigs.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateProjectileConfigs.java index 05ac4d0c..435a6a1b 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateProjectileConfigs.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateProjectileConfigs.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.ProjectileConfig; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -16,7 +18,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateProjectileConfigs implements Packet { +public class UpdateProjectileConfigs implements Packet, ToClientPacket { public static final int PACKET_ID = 85; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -36,6 +38,11 @@ public class UpdateProjectileConfigs implements Packet { return 85; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateProjectileConfigs() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateRecipes.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateRecipes.java index fd274c2d..bd476d1c 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateRecipes.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateRecipes.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.CraftingRecipe; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -16,7 +18,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateRecipes implements Packet { +public class UpdateRecipes implements Packet, ToClientPacket { public static final int PACKET_ID = 60; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -36,6 +38,11 @@ public class UpdateRecipes implements Packet { return 60; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateRecipes() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateRepulsionConfig.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateRepulsionConfig.java index 2ca2b9ec..ab3a5075 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateRepulsionConfig.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateRepulsionConfig.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.RepulsionConfig; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateRepulsionConfig implements Packet { +public class UpdateRepulsionConfig implements Packet, ToClientPacket { public static final int PACKET_ID = 75; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateRepulsionConfig implements Packet { return 75; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateRepulsionConfig() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateResourceTypes.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateResourceTypes.java index bf740990..a98a8eda 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateResourceTypes.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateResourceTypes.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.ResourceType; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateResourceTypes implements Packet { +public class UpdateResourceTypes implements Packet, ToClientPacket { public static final int PACKET_ID = 59; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateResourceTypes implements Packet { return 59; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateResourceTypes() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateReverbEffects.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateReverbEffects.java index 3e544b61..3515e545 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateReverbEffects.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateReverbEffects.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.ReverbEffect; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateReverbEffects implements Packet { +public class UpdateReverbEffects implements Packet, ToClientPacket { public static final int PACKET_ID = 81; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateReverbEffects implements Packet { return 81; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateReverbEffects() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateRootInteractions.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateRootInteractions.java index 143cc2dc..8f51e798 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateRootInteractions.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateRootInteractions.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.RootInteraction; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateRootInteractions implements Packet { +public class UpdateRootInteractions implements Packet, ToClientPacket { public static final int PACKET_ID = 67; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateRootInteractions implements Packet { return 67; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateRootInteractions() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateSoundEvents.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateSoundEvents.java index dd7ac61b..2cc08c88 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateSoundEvents.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateSoundEvents.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.SoundEvent; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateSoundEvents implements Packet { +public class UpdateSoundEvents implements Packet, ToClientPacket { public static final int PACKET_ID = 65; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateSoundEvents implements Packet { return 65; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateSoundEvents() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateSoundSets.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateSoundSets.java index 7aa63493..941eb103 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateSoundSets.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateSoundSets.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.SoundSet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateSoundSets implements Packet { +public class UpdateSoundSets implements Packet, ToClientPacket { public static final int PACKET_ID = 79; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateSoundSets implements Packet { return 79; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateSoundSets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateTagPatterns.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateTagPatterns.java index f15f1236..b29d51cc 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateTagPatterns.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateTagPatterns.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.TagPattern; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateTagPatterns implements Packet { +public class UpdateTagPatterns implements Packet, ToClientPacket { public static final int PACKET_ID = 84; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateTagPatterns implements Packet { return 84; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateTagPatterns() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateTrails.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateTrails.java index f5e7e83f..48dc2f8d 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateTrails.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateTrails.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.Trail; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateTrails implements Packet { +public class UpdateTrails implements Packet, ToClientPacket { public static final int PACKET_ID = 48; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateTrails implements Packet { return 48; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateTrails() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateTranslations.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateTranslations.java index c2fa0adc..911cba01 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateTranslations.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateTranslations.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateTranslations implements Packet { +public class UpdateTranslations implements Packet, ToClientPacket { public static final int PACKET_ID = 64; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -32,6 +34,11 @@ public class UpdateTranslations implements Packet { return 64; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateTranslations() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateUnarmedInteractions.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateUnarmedInteractions.java index 337157ba..f096076c 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateUnarmedInteractions.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateUnarmedInteractions.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.InteractionType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateUnarmedInteractions implements Packet { +public class UpdateUnarmedInteractions implements Packet, ToClientPacket { public static final int PACKET_ID = 68; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -32,6 +34,11 @@ public class UpdateUnarmedInteractions implements Packet { return 68; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateUnarmedInteractions() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateViewBobbing.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateViewBobbing.java index 35879052..3e642ea9 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateViewBobbing.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateViewBobbing.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.assets; import com.hypixel.hytale.protocol.MovementType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.ViewBobbing; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -15,7 +17,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateViewBobbing implements Packet { +public class UpdateViewBobbing implements Packet, ToClientPacket { public static final int PACKET_ID = 76; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateViewBobbing implements Packet { return 76; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateViewBobbing() { } diff --git a/src/com/hypixel/hytale/protocol/packets/assets/UpdateWeathers.java b/src/com/hypixel/hytale/protocol/packets/assets/UpdateWeathers.java index 15c840a0..dd3cbbd3 100644 --- a/src/com/hypixel/hytale/protocol/packets/assets/UpdateWeathers.java +++ b/src/com/hypixel/hytale/protocol/packets/assets/UpdateWeathers.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.assets; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.Weather; import com.hypixel.hytale.protocol.io.ProtocolException; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateWeathers implements Packet { +public class UpdateWeathers implements Packet, ToClientPacket { public static final int PACKET_ID = 47; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateWeathers implements Packet { return 47; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateWeathers() { } diff --git a/src/com/hypixel/hytale/protocol/packets/auth/AuthGrant.java b/src/com/hypixel/hytale/protocol/packets/auth/AuthGrant.java index 8b9228b2..caa34a8c 100644 --- a/src/com/hypixel/hytale/protocol/packets/auth/AuthGrant.java +++ b/src/com/hypixel/hytale/protocol/packets/auth/AuthGrant.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.auth; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AuthGrant implements Packet { +public class AuthGrant implements Packet, ToClientPacket { public static final int PACKET_ID = 11; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class AuthGrant implements Packet { return 11; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AuthGrant() { } diff --git a/src/com/hypixel/hytale/protocol/packets/auth/AuthToken.java b/src/com/hypixel/hytale/protocol/packets/auth/AuthToken.java index 2aa925e8..d9d9ad1a 100644 --- a/src/com/hypixel/hytale/protocol/packets/auth/AuthToken.java +++ b/src/com/hypixel/hytale/protocol/packets/auth/AuthToken.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.auth; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AuthToken implements Packet { +public class AuthToken implements Packet, ToServerPacket { public static final int PACKET_ID = 12; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class AuthToken implements Packet { return 12; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AuthToken() { } diff --git a/src/com/hypixel/hytale/protocol/packets/auth/ClientReferral.java b/src/com/hypixel/hytale/protocol/packets/auth/ClientReferral.java index 6d8dbe93..a9ec6a1f 100644 --- a/src/com/hypixel/hytale/protocol/packets/auth/ClientReferral.java +++ b/src/com/hypixel/hytale/protocol/packets/auth/ClientReferral.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.auth; import com.hypixel.hytale.protocol.HostAddress; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ClientReferral implements Packet { +public class ClientReferral implements Packet, ToClientPacket { public static final int PACKET_ID = 18; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class ClientReferral implements Packet { return 18; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ClientReferral() { } diff --git a/src/com/hypixel/hytale/protocol/packets/auth/ConnectAccept.java b/src/com/hypixel/hytale/protocol/packets/auth/ConnectAccept.java index 15bd0803..1f91d700 100644 --- a/src/com/hypixel/hytale/protocol/packets/auth/ConnectAccept.java +++ b/src/com/hypixel/hytale/protocol/packets/auth/ConnectAccept.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.auth; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ConnectAccept implements Packet { +public class ConnectAccept implements Packet, ToClientPacket { public static final int PACKET_ID = 14; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class ConnectAccept implements Packet { return 14; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ConnectAccept() { } diff --git a/src/com/hypixel/hytale/protocol/packets/auth/PasswordAccepted.java b/src/com/hypixel/hytale/protocol/packets/auth/PasswordAccepted.java index e7acda8c..ee6e8341 100644 --- a/src/com/hypixel/hytale/protocol/packets/auth/PasswordAccepted.java +++ b/src/com/hypixel/hytale/protocol/packets/auth/PasswordAccepted.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.auth; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class PasswordAccepted implements Packet { +public class PasswordAccepted implements Packet, ToClientPacket { public static final int PACKET_ID = 16; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class PasswordAccepted implements Packet { return 16; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static PasswordAccepted deserialize(@Nonnull ByteBuf buf, int offset) { return new PasswordAccepted(); diff --git a/src/com/hypixel/hytale/protocol/packets/auth/PasswordRejected.java b/src/com/hypixel/hytale/protocol/packets/auth/PasswordRejected.java index 5708348f..86cb4856 100644 --- a/src/com/hypixel/hytale/protocol/packets/auth/PasswordRejected.java +++ b/src/com/hypixel/hytale/protocol/packets/auth/PasswordRejected.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.auth; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class PasswordRejected implements Packet { +public class PasswordRejected implements Packet, ToClientPacket { public static final int PACKET_ID = 17; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class PasswordRejected implements Packet { return 17; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public PasswordRejected() { } diff --git a/src/com/hypixel/hytale/protocol/packets/auth/PasswordResponse.java b/src/com/hypixel/hytale/protocol/packets/auth/PasswordResponse.java index 571e89be..2b8b3ef0 100644 --- a/src/com/hypixel/hytale/protocol/packets/auth/PasswordResponse.java +++ b/src/com/hypixel/hytale/protocol/packets/auth/PasswordResponse.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.auth; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class PasswordResponse implements Packet { +public class PasswordResponse implements Packet, ToServerPacket { public static final int PACKET_ID = 15; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class PasswordResponse implements Packet { return 15; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public PasswordResponse() { } diff --git a/src/com/hypixel/hytale/protocol/packets/auth/ServerAuthToken.java b/src/com/hypixel/hytale/protocol/packets/auth/ServerAuthToken.java index 46870392..4e5e5ae2 100644 --- a/src/com/hypixel/hytale/protocol/packets/auth/ServerAuthToken.java +++ b/src/com/hypixel/hytale/protocol/packets/auth/ServerAuthToken.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.auth; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ServerAuthToken implements Packet { +public class ServerAuthToken implements Packet, ToClientPacket { public static final int PACKET_ID = 13; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class ServerAuthToken implements Packet { return 13; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ServerAuthToken() { } diff --git a/src/com/hypixel/hytale/protocol/packets/auth/Status.java b/src/com/hypixel/hytale/protocol/packets/auth/Status.java deleted file mode 100644 index 96700e1d..00000000 --- a/src/com/hypixel/hytale/protocol/packets/auth/Status.java +++ /dev/null @@ -1,252 +0,0 @@ -package com.hypixel.hytale.protocol.packets.auth; - -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 Status implements Packet { - public static final int PACKET_ID = 10; - public static final boolean IS_COMPRESSED = false; - 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 = 2587; - @Nullable - public String name; - @Nullable - public String motd; - public int playerCount; - public int maxPlayers; - - @Override - public int getId() { - return 10; - } - - public Status() { - } - - public Status(@Nullable String name, @Nullable String motd, int playerCount, int maxPlayers) { - this.name = name; - this.motd = motd; - this.playerCount = playerCount; - this.maxPlayers = maxPlayers; - } - - public Status(@Nonnull Status other) { - this.name = other.name; - this.motd = other.motd; - this.playerCount = other.playerCount; - this.maxPlayers = other.maxPlayers; - } - - @Nonnull - public static Status deserialize(@Nonnull ByteBuf buf, int offset) { - Status obj = new Status(); - byte nullBits = buf.getByte(offset); - obj.playerCount = buf.getIntLE(offset + 1); - obj.maxPlayers = buf.getIntLE(offset + 5); - if ((nullBits & 1) != 0) { - int varPos0 = offset + 17 + buf.getIntLE(offset + 9); - int nameLen = VarInt.peek(buf, varPos0); - if (nameLen < 0) { - throw ProtocolException.negativeLength("Name", nameLen); - } - - if (nameLen > 128) { - throw ProtocolException.stringTooLong("Name", nameLen, 128); - } - - obj.name = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); - } - - if ((nullBits & 2) != 0) { - int varPos1 = offset + 17 + buf.getIntLE(offset + 13); - int motdLen = VarInt.peek(buf, varPos1); - if (motdLen < 0) { - throw ProtocolException.negativeLength("Motd", motdLen); - } - - if (motdLen > 512) { - throw ProtocolException.stringTooLong("Motd", motdLen, 512); - } - - obj.motd = 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 void serialize(@Nonnull ByteBuf buf) { - int startPos = buf.writerIndex(); - byte nullBits = 0; - if (this.name != null) { - nullBits = (byte)(nullBits | 1); - } - - if (this.motd != null) { - nullBits = (byte)(nullBits | 2); - } - - buf.writeByte(nullBits); - buf.writeIntLE(this.playerCount); - buf.writeIntLE(this.maxPlayers); - int nameOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int motdOffsetSlot = buf.writerIndex(); - buf.writeIntLE(0); - int varBlockStart = buf.writerIndex(); - if (this.name != null) { - buf.setIntLE(nameOffsetSlot, buf.writerIndex() - varBlockStart); - PacketIO.writeVarString(buf, this.name, 128); - } else { - buf.setIntLE(nameOffsetSlot, -1); - } - - if (this.motd != null) { - buf.setIntLE(motdOffsetSlot, buf.writerIndex() - varBlockStart); - PacketIO.writeVarString(buf, this.motd, 512); - } else { - buf.setIntLE(motdOffsetSlot, -1); - } - } - - @Override - public int computeSize() { - int size = 17; - if (this.name != null) { - size += PacketIO.stringSize(this.name); - } - - if (this.motd != null) { - size += PacketIO.stringSize(this.motd); - } - - 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 nameOffset = buffer.getIntLE(offset + 9); - if (nameOffset < 0) { - return ValidationResult.error("Invalid offset for Name"); - } - - int pos = offset + 17 + 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 > 128) { - return ValidationResult.error("Name exceeds max length 128"); - } - - pos += VarInt.length(buffer, pos); - pos += nameLen; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Name"); - } - } - - if ((nullBits & 2) != 0) { - int motdOffset = buffer.getIntLE(offset + 13); - if (motdOffset < 0) { - return ValidationResult.error("Invalid offset for Motd"); - } - - int posx = offset + 17 + motdOffset; - if (posx >= buffer.writerIndex()) { - return ValidationResult.error("Offset out of bounds for Motd"); - } - - int motdLen = VarInt.peek(buffer, posx); - if (motdLen < 0) { - return ValidationResult.error("Invalid string length for Motd"); - } - - if (motdLen > 512) { - return ValidationResult.error("Motd exceeds max length 512"); - } - - posx += VarInt.length(buffer, posx); - posx += motdLen; - if (posx > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading Motd"); - } - } - - return ValidationResult.OK; - } - } - - public Status clone() { - Status copy = new Status(); - copy.name = this.name; - copy.motd = this.motd; - copy.playerCount = this.playerCount; - copy.maxPlayers = this.maxPlayers; - return copy; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } else { - return !(obj instanceof Status other) - ? false - : Objects.equals(this.name, other.name) - && Objects.equals(this.motd, other.motd) - && this.playerCount == other.playerCount - && this.maxPlayers == other.maxPlayers; - } - } - - @Override - public int hashCode() { - return Objects.hash(this.name, this.motd, this.playerCount, this.maxPlayers); - } -} diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolArgUpdate.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolArgUpdate.java index 8626a2bd..c59ace76 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolArgUpdate.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolArgUpdate.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class BuilderToolArgUpdate implements Packet { +public class BuilderToolArgUpdate implements Packet, ToServerPacket { public static final int PACKET_ID = 400; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class BuilderToolArgUpdate implements Packet { return 400; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolArgUpdate() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolEntityAction.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolEntityAction.java index 6c228725..85cfc6f3 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolEntityAction.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolEntityAction.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolEntityAction implements Packet { +public class BuilderToolEntityAction implements Packet, ToServerPacket { public static final int PACKET_ID = 401; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class BuilderToolEntityAction implements Packet { return 401; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolEntityAction() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolExtrudeAction.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolExtrudeAction.java index 86ad924d..e144185f 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolExtrudeAction.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolExtrudeAction.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolExtrudeAction implements Packet { +public class BuilderToolExtrudeAction implements Packet, ToServerPacket { public static final int PACKET_ID = 403; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +28,11 @@ public class BuilderToolExtrudeAction implements Packet { return 403; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolExtrudeAction() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolGeneralAction.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolGeneralAction.java index 28016872..b8391b95 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolGeneralAction.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolGeneralAction.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolGeneralAction implements Packet { +public class BuilderToolGeneralAction implements Packet, ToServerPacket { public static final int PACKET_ID = 412; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class BuilderToolGeneralAction implements Packet { return 412; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolGeneralAction() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolHideAnchors.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolHideAnchors.java index bd367b47..a5204230 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolHideAnchors.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolHideAnchors.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class BuilderToolHideAnchors implements Packet { +public class BuilderToolHideAnchors implements Packet, ToClientPacket { public static final int PACKET_ID = 416; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class BuilderToolHideAnchors implements Packet { return 416; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static BuilderToolHideAnchors deserialize(@Nonnull ByteBuf buf, int offset) { return new BuilderToolHideAnchors(); diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolLaserPointer.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolLaserPointer.java index e504f602..d9b16025 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolLaserPointer.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolLaserPointer.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolLaserPointer implements Packet { +public class BuilderToolLaserPointer implements Packet, ToClientPacket { public static final int PACKET_ID = 419; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -29,6 +31,11 @@ public class BuilderToolLaserPointer implements Packet { return 419; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolLaserPointer() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolLineAction.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolLineAction.java index a551534e..4469fb57 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolLineAction.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolLineAction.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolLineAction implements Packet { +public class BuilderToolLineAction implements Packet, ToServerPacket { public static final int PACKET_ID = 414; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +28,11 @@ public class BuilderToolLineAction implements Packet { return 414; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolLineAction() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolOnUseInteraction.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolOnUseInteraction.java index 65dca523..9262fdfa 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolOnUseInteraction.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolOnUseInteraction.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.buildertools; import com.hypixel.hytale.protocol.InteractionType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolOnUseInteraction implements Packet { +public class BuilderToolOnUseInteraction implements Packet, ToServerPacket { public static final int PACKET_ID = 413; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -40,6 +42,11 @@ public class BuilderToolOnUseInteraction implements Packet { return 413; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolOnUseInteraction() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolPasteClipboard.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolPasteClipboard.java index c9f4c6c5..19e06cf8 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolPasteClipboard.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolPasteClipboard.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolPasteClipboard implements Packet { +public class BuilderToolPasteClipboard implements Packet, ToServerPacket { public static final int PACKET_ID = 407; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class BuilderToolPasteClipboard implements Packet { return 407; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolPasteClipboard() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolRotateClipboard.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolRotateClipboard.java index c818e40b..21027121 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolRotateClipboard.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolRotateClipboard.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolRotateClipboard implements Packet { +public class BuilderToolRotateClipboard implements Packet, ToServerPacket { public static final int PACKET_ID = 406; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class BuilderToolRotateClipboard implements Packet { return 406; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolRotateClipboard() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionToolAskForClipboard.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionToolAskForClipboard.java index f5e139db..411e5e42 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionToolAskForClipboard.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionToolAskForClipboard.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class BuilderToolSelectionToolAskForClipboard implements Packet { +public class BuilderToolSelectionToolAskForClipboard implements Packet, ToServerPacket { public static final int PACKET_ID = 410; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class BuilderToolSelectionToolAskForClipboard implements Packet { return 410; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static BuilderToolSelectionToolAskForClipboard deserialize(@Nonnull ByteBuf buf, int offset) { return new BuilderToolSelectionToolAskForClipboard(); diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionToolReplyWithClipboard.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionToolReplyWithClipboard.java index 571d4f45..8749a812 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionToolReplyWithClipboard.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionToolReplyWithClipboard.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -11,7 +13,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class BuilderToolSelectionToolReplyWithClipboard implements Packet { +public class BuilderToolSelectionToolReplyWithClipboard implements Packet, ToClientPacket { public static final int PACKET_ID = 411; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class BuilderToolSelectionToolReplyWithClipboard implements Packet { return 411; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSelectionToolReplyWithClipboard() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionTransform.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionTransform.java index 4df45c44..d9705638 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionTransform.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionTransform.java @@ -1,27 +1,29 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.math.Quatf; import com.hypixel.hytale.protocol.BlockPosition; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.Vector3f; -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.Arrays; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class BuilderToolSelectionTransform implements Packet { +public class BuilderToolSelectionTransform implements Packet, ToServerPacket { public static final int PACKET_ID = 405; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; - public static final int FIXED_BLOCK_SIZE = 52; - public static final int VARIABLE_FIELD_COUNT = 1; - public static final int VARIABLE_BLOCK_START = 52; - public static final int MAX_SIZE = 16384057; + public static final int FIXED_BLOCK_SIZE = 80; + public static final int VARIABLE_FIELD_COUNT = 0; + public static final int VARIABLE_BLOCK_START = 80; + public static final int MAX_SIZE = 80; @Nullable - public float[] transformationMatrix; + public Quatf rotation; + @Nullable + public BlockPosition translationOffset; @Nullable public BlockPosition initialSelectionMin; @Nullable @@ -39,11 +41,17 @@ public class BuilderToolSelectionTransform implements Packet { return 405; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSelectionTransform() { } public BuilderToolSelectionTransform( - @Nullable float[] transformationMatrix, + @Nullable Quatf rotation, + @Nullable BlockPosition translationOffset, @Nullable BlockPosition initialSelectionMin, @Nullable BlockPosition initialSelectionMax, @Nullable Vector3f initialRotationOrigin, @@ -52,7 +60,8 @@ public class BuilderToolSelectionTransform implements Packet { boolean isExitingTransformMode, @Nullable BlockPosition initialPastePointForClipboardPaste ) { - this.transformationMatrix = transformationMatrix; + this.rotation = rotation; + this.translationOffset = translationOffset; this.initialSelectionMin = initialSelectionMin; this.initialSelectionMax = initialSelectionMax; this.initialRotationOrigin = initialRotationOrigin; @@ -63,7 +72,8 @@ public class BuilderToolSelectionTransform implements Packet { } public BuilderToolSelectionTransform(@Nonnull BuilderToolSelectionTransform other) { - this.transformationMatrix = other.transformationMatrix; + this.rotation = other.rotation; + this.translationOffset = other.translationOffset; this.initialSelectionMin = other.initialSelectionMin; this.initialSelectionMax = other.initialSelectionMax; this.initialRotationOrigin = other.initialRotationOrigin; @@ -78,90 +88,79 @@ public class BuilderToolSelectionTransform implements Packet { BuilderToolSelectionTransform obj = new BuilderToolSelectionTransform(); byte nullBits = buf.getByte(offset); if ((nullBits & 1) != 0) { - obj.initialSelectionMin = BlockPosition.deserialize(buf, offset + 1); + obj.rotation = Quatf.deserialize(buf, offset + 1); } if ((nullBits & 2) != 0) { - obj.initialSelectionMax = BlockPosition.deserialize(buf, offset + 13); + obj.translationOffset = BlockPosition.deserialize(buf, offset + 17); } if ((nullBits & 4) != 0) { - obj.initialRotationOrigin = Vector3f.deserialize(buf, offset + 25); + obj.initialSelectionMin = BlockPosition.deserialize(buf, offset + 29); } - obj.cutOriginal = buf.getByte(offset + 37) != 0; - obj.applyTransformationToSelectionMinMax = buf.getByte(offset + 38) != 0; - obj.isExitingTransformMode = buf.getByte(offset + 39) != 0; if ((nullBits & 8) != 0) { - obj.initialPastePointForClipboardPaste = BlockPosition.deserialize(buf, offset + 40); + obj.initialSelectionMax = BlockPosition.deserialize(buf, offset + 41); } - int pos = offset + 52; if ((nullBits & 16) != 0) { - int transformationMatrixCount = VarInt.peek(buf, pos); - if (transformationMatrixCount < 0) { - throw ProtocolException.negativeLength("TransformationMatrix", transformationMatrixCount); - } + obj.initialRotationOrigin = Vector3f.deserialize(buf, offset + 53); + } - if (transformationMatrixCount > 4096000) { - throw ProtocolException.arrayTooLong("TransformationMatrix", transformationMatrixCount, 4096000); - } - - int transformationMatrixVarLen = VarInt.size(transformationMatrixCount); - if (pos + transformationMatrixVarLen + transformationMatrixCount * 4L > buf.readableBytes()) { - throw ProtocolException.bufferTooSmall( - "TransformationMatrix", pos + transformationMatrixVarLen + transformationMatrixCount * 4, buf.readableBytes() - ); - } - - pos += transformationMatrixVarLen; - obj.transformationMatrix = new float[transformationMatrixCount]; - - for (int i = 0; i < transformationMatrixCount; i++) { - obj.transformationMatrix[i] = buf.getFloatLE(pos + i * 4); - } - - pos += transformationMatrixCount * 4; + obj.cutOriginal = buf.getByte(offset + 65) != 0; + obj.applyTransformationToSelectionMinMax = buf.getByte(offset + 66) != 0; + obj.isExitingTransformMode = buf.getByte(offset + 67) != 0; + if ((nullBits & 32) != 0) { + obj.initialPastePointForClipboardPaste = BlockPosition.deserialize(buf, offset + 68); } return obj; } public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { - byte nullBits = buf.getByte(offset); - int pos = offset + 52; - if ((nullBits & 16) != 0) { - int arrLen = VarInt.peek(buf, pos); - pos += VarInt.length(buf, pos) + arrLen * 4; - } - - return pos - offset; + return 80; } @Override public void serialize(@Nonnull ByteBuf buf) { byte nullBits = 0; - if (this.initialSelectionMin != null) { + if (this.rotation != null) { nullBits = (byte)(nullBits | 1); } - if (this.initialSelectionMax != null) { + if (this.translationOffset != null) { nullBits = (byte)(nullBits | 2); } - if (this.initialRotationOrigin != null) { + if (this.initialSelectionMin != null) { nullBits = (byte)(nullBits | 4); } - if (this.initialPastePointForClipboardPaste != null) { + if (this.initialSelectionMax != null) { nullBits = (byte)(nullBits | 8); } - if (this.transformationMatrix != null) { + if (this.initialRotationOrigin != null) { nullBits = (byte)(nullBits | 16); } + if (this.initialPastePointForClipboardPaste != null) { + nullBits = (byte)(nullBits | 32); + } + buf.writeByte(nullBits); + if (this.rotation != null) { + this.rotation.serialize(buf); + } else { + buf.writeZero(16); + } + + if (this.translationOffset != null) { + this.translationOffset.serialize(buf); + } else { + buf.writeZero(12); + } + if (this.initialSelectionMin != null) { this.initialSelectionMin.serialize(buf); } else { @@ -188,60 +187,21 @@ public class BuilderToolSelectionTransform implements Packet { } else { buf.writeZero(12); } - - if (this.transformationMatrix != null) { - if (this.transformationMatrix.length > 4096000) { - throw ProtocolException.arrayTooLong("TransformationMatrix", this.transformationMatrix.length, 4096000); - } - - VarInt.write(buf, this.transformationMatrix.length); - - for (float item : this.transformationMatrix) { - buf.writeFloatLE(item); - } - } } @Override public int computeSize() { - int size = 52; - if (this.transformationMatrix != null) { - size += VarInt.size(this.transformationMatrix.length) + this.transformationMatrix.length * 4; - } - - return size; + return 80; } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 52) { - return ValidationResult.error("Buffer too small: expected at least 52 bytes"); - } else { - byte nullBits = buffer.getByte(offset); - int pos = offset + 52; - if ((nullBits & 16) != 0) { - int transformationMatrixCount = VarInt.peek(buffer, pos); - if (transformationMatrixCount < 0) { - return ValidationResult.error("Invalid array count for TransformationMatrix"); - } - - if (transformationMatrixCount > 4096000) { - return ValidationResult.error("TransformationMatrix exceeds max length 4096000"); - } - - pos += VarInt.length(buffer, pos); - pos += transformationMatrixCount * 4; - if (pos > buffer.writerIndex()) { - return ValidationResult.error("Buffer overflow reading TransformationMatrix"); - } - } - - return ValidationResult.OK; - } + return buffer.readableBytes() - offset < 80 ? ValidationResult.error("Buffer too small: expected at least 80 bytes") : ValidationResult.OK; } public BuilderToolSelectionTransform clone() { BuilderToolSelectionTransform copy = new BuilderToolSelectionTransform(); - copy.transformationMatrix = this.transformationMatrix != null ? Arrays.copyOf(this.transformationMatrix, this.transformationMatrix.length) : null; + copy.rotation = this.rotation; + copy.translationOffset = this.translationOffset != null ? this.translationOffset.clone() : null; copy.initialSelectionMin = this.initialSelectionMin != null ? this.initialSelectionMin.clone() : null; copy.initialSelectionMax = this.initialSelectionMax != null ? this.initialSelectionMax.clone() : null; copy.initialRotationOrigin = this.initialRotationOrigin != null ? this.initialRotationOrigin.clone() : null; @@ -259,7 +219,8 @@ public class BuilderToolSelectionTransform implements Packet { } else { return !(obj instanceof BuilderToolSelectionTransform other) ? false - : Arrays.equals(this.transformationMatrix, other.transformationMatrix) + : Objects.equals(this.rotation, other.rotation) + && Objects.equals(this.translationOffset, other.translationOffset) && Objects.equals(this.initialSelectionMin, other.initialSelectionMin) && Objects.equals(this.initialSelectionMax, other.initialSelectionMax) && Objects.equals(this.initialRotationOrigin, other.initialRotationOrigin) @@ -272,14 +233,16 @@ public class BuilderToolSelectionTransform implements Packet { @Override public int hashCode() { - int result = 1; - result = 31 * result + Arrays.hashCode(this.transformationMatrix); - result = 31 * result + Objects.hashCode(this.initialSelectionMin); - result = 31 * result + Objects.hashCode(this.initialSelectionMax); - result = 31 * result + Objects.hashCode(this.initialRotationOrigin); - result = 31 * result + Boolean.hashCode(this.cutOriginal); - result = 31 * result + Boolean.hashCode(this.applyTransformationToSelectionMinMax); - result = 31 * result + Boolean.hashCode(this.isExitingTransformMode); - return 31 * result + Objects.hashCode(this.initialPastePointForClipboardPaste); + return Objects.hash( + this.rotation, + this.translationOffset, + this.initialSelectionMin, + this.initialSelectionMax, + this.initialRotationOrigin, + this.cutOriginal, + this.applyTransformationToSelectionMinMax, + this.isExitingTransformMode, + this.initialPastePointForClipboardPaste + ); } } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionUpdate.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionUpdate.java index c3b10d64..387210fd 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionUpdate.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSelectionUpdate.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolSelectionUpdate implements Packet { +public class BuilderToolSelectionUpdate implements Packet, ToServerPacket { public static final int PACKET_ID = 409; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +28,11 @@ public class BuilderToolSelectionUpdate implements Packet { return 409; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSelectionUpdate() { } 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..dafa9d82 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityCollision.java @@ -0,0 +1,158 @@ +package com.hypixel.hytale.protocol.packets.buildertools; + +import com.hypixel.hytale.protocol.NetworkChannel; +import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; +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, ToServerPacket { + 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; + } + + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + + 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/buildertools/BuilderToolSetEntityLight.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityLight.java index 92f1f444..abed5843 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityLight.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityLight.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.buildertools; import com.hypixel.hytale.protocol.ColorLight; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class BuilderToolSetEntityLight implements Packet { +public class BuilderToolSetEntityLight implements Packet, ToServerPacket { public static final int PACKET_ID = 422; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class BuilderToolSetEntityLight implements Packet { return 422; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSetEntityLight() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityPickupEnabled.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityPickupEnabled.java index a46d96b8..8138f39d 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityPickupEnabled.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityPickupEnabled.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolSetEntityPickupEnabled implements Packet { +public class BuilderToolSetEntityPickupEnabled implements Packet, ToServerPacket { public static final int PACKET_ID = 421; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class BuilderToolSetEntityPickupEnabled implements Packet { return 421; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSetEntityPickupEnabled() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityScale.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityScale.java index bd322545..b0239001 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityScale.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityScale.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolSetEntityScale implements Packet { +public class BuilderToolSetEntityScale implements Packet, ToServerPacket { public static final int PACKET_ID = 420; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class BuilderToolSetEntityScale implements Packet { return 420; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSetEntityScale() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityTransform.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityTransform.java index 0bd7e009..c3774a58 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityTransform.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetEntityTransform.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.buildertools; import com.hypixel.hytale.protocol.ModelTransform; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class BuilderToolSetEntityTransform implements Packet { +public class BuilderToolSetEntityTransform implements Packet, ToServerPacket { public static final int PACKET_ID = 402; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class BuilderToolSetEntityTransform implements Packet { return 402; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSetEntityTransform() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetNPCDebug.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetNPCDebug.java index f12ddcc9..b0000b28 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetNPCDebug.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetNPCDebug.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolSetNPCDebug implements Packet { +public class BuilderToolSetNPCDebug implements Packet, ToServerPacket { public static final int PACKET_ID = 423; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class BuilderToolSetNPCDebug implements Packet { return 423; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSetNPCDebug() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetTransformationModeState.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetTransformationModeState.java index b4265a10..eebc9038 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetTransformationModeState.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolSetTransformationModeState.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolSetTransformationModeState implements Packet { +public class BuilderToolSetTransformationModeState implements Packet, ToServerPacket { public static final int PACKET_ID = 408; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class BuilderToolSetTransformationModeState implements Packet { return 408; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolSetTransformationModeState() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolShowAnchor.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolShowAnchor.java index ea027aea..876413c1 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolShowAnchor.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolShowAnchor.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolShowAnchor implements Packet { +public class BuilderToolShowAnchor implements Packet, ToClientPacket { public static final int PACKET_ID = 415; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class BuilderToolShowAnchor implements Packet { return 415; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolShowAnchor() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolStackArea.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolStackArea.java index e4ca72bb..3d1ac5f6 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolStackArea.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolStackArea.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.buildertools; import com.hypixel.hytale.protocol.BlockPosition; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class BuilderToolStackArea implements Packet { +public class BuilderToolStackArea implements Packet, ToServerPacket { public static final int PACKET_ID = 404; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class BuilderToolStackArea implements Packet { return 404; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolStackArea() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolsSetSoundSet.java b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolsSetSoundSet.java index ebf515b2..b87ea4d6 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolsSetSoundSet.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/BuilderToolsSetSoundSet.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class BuilderToolsSetSoundSet implements Packet { +public class BuilderToolsSetSoundSet implements Packet, ToClientPacket { public static final int PACKET_ID = 418; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class BuilderToolsSetSoundSet implements Packet { return 418; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public BuilderToolsSetSoundSet() { } diff --git a/src/com/hypixel/hytale/protocol/packets/buildertools/PrefabUnselectPrefab.java b/src/com/hypixel/hytale/protocol/packets/buildertools/PrefabUnselectPrefab.java index c1393462..b5656ff2 100644 --- a/src/com/hypixel/hytale/protocol/packets/buildertools/PrefabUnselectPrefab.java +++ b/src/com/hypixel/hytale/protocol/packets/buildertools/PrefabUnselectPrefab.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.buildertools; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class PrefabUnselectPrefab implements Packet { +public class PrefabUnselectPrefab implements Packet, ToServerPacket { public static final int PACKET_ID = 417; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class PrefabUnselectPrefab implements Packet { return 417; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static PrefabUnselectPrefab deserialize(@Nonnull ByteBuf buf, int offset) { return new PrefabUnselectPrefab(); diff --git a/src/com/hypixel/hytale/protocol/packets/camera/CameraShakeEffect.java b/src/com/hypixel/hytale/protocol/packets/camera/CameraShakeEffect.java index 8199620e..1342cb2b 100644 --- a/src/com/hypixel/hytale/protocol/packets/camera/CameraShakeEffect.java +++ b/src/com/hypixel/hytale/protocol/packets/camera/CameraShakeEffect.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.camera; import com.hypixel.hytale.protocol.AccumulationMode; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class CameraShakeEffect implements Packet { +public class CameraShakeEffect implements Packet, ToClientPacket { public static final int PACKET_ID = 281; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -25,6 +27,11 @@ public class CameraShakeEffect implements Packet { return 281; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public CameraShakeEffect() { } diff --git a/src/com/hypixel/hytale/protocol/packets/camera/RequestFlyCameraMode.java b/src/com/hypixel/hytale/protocol/packets/camera/RequestFlyCameraMode.java index 968428e8..910b82c3 100644 --- a/src/com/hypixel/hytale/protocol/packets/camera/RequestFlyCameraMode.java +++ b/src/com/hypixel/hytale/protocol/packets/camera/RequestFlyCameraMode.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.camera; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class RequestFlyCameraMode implements Packet { +public class RequestFlyCameraMode implements Packet, ToServerPacket { public static final int PACKET_ID = 282; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class RequestFlyCameraMode implements Packet { return 282; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public RequestFlyCameraMode() { } diff --git a/src/com/hypixel/hytale/protocol/packets/camera/SetFlyCameraMode.java b/src/com/hypixel/hytale/protocol/packets/camera/SetFlyCameraMode.java index 7ee7f4cf..625c6408 100644 --- a/src/com/hypixel/hytale/protocol/packets/camera/SetFlyCameraMode.java +++ b/src/com/hypixel/hytale/protocol/packets/camera/SetFlyCameraMode.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.camera; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetFlyCameraMode implements Packet { +public class SetFlyCameraMode implements Packet, ToClientPacket { public static final int PACKET_ID = 283; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class SetFlyCameraMode implements Packet { return 283; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetFlyCameraMode() { } diff --git a/src/com/hypixel/hytale/protocol/packets/camera/SetServerCamera.java b/src/com/hypixel/hytale/protocol/packets/camera/SetServerCamera.java index 19109ac8..92950eb2 100644 --- a/src/com/hypixel/hytale/protocol/packets/camera/SetServerCamera.java +++ b/src/com/hypixel/hytale/protocol/packets/camera/SetServerCamera.java @@ -1,15 +1,17 @@ package com.hypixel.hytale.protocol.packets.camera; import com.hypixel.hytale.protocol.ClientCameraView; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.ServerCameraSettings; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetServerCamera implements Packet { +public class SetServerCamera implements Packet, ToClientPacket { public static final int PACKET_ID = 280; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class SetServerCamera implements Packet { return 280; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetServerCamera() { } diff --git a/src/com/hypixel/hytale/protocol/packets/connection/Connect.java b/src/com/hypixel/hytale/protocol/packets/connection/Connect.java index c561beb9..276f6898 100644 --- a/src/com/hypixel/hytale/protocol/packets/connection/Connect.java +++ b/src/com/hypixel/hytale/protocol/packets/connection/Connect.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.connection; import com.hypixel.hytale.protocol.HostAddress; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -13,7 +15,7 @@ import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class Connect implements Packet { +public class Connect implements Packet, ToServerPacket { public static final int PACKET_ID = 0; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -45,6 +47,11 @@ public class Connect implements Packet { return 0; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public Connect() { } diff --git a/src/com/hypixel/hytale/protocol/packets/connection/Disconnect.java b/src/com/hypixel/hytale/protocol/packets/connection/Disconnect.java index ae099cdc..3b6c0afb 100644 --- a/src/com/hypixel/hytale/protocol/packets/connection/Disconnect.java +++ b/src/com/hypixel/hytale/protocol/packets/connection/Disconnect.java @@ -1,6 +1,9 @@ package com.hypixel.hytale.protocol.packets.connection; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class Disconnect implements Packet { +public class Disconnect implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 1; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +31,11 @@ public class Disconnect implements Packet { return 1; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public Disconnect() { } diff --git a/src/com/hypixel/hytale/protocol/packets/connection/Ping.java b/src/com/hypixel/hytale/protocol/packets/connection/Ping.java index 30dc2bb2..505dc750 100644 --- a/src/com/hypixel/hytale/protocol/packets/connection/Ping.java +++ b/src/com/hypixel/hytale/protocol/packets/connection/Ping.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.connection; import com.hypixel.hytale.protocol.InstantData; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class Ping implements Packet { +public class Ping implements Packet, ToClientPacket { public static final int PACKET_ID = 2; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class Ping implements Packet { return 2; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public Ping() { } diff --git a/src/com/hypixel/hytale/protocol/packets/connection/Pong.java b/src/com/hypixel/hytale/protocol/packets/connection/Pong.java index 5c4d0346..45d7882c 100644 --- a/src/com/hypixel/hytale/protocol/packets/connection/Pong.java +++ b/src/com/hypixel/hytale/protocol/packets/connection/Pong.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.connection; import com.hypixel.hytale.protocol.InstantData; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class Pong implements Packet { +public class Pong implements Packet, ToServerPacket { public static final int PACKET_ID = 3; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class Pong implements Packet { return 3; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public Pong() { } diff --git a/src/com/hypixel/hytale/protocol/packets/entities/ApplyKnockback.java b/src/com/hypixel/hytale/protocol/packets/entities/ApplyKnockback.java index fdc5a863..0527c651 100644 --- a/src/com/hypixel/hytale/protocol/packets/entities/ApplyKnockback.java +++ b/src/com/hypixel/hytale/protocol/packets/entities/ApplyKnockback.java @@ -1,15 +1,17 @@ package com.hypixel.hytale.protocol.packets.entities; import com.hypixel.hytale.protocol.ChangeVelocityType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.Position; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ApplyKnockback implements Packet { +public class ApplyKnockback implements Packet, ToClientPacket { public static final int PACKET_ID = 164; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class ApplyKnockback implements Packet { return 164; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ApplyKnockback() { } diff --git a/src/com/hypixel/hytale/protocol/packets/entities/ChangeVelocity.java b/src/com/hypixel/hytale/protocol/packets/entities/ChangeVelocity.java index cc0f2153..c315653c 100644 --- a/src/com/hypixel/hytale/protocol/packets/entities/ChangeVelocity.java +++ b/src/com/hypixel/hytale/protocol/packets/entities/ChangeVelocity.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.entities; import com.hypixel.hytale.protocol.ChangeVelocityType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.VelocityConfig; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; @@ -9,7 +11,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ChangeVelocity implements Packet { +public class ChangeVelocity implements Packet, ToClientPacket { public static final int PACKET_ID = 163; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class ChangeVelocity implements Packet { return 163; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ChangeVelocity() { } diff --git a/src/com/hypixel/hytale/protocol/packets/entities/EntityUpdates.java b/src/com/hypixel/hytale/protocol/packets/entities/EntityUpdates.java index 40052435..1d9d42cc 100644 --- a/src/com/hypixel/hytale/protocol/packets/entities/EntityUpdates.java +++ b/src/com/hypixel/hytale/protocol/packets/entities/EntityUpdates.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.entities; import com.hypixel.hytale.protocol.EntityUpdate; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -10,7 +12,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class EntityUpdates implements Packet { +public class EntityUpdates implements Packet, ToClientPacket { public static final int PACKET_ID = 161; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class EntityUpdates implements Packet { return 161; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public EntityUpdates() { } diff --git a/src/com/hypixel/hytale/protocol/packets/entities/MountMovement.java b/src/com/hypixel/hytale/protocol/packets/entities/MountMovement.java index 40d1179f..3a2ce771 100644 --- a/src/com/hypixel/hytale/protocol/packets/entities/MountMovement.java +++ b/src/com/hypixel/hytale/protocol/packets/entities/MountMovement.java @@ -2,15 +2,17 @@ package com.hypixel.hytale.protocol.packets.entities; import com.hypixel.hytale.protocol.Direction; import com.hypixel.hytale.protocol.MovementStates; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.Position; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class MountMovement implements Packet { +public class MountMovement implements Packet, ToServerPacket { public static final int PACKET_ID = 166; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class MountMovement implements Packet { return 166; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public MountMovement() { } diff --git a/src/com/hypixel/hytale/protocol/packets/entities/PlayAnimation.java b/src/com/hypixel/hytale/protocol/packets/entities/PlayAnimation.java index 48cbe7a6..ed23390c 100644 --- a/src/com/hypixel/hytale/protocol/packets/entities/PlayAnimation.java +++ b/src/com/hypixel/hytale/protocol/packets/entities/PlayAnimation.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.entities; import com.hypixel.hytale.protocol.AnimationSlot; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class PlayAnimation implements Packet { +public class PlayAnimation implements Packet, ToClientPacket { public static final int PACKET_ID = 162; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -32,6 +34,11 @@ public class PlayAnimation implements Packet { return 162; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public PlayAnimation() { } diff --git a/src/com/hypixel/hytale/protocol/packets/entities/SetEntitySeed.java b/src/com/hypixel/hytale/protocol/packets/entities/SetEntitySeed.java index db75f198..02b93b96 100644 --- a/src/com/hypixel/hytale/protocol/packets/entities/SetEntitySeed.java +++ b/src/com/hypixel/hytale/protocol/packets/entities/SetEntitySeed.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.entities; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetEntitySeed implements Packet { +public class SetEntitySeed implements Packet, ToClientPacket { public static final int PACKET_ID = 160; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class SetEntitySeed implements Packet { return 160; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetEntitySeed() { } diff --git a/src/com/hypixel/hytale/protocol/packets/entities/SpawnModelParticles.java b/src/com/hypixel/hytale/protocol/packets/entities/SpawnModelParticles.java index 5a3bb048..5e60745c 100644 --- a/src/com/hypixel/hytale/protocol/packets/entities/SpawnModelParticles.java +++ b/src/com/hypixel/hytale/protocol/packets/entities/SpawnModelParticles.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.entities; import com.hypixel.hytale.protocol.ModelParticle; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -10,7 +12,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SpawnModelParticles implements Packet { +public class SpawnModelParticles implements Packet, ToClientPacket { public static final int PACKET_ID = 165; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class SpawnModelParticles implements Packet { return 165; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SpawnModelParticles() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interaction/CancelInteractionChain.java b/src/com/hypixel/hytale/protocol/packets/interaction/CancelInteractionChain.java index c5ab78e4..e1755121 100644 --- a/src/com/hypixel/hytale/protocol/packets/interaction/CancelInteractionChain.java +++ b/src/com/hypixel/hytale/protocol/packets/interaction/CancelInteractionChain.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.interaction; import com.hypixel.hytale.protocol.ForkedChainId; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class CancelInteractionChain implements Packet { +public class CancelInteractionChain implements Packet, ToClientPacket { public static final int PACKET_ID = 291; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class CancelInteractionChain implements Packet { return 291; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public CancelInteractionChain() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interaction/DismountNPC.java b/src/com/hypixel/hytale/protocol/packets/interaction/DismountNPC.java index eafb20d2..ebc5c5ed 100644 --- a/src/com/hypixel/hytale/protocol/packets/interaction/DismountNPC.java +++ b/src/com/hypixel/hytale/protocol/packets/interaction/DismountNPC.java @@ -1,11 +1,14 @@ package com.hypixel.hytale.protocol.packets.interaction; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class DismountNPC implements Packet { +public class DismountNPC implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 294; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +22,11 @@ public class DismountNPC implements Packet { return 294; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static DismountNPC deserialize(@Nonnull ByteBuf buf, int offset) { return new DismountNPC(); diff --git a/src/com/hypixel/hytale/protocol/packets/interaction/MountNPC.java b/src/com/hypixel/hytale/protocol/packets/interaction/MountNPC.java index 004b4e2e..9e0f9cd7 100644 --- a/src/com/hypixel/hytale/protocol/packets/interaction/MountNPC.java +++ b/src/com/hypixel/hytale/protocol/packets/interaction/MountNPC.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.interaction; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class MountNPC implements Packet { +public class MountNPC implements Packet, ToClientPacket { public static final int PACKET_ID = 293; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -24,6 +26,11 @@ public class MountNPC implements Packet { return 293; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public MountNPC() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interaction/PlayInteractionFor.java b/src/com/hypixel/hytale/protocol/packets/interaction/PlayInteractionFor.java index d2b56767..43bd467e 100644 --- a/src/com/hypixel/hytale/protocol/packets/interaction/PlayInteractionFor.java +++ b/src/com/hypixel/hytale/protocol/packets/interaction/PlayInteractionFor.java @@ -2,7 +2,9 @@ package com.hypixel.hytale.protocol.packets.interaction; import com.hypixel.hytale.protocol.ForkedChainId; import com.hypixel.hytale.protocol.InteractionType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -12,7 +14,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class PlayInteractionFor implements Packet { +public class PlayInteractionFor implements Packet, ToClientPacket { public static final int PACKET_ID = 292; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -37,6 +39,11 @@ public class PlayInteractionFor implements Packet { return 292; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public PlayInteractionFor() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interaction/SyncInteractionChains.java b/src/com/hypixel/hytale/protocol/packets/interaction/SyncInteractionChains.java index 67b632f9..55fe6b04 100644 --- a/src/com/hypixel/hytale/protocol/packets/interaction/SyncInteractionChains.java +++ b/src/com/hypixel/hytale/protocol/packets/interaction/SyncInteractionChains.java @@ -1,6 +1,9 @@ package com.hypixel.hytale.protocol.packets.interaction; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -8,7 +11,7 @@ import io.netty.buffer.ByteBuf; import java.util.Arrays; import javax.annotation.Nonnull; -public class SyncInteractionChains implements Packet { +public class SyncInteractionChains implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 290; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -24,6 +27,11 @@ public class SyncInteractionChains implements Packet { return 290; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SyncInteractionChains() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/AddToServerPlayerList.java b/src/com/hypixel/hytale/protocol/packets/interface_/AddToServerPlayerList.java index c4fae670..a9dd955c 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/AddToServerPlayerList.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/AddToServerPlayerList.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AddToServerPlayerList implements Packet { +public class AddToServerPlayerList implements Packet, ToClientPacket { public static final int PACKET_ID = 224; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AddToServerPlayerList implements Packet { return 224; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AddToServerPlayerList() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/ChatMessage.java b/src/com/hypixel/hytale/protocol/packets/interface_/ChatMessage.java index 909bf120..be1142bd 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/ChatMessage.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/ChatMessage.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ChatMessage implements Packet { +public class ChatMessage implements Packet, ToServerPacket { public static final int PACKET_ID = 211; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class ChatMessage implements Packet { return 211; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ChatMessage() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/CustomHud.java b/src/com/hypixel/hytale/protocol/packets/interface_/CustomHud.java index dca66ddb..1543da81 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/CustomHud.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/CustomHud.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class CustomHud implements Packet { +public class CustomHud implements Packet, ToClientPacket { public static final int PACKET_ID = 217; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class CustomHud implements Packet { return 217; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public CustomHud() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/CustomPage.java b/src/com/hypixel/hytale/protocol/packets/interface_/CustomPage.java index a237093f..c64e1af4 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/CustomPage.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/CustomPage.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class CustomPage implements Packet { +public class CustomPage implements Packet, ToClientPacket { public static final int PACKET_ID = 218; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -35,6 +37,11 @@ public class CustomPage implements Packet { return 218; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public CustomPage() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/CustomPageEvent.java b/src/com/hypixel/hytale/protocol/packets/interface_/CustomPageEvent.java index 2496534c..4ac2ee99 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/CustomPageEvent.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/CustomPageEvent.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class CustomPageEvent implements Packet { +public class CustomPageEvent implements Packet, ToServerPacket { public static final int PACKET_ID = 219; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class CustomPageEvent implements Packet { return 219; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public CustomPageEvent() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/EditorBlocksChange.java b/src/com/hypixel/hytale/protocol/packets/interface_/EditorBlocksChange.java index a94f38fd..780e99d0 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/EditorBlocksChange.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/EditorBlocksChange.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class EditorBlocksChange implements Packet { +public class EditorBlocksChange implements Packet, ToClientPacket { public static final int PACKET_ID = 222; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -32,6 +34,11 @@ public class EditorBlocksChange implements Packet { return 222; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public EditorBlocksChange() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/HideEventTitle.java b/src/com/hypixel/hytale/protocol/packets/interface_/HideEventTitle.java index 79105a7d..38e3b433 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/HideEventTitle.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/HideEventTitle.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class HideEventTitle implements Packet { +public class HideEventTitle implements Packet, ToClientPacket { public static final int PACKET_ID = 215; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class HideEventTitle implements Packet { return 215; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public HideEventTitle() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/KillFeedMessage.java b/src/com/hypixel/hytale/protocol/packets/interface_/KillFeedMessage.java index 2a7ca9cf..ab17bfca 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/KillFeedMessage.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/KillFeedMessage.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.interface_; import com.hypixel.hytale.protocol.FormattedMessage; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class KillFeedMessage implements Packet { +public class KillFeedMessage implements Packet, ToClientPacket { public static final int PACKET_ID = 213; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -31,6 +33,11 @@ public class KillFeedMessage implements Packet { return 213; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public KillFeedMessage() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/Notification.java b/src/com/hypixel/hytale/protocol/packets/interface_/Notification.java index c9e24457..1359298a 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/Notification.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/Notification.java @@ -2,7 +2,9 @@ package com.hypixel.hytale.protocol.packets.interface_; import com.hypixel.hytale.protocol.FormattedMessage; import com.hypixel.hytale.protocol.ItemWithAllMetadata; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -12,7 +14,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class Notification implements Packet { +public class Notification implements Packet, ToClientPacket { public static final int PACKET_ID = 212; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -36,6 +38,11 @@ public class Notification implements Packet { return 212; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public Notification() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/OpenChatWithCommand.java b/src/com/hypixel/hytale/protocol/packets/interface_/OpenChatWithCommand.java index 33f6bc9c..66148885 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/OpenChatWithCommand.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/OpenChatWithCommand.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class OpenChatWithCommand implements Packet { +public class OpenChatWithCommand implements Packet, ToClientPacket { public static final int PACKET_ID = 234; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class OpenChatWithCommand implements Packet { return 234; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public OpenChatWithCommand() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/RemoveFromServerPlayerList.java b/src/com/hypixel/hytale/protocol/packets/interface_/RemoveFromServerPlayerList.java index 3102b740..227b9b09 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/RemoveFromServerPlayerList.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/RemoveFromServerPlayerList.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class RemoveFromServerPlayerList implements Packet { +public class RemoveFromServerPlayerList implements Packet, ToClientPacket { public static final int PACKET_ID = 225; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class RemoveFromServerPlayerList implements Packet { return 225; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public RemoveFromServerPlayerList() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/ResetUserInterfaceState.java b/src/com/hypixel/hytale/protocol/packets/interface_/ResetUserInterfaceState.java index 88d8d417..b91ce2b9 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/ResetUserInterfaceState.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/ResetUserInterfaceState.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class ResetUserInterfaceState implements Packet { +public class ResetUserInterfaceState implements Packet, ToClientPacket { public static final int PACKET_ID = 231; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class ResetUserInterfaceState implements Packet { return 231; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static ResetUserInterfaceState deserialize(@Nonnull ByteBuf buf, int offset) { return new ResetUserInterfaceState(); diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/ServerInfo.java b/src/com/hypixel/hytale/protocol/packets/interface_/ServerInfo.java index ae18da2e..c68f2f24 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/ServerInfo.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/ServerInfo.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ServerInfo implements Packet { +public class ServerInfo implements Packet, ToClientPacket { public static final int PACKET_ID = 223; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class ServerInfo implements Packet { return 223; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ServerInfo() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/ServerMessage.java b/src/com/hypixel/hytale/protocol/packets/interface_/ServerMessage.java index 356444c0..42d52abc 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/ServerMessage.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/ServerMessage.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.interface_; import com.hypixel.hytale.protocol.FormattedMessage; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ServerMessage implements Packet { +public class ServerMessage implements Packet, ToClientPacket { public static final int PACKET_ID = 210; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class ServerMessage implements Packet { return 210; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ServerMessage() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/SetPage.java b/src/com/hypixel/hytale/protocol/packets/interface_/SetPage.java index 6733b84b..61cdc273 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/SetPage.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/SetPage.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetPage implements Packet { +public class SetPage implements Packet, ToClientPacket { public static final int PACKET_ID = 216; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class SetPage implements Packet { return 216; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetPage() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/ShowEventTitle.java b/src/com/hypixel/hytale/protocol/packets/interface_/ShowEventTitle.java index 74f3b920..354a5986 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/ShowEventTitle.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/ShowEventTitle.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.interface_; import com.hypixel.hytale.protocol.FormattedMessage; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ShowEventTitle implements Packet { +public class ShowEventTitle implements Packet, ToClientPacket { public static final int PACKET_ID = 214; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -35,6 +37,11 @@ public class ShowEventTitle implements Packet { return 214; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ShowEventTitle() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateAnchorUI.java b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateAnchorUI.java new file mode 100644 index 00000000..b94fbdb7 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateAnchorUI.java @@ -0,0 +1,401 @@ +package com.hypixel.hytale.protocol.packets.interface_; + +import com.hypixel.hytale.protocol.NetworkChannel; +import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +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.Arrays; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class UpdateAnchorUI implements Packet, ToClientPacket { + public static final int PACKET_ID = 235; + public static final boolean IS_COMPRESSED = true; + public static final int NULLABLE_BIT_FIELD_SIZE = 1; + public static final int FIXED_BLOCK_SIZE = 2; + public static final int VARIABLE_FIELD_COUNT = 3; + public static final int VARIABLE_BLOCK_START = 14; + public static final int MAX_SIZE = 1677721600; + @Nullable + public String anchorId; + public boolean clear; + @Nullable + public CustomUICommand[] commands; + @Nullable + public CustomUIEventBinding[] eventBindings; + + @Override + public int getId() { + return 235; + } + + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + + public UpdateAnchorUI() { + } + + public UpdateAnchorUI(@Nullable String anchorId, boolean clear, @Nullable CustomUICommand[] commands, @Nullable CustomUIEventBinding[] eventBindings) { + this.anchorId = anchorId; + this.clear = clear; + this.commands = commands; + this.eventBindings = eventBindings; + } + + public UpdateAnchorUI(@Nonnull UpdateAnchorUI other) { + this.anchorId = other.anchorId; + this.clear = other.clear; + this.commands = other.commands; + this.eventBindings = other.eventBindings; + } + + @Nonnull + public static UpdateAnchorUI deserialize(@Nonnull ByteBuf buf, int offset) { + UpdateAnchorUI obj = new UpdateAnchorUI(); + byte nullBits = buf.getByte(offset); + obj.clear = buf.getByte(offset + 1) != 0; + if ((nullBits & 1) != 0) { + int varPos0 = offset + 14 + buf.getIntLE(offset + 2); + int anchorIdLen = VarInt.peek(buf, varPos0); + if (anchorIdLen < 0) { + throw ProtocolException.negativeLength("AnchorId", anchorIdLen); + } + + if (anchorIdLen > 4096000) { + throw ProtocolException.stringTooLong("AnchorId", anchorIdLen, 4096000); + } + + obj.anchorId = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8); + } + + if ((nullBits & 2) != 0) { + int varPos1 = offset + 14 + buf.getIntLE(offset + 6); + int commandsCount = VarInt.peek(buf, varPos1); + if (commandsCount < 0) { + throw ProtocolException.negativeLength("Commands", commandsCount); + } + + if (commandsCount > 4096000) { + throw ProtocolException.arrayTooLong("Commands", commandsCount, 4096000); + } + + int varIntLen = VarInt.length(buf, varPos1); + if (varPos1 + varIntLen + commandsCount * 2L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("Commands", varPos1 + varIntLen + commandsCount * 2, buf.readableBytes()); + } + + obj.commands = new CustomUICommand[commandsCount]; + int elemPos = varPos1 + varIntLen; + + for (int i = 0; i < commandsCount; i++) { + obj.commands[i] = CustomUICommand.deserialize(buf, elemPos); + elemPos += CustomUICommand.computeBytesConsumed(buf, elemPos); + } + } + + if ((nullBits & 4) != 0) { + int varPos2 = offset + 14 + buf.getIntLE(offset + 10); + int eventBindingsCount = VarInt.peek(buf, varPos2); + if (eventBindingsCount < 0) { + throw ProtocolException.negativeLength("EventBindings", eventBindingsCount); + } + + if (eventBindingsCount > 4096000) { + throw ProtocolException.arrayTooLong("EventBindings", eventBindingsCount, 4096000); + } + + int varIntLen = VarInt.length(buf, varPos2); + if (varPos2 + varIntLen + eventBindingsCount * 3L > buf.readableBytes()) { + throw ProtocolException.bufferTooSmall("EventBindings", varPos2 + varIntLen + eventBindingsCount * 3, buf.readableBytes()); + } + + obj.eventBindings = new CustomUIEventBinding[eventBindingsCount]; + int elemPos = varPos2 + varIntLen; + + for (int i = 0; i < eventBindingsCount; i++) { + obj.eventBindings[i] = CustomUIEventBinding.deserialize(buf, elemPos); + elemPos += CustomUIEventBinding.computeBytesConsumed(buf, elemPos); + } + } + + return obj; + } + + public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { + byte nullBits = buf.getByte(offset); + int maxEnd = 14; + if ((nullBits & 1) != 0) { + int fieldOffset0 = buf.getIntLE(offset + 2); + int pos0 = offset + 14 + 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 + 6); + int pos1 = offset + 14 + fieldOffset1; + int arrLen = VarInt.peek(buf, pos1); + pos1 += VarInt.length(buf, pos1); + + for (int i = 0; i < arrLen; i++) { + pos1 += CustomUICommand.computeBytesConsumed(buf, pos1); + } + + if (pos1 - offset > maxEnd) { + maxEnd = pos1 - offset; + } + } + + if ((nullBits & 4) != 0) { + int fieldOffset2 = buf.getIntLE(offset + 10); + int pos2 = offset + 14 + fieldOffset2; + int arrLen = VarInt.peek(buf, pos2); + pos2 += VarInt.length(buf, pos2); + + for (int i = 0; i < arrLen; i++) { + pos2 += CustomUIEventBinding.computeBytesConsumed(buf, pos2); + } + + if (pos2 - offset > maxEnd) { + maxEnd = pos2 - offset; + } + } + + return maxEnd; + } + + @Override + public void serialize(@Nonnull ByteBuf buf) { + int startPos = buf.writerIndex(); + byte nullBits = 0; + if (this.anchorId != null) { + nullBits = (byte)(nullBits | 1); + } + + if (this.commands != null) { + nullBits = (byte)(nullBits | 2); + } + + if (this.eventBindings != null) { + nullBits = (byte)(nullBits | 4); + } + + buf.writeByte(nullBits); + buf.writeByte(this.clear ? 1 : 0); + int anchorIdOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int commandsOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int eventBindingsOffsetSlot = buf.writerIndex(); + buf.writeIntLE(0); + int varBlockStart = buf.writerIndex(); + if (this.anchorId != null) { + buf.setIntLE(anchorIdOffsetSlot, buf.writerIndex() - varBlockStart); + PacketIO.writeVarString(buf, this.anchorId, 4096000); + } else { + buf.setIntLE(anchorIdOffsetSlot, -1); + } + + if (this.commands != null) { + buf.setIntLE(commandsOffsetSlot, buf.writerIndex() - varBlockStart); + if (this.commands.length > 4096000) { + throw ProtocolException.arrayTooLong("Commands", this.commands.length, 4096000); + } + + VarInt.write(buf, this.commands.length); + + for (CustomUICommand item : this.commands) { + item.serialize(buf); + } + } else { + buf.setIntLE(commandsOffsetSlot, -1); + } + + if (this.eventBindings != null) { + buf.setIntLE(eventBindingsOffsetSlot, buf.writerIndex() - varBlockStart); + if (this.eventBindings.length > 4096000) { + throw ProtocolException.arrayTooLong("EventBindings", this.eventBindings.length, 4096000); + } + + VarInt.write(buf, this.eventBindings.length); + + for (CustomUIEventBinding item : this.eventBindings) { + item.serialize(buf); + } + } else { + buf.setIntLE(eventBindingsOffsetSlot, -1); + } + } + + @Override + public int computeSize() { + int size = 14; + if (this.anchorId != null) { + size += PacketIO.stringSize(this.anchorId); + } + + if (this.commands != null) { + int commandsSize = 0; + + for (CustomUICommand elem : this.commands) { + commandsSize += elem.computeSize(); + } + + size += VarInt.size(this.commands.length) + commandsSize; + } + + if (this.eventBindings != null) { + int eventBindingsSize = 0; + + for (CustomUIEventBinding elem : this.eventBindings) { + eventBindingsSize += elem.computeSize(); + } + + size += VarInt.size(this.eventBindings.length) + eventBindingsSize; + } + + return size; + } + + public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { + if (buffer.readableBytes() - offset < 14) { + return ValidationResult.error("Buffer too small: expected at least 14 bytes"); + } else { + byte nullBits = buffer.getByte(offset); + if ((nullBits & 1) != 0) { + int anchorIdOffset = buffer.getIntLE(offset + 2); + if (anchorIdOffset < 0) { + return ValidationResult.error("Invalid offset for AnchorId"); + } + + int pos = offset + 14 + anchorIdOffset; + if (pos >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for AnchorId"); + } + + int anchorIdLen = VarInt.peek(buffer, pos); + if (anchorIdLen < 0) { + return ValidationResult.error("Invalid string length for AnchorId"); + } + + if (anchorIdLen > 4096000) { + return ValidationResult.error("AnchorId exceeds max length 4096000"); + } + + pos += VarInt.length(buffer, pos); + pos += anchorIdLen; + if (pos > buffer.writerIndex()) { + return ValidationResult.error("Buffer overflow reading AnchorId"); + } + } + + if ((nullBits & 2) != 0) { + int commandsOffset = buffer.getIntLE(offset + 6); + if (commandsOffset < 0) { + return ValidationResult.error("Invalid offset for Commands"); + } + + int posx = offset + 14 + commandsOffset; + if (posx >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for Commands"); + } + + int commandsCount = VarInt.peek(buffer, posx); + if (commandsCount < 0) { + return ValidationResult.error("Invalid array count for Commands"); + } + + if (commandsCount > 4096000) { + return ValidationResult.error("Commands exceeds max length 4096000"); + } + + posx += VarInt.length(buffer, posx); + + for (int i = 0; i < commandsCount; i++) { + ValidationResult structResult = CustomUICommand.validateStructure(buffer, posx); + if (!structResult.isValid()) { + return ValidationResult.error("Invalid CustomUICommand in Commands[" + i + "]: " + structResult.error()); + } + + posx += CustomUICommand.computeBytesConsumed(buffer, posx); + } + } + + if ((nullBits & 4) != 0) { + int eventBindingsOffset = buffer.getIntLE(offset + 10); + if (eventBindingsOffset < 0) { + return ValidationResult.error("Invalid offset for EventBindings"); + } + + int posxx = offset + 14 + eventBindingsOffset; + if (posxx >= buffer.writerIndex()) { + return ValidationResult.error("Offset out of bounds for EventBindings"); + } + + int eventBindingsCount = VarInt.peek(buffer, posxx); + if (eventBindingsCount < 0) { + return ValidationResult.error("Invalid array count for EventBindings"); + } + + if (eventBindingsCount > 4096000) { + return ValidationResult.error("EventBindings exceeds max length 4096000"); + } + + posxx += VarInt.length(buffer, posxx); + + for (int i = 0; i < eventBindingsCount; i++) { + ValidationResult structResult = CustomUIEventBinding.validateStructure(buffer, posxx); + if (!structResult.isValid()) { + return ValidationResult.error("Invalid CustomUIEventBinding in EventBindings[" + i + "]: " + structResult.error()); + } + + posxx += CustomUIEventBinding.computeBytesConsumed(buffer, posxx); + } + } + + return ValidationResult.OK; + } + } + + public UpdateAnchorUI clone() { + UpdateAnchorUI copy = new UpdateAnchorUI(); + copy.anchorId = this.anchorId; + copy.clear = this.clear; + copy.commands = this.commands != null ? Arrays.stream(this.commands).map(e -> e.clone()).toArray(CustomUICommand[]::new) : null; + copy.eventBindings = this.eventBindings != null ? Arrays.stream(this.eventBindings).map(e -> e.clone()).toArray(CustomUIEventBinding[]::new) : null; + return copy; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return !(obj instanceof UpdateAnchorUI other) + ? false + : Objects.equals(this.anchorId, other.anchorId) + && this.clear == other.clear + && Arrays.equals((Object[])this.commands, (Object[])other.commands) + && Arrays.equals((Object[])this.eventBindings, (Object[])other.eventBindings); + } + } + + @Override + public int hashCode() { + int result = 1; + result = 31 * result + Objects.hashCode(this.anchorId); + result = 31 * result + Boolean.hashCode(this.clear); + result = 31 * result + Arrays.hashCode((Object[])this.commands); + return 31 * result + Arrays.hashCode((Object[])this.eventBindings); + } +} diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateKnownRecipes.java b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateKnownRecipes.java index b3305b27..0ae498c5 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateKnownRecipes.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateKnownRecipes.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.interface_; import com.hypixel.hytale.protocol.CraftingRecipe; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateKnownRecipes implements Packet { +public class UpdateKnownRecipes implements Packet, ToClientPacket { public static final int PACKET_ID = 228; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class UpdateKnownRecipes implements Packet { return 228; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateKnownRecipes() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateLanguage.java b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateLanguage.java index c707172e..58a905e4 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateLanguage.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateLanguage.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateLanguage implements Packet { +public class UpdateLanguage implements Packet, ToServerPacket { public static final int PACKET_ID = 232; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class UpdateLanguage implements Packet { return 232; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateLanguage() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/UpdatePortal.java b/src/com/hypixel/hytale/protocol/packets/interface_/UpdatePortal.java index d475e6e8..0fd42908 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/UpdatePortal.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/UpdatePortal.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdatePortal implements Packet { +public class UpdatePortal implements Packet, ToClientPacket { public static final int PACKET_ID = 229; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class UpdatePortal implements Packet { return 229; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdatePortal() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateServerPlayerList.java b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateServerPlayerList.java index da0362da..3e2ae715 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateServerPlayerList.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateServerPlayerList.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateServerPlayerList implements Packet { +public class UpdateServerPlayerList implements Packet, ToClientPacket { public static final int PACKET_ID = 226; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class UpdateServerPlayerList implements Packet { return 226; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateServerPlayerList() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateServerPlayerListPing.java b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateServerPlayerListPing.java index 91906fa4..59e9b3e9 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateServerPlayerListPing.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateServerPlayerListPing.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateServerPlayerListPing implements Packet { +public class UpdateServerPlayerListPing implements Packet, ToClientPacket { public static final int PACKET_ID = 227; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class UpdateServerPlayerListPing implements Packet { return 227; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateServerPlayerListPing() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateVisibleHudComponents.java b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateVisibleHudComponents.java index 501821e8..3b8c3a14 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/UpdateVisibleHudComponents.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/UpdateVisibleHudComponents.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateVisibleHudComponents implements Packet { +public class UpdateVisibleHudComponents implements Packet, ToClientPacket { public static final int PACKET_ID = 230; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class UpdateVisibleHudComponents implements Packet { return 230; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateVisibleHudComponents() { } diff --git a/src/com/hypixel/hytale/protocol/packets/interface_/WorldSavingStatus.java b/src/com/hypixel/hytale/protocol/packets/interface_/WorldSavingStatus.java index 259058db..fe435b00 100644 --- a/src/com/hypixel/hytale/protocol/packets/interface_/WorldSavingStatus.java +++ b/src/com/hypixel/hytale/protocol/packets/interface_/WorldSavingStatus.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.interface_; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class WorldSavingStatus implements Packet { +public class WorldSavingStatus implements Packet, ToClientPacket { public static final int PACKET_ID = 233; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class WorldSavingStatus implements Packet { return 233; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public WorldSavingStatus() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/DropCreativeItem.java b/src/com/hypixel/hytale/protocol/packets/inventory/DropCreativeItem.java index cc356ca6..b517b4ca 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/DropCreativeItem.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/DropCreativeItem.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.inventory; import com.hypixel.hytale.protocol.ItemQuantity; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class DropCreativeItem implements Packet { +public class DropCreativeItem implements Packet, ToServerPacket { public static final int PACKET_ID = 172; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class DropCreativeItem implements Packet { return 172; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public DropCreativeItem() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/DropItemStack.java b/src/com/hypixel/hytale/protocol/packets/inventory/DropItemStack.java index dcb5a143..c2a07333 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/DropItemStack.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/DropItemStack.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.inventory; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class DropItemStack implements Packet { +public class DropItemStack implements Packet, ToServerPacket { public static final int PACKET_ID = 174; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class DropItemStack implements Packet { return 174; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public DropItemStack() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/InventoryAction.java b/src/com/hypixel/hytale/protocol/packets/inventory/InventoryAction.java index c95b668f..8bc329ed 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/InventoryAction.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/InventoryAction.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.inventory; import com.hypixel.hytale.protocol.InventoryActionType; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class InventoryAction implements Packet { +public class InventoryAction implements Packet, ToServerPacket { public static final int PACKET_ID = 179; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -25,6 +27,11 @@ public class InventoryAction implements Packet { return 179; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public InventoryAction() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/MoveItemStack.java b/src/com/hypixel/hytale/protocol/packets/inventory/MoveItemStack.java index 468418f9..ef1cd823 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/MoveItemStack.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/MoveItemStack.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.inventory; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class MoveItemStack implements Packet { +public class MoveItemStack implements Packet, ToServerPacket { public static final int PACKET_ID = 175; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -25,6 +27,11 @@ public class MoveItemStack implements Packet { return 175; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public MoveItemStack() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/SetActiveSlot.java b/src/com/hypixel/hytale/protocol/packets/inventory/SetActiveSlot.java index e78fa438..14966a60 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/SetActiveSlot.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/SetActiveSlot.java @@ -1,12 +1,15 @@ package com.hypixel.hytale.protocol.packets.inventory; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetActiveSlot implements Packet { +public class SetActiveSlot implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 177; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +25,11 @@ public class SetActiveSlot implements Packet { return 177; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetActiveSlot() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/SetCreativeItem.java b/src/com/hypixel/hytale/protocol/packets/inventory/SetCreativeItem.java index 214a850b..a5dc16c0 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/SetCreativeItem.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/SetCreativeItem.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.inventory; import com.hypixel.hytale.protocol.ItemQuantity; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetCreativeItem implements Packet { +public class SetCreativeItem implements Packet, ToServerPacket { public static final int PACKET_ID = 171; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +28,11 @@ public class SetCreativeItem implements Packet { return 171; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetCreativeItem() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/SmartGiveCreativeItem.java b/src/com/hypixel/hytale/protocol/packets/inventory/SmartGiveCreativeItem.java index b3e95844..b39d230b 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/SmartGiveCreativeItem.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/SmartGiveCreativeItem.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.inventory; import com.hypixel.hytale.protocol.ItemQuantity; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.SmartMoveType; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SmartGiveCreativeItem implements Packet { +public class SmartGiveCreativeItem implements Packet, ToServerPacket { public static final int PACKET_ID = 173; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +28,11 @@ public class SmartGiveCreativeItem implements Packet { return 173; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SmartGiveCreativeItem() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/SmartMoveItemStack.java b/src/com/hypixel/hytale/protocol/packets/inventory/SmartMoveItemStack.java index b20b10ef..061343bb 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/SmartMoveItemStack.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/SmartMoveItemStack.java @@ -1,13 +1,16 @@ package com.hypixel.hytale.protocol.packets.inventory; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.SmartMoveType; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SmartMoveItemStack implements Packet { +public class SmartMoveItemStack implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 176; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +29,11 @@ public class SmartMoveItemStack implements Packet { return 176; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SmartMoveItemStack() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/SwitchHotbarBlockSet.java b/src/com/hypixel/hytale/protocol/packets/inventory/SwitchHotbarBlockSet.java index ef36b9db..6b21c13d 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/SwitchHotbarBlockSet.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/SwitchHotbarBlockSet.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.inventory; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SwitchHotbarBlockSet implements Packet { +public class SwitchHotbarBlockSet implements Packet, ToServerPacket { public static final int PACKET_ID = 178; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class SwitchHotbarBlockSet implements Packet { return 178; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SwitchHotbarBlockSet() { } diff --git a/src/com/hypixel/hytale/protocol/packets/inventory/UpdatePlayerInventory.java b/src/com/hypixel/hytale/protocol/packets/inventory/UpdatePlayerInventory.java index c7fa33a2..72744306 100644 --- a/src/com/hypixel/hytale/protocol/packets/inventory/UpdatePlayerInventory.java +++ b/src/com/hypixel/hytale/protocol/packets/inventory/UpdatePlayerInventory.java @@ -1,15 +1,17 @@ package com.hypixel.hytale.protocol.packets.inventory; import com.hypixel.hytale.protocol.InventorySection; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.SortType; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdatePlayerInventory implements Packet { +public class UpdatePlayerInventory implements Packet, ToClientPacket { public static final int PACKET_ID = 170; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -39,6 +41,11 @@ public class UpdatePlayerInventory implements Packet { return 170; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdatePlayerInventory() { } diff --git a/src/com/hypixel/hytale/protocol/packets/machinima/RequestMachinimaActorModel.java b/src/com/hypixel/hytale/protocol/packets/machinima/RequestMachinimaActorModel.java index 2214eb01..b419c1cc 100644 --- a/src/com/hypixel/hytale/protocol/packets/machinima/RequestMachinimaActorModel.java +++ b/src/com/hypixel/hytale/protocol/packets/machinima/RequestMachinimaActorModel.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.machinima; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class RequestMachinimaActorModel implements Packet { +public class RequestMachinimaActorModel implements Packet, ToServerPacket { public static final int PACKET_ID = 260; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class RequestMachinimaActorModel implements Packet { return 260; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public RequestMachinimaActorModel() { } diff --git a/src/com/hypixel/hytale/protocol/packets/machinima/SetMachinimaActorModel.java b/src/com/hypixel/hytale/protocol/packets/machinima/SetMachinimaActorModel.java index 6c768a49..5528242c 100644 --- a/src/com/hypixel/hytale/protocol/packets/machinima/SetMachinimaActorModel.java +++ b/src/com/hypixel/hytale/protocol/packets/machinima/SetMachinimaActorModel.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.machinima; import com.hypixel.hytale.protocol.Model; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetMachinimaActorModel implements Packet { +public class SetMachinimaActorModel implements Packet, ToClientPacket { public static final int PACKET_ID = 261; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -31,6 +33,11 @@ public class SetMachinimaActorModel implements Packet { return 261; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetMachinimaActorModel() { } diff --git a/src/com/hypixel/hytale/protocol/packets/machinima/UpdateMachinimaScene.java b/src/com/hypixel/hytale/protocol/packets/machinima/UpdateMachinimaScene.java index 989ab812..1fc62db0 100644 --- a/src/com/hypixel/hytale/protocol/packets/machinima/UpdateMachinimaScene.java +++ b/src/com/hypixel/hytale/protocol/packets/machinima/UpdateMachinimaScene.java @@ -1,6 +1,9 @@ package com.hypixel.hytale.protocol.packets.machinima; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -11,7 +14,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateMachinimaScene implements Packet { +public class UpdateMachinimaScene implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 262; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -34,6 +37,11 @@ public class UpdateMachinimaScene implements Packet { return 262; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateMachinimaScene() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/ClearDebugShapes.java b/src/com/hypixel/hytale/protocol/packets/player/ClearDebugShapes.java index dbec88ff..befeeefb 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/ClearDebugShapes.java +++ b/src/com/hypixel/hytale/protocol/packets/player/ClearDebugShapes.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class ClearDebugShapes implements Packet { +public class ClearDebugShapes implements Packet, ToClientPacket { public static final int PACKET_ID = 115; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class ClearDebugShapes implements Packet { return 115; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static ClearDebugShapes deserialize(@Nonnull ByteBuf buf, int offset) { return new ClearDebugShapes(); diff --git a/src/com/hypixel/hytale/protocol/packets/player/ClientMovement.java b/src/com/hypixel/hytale/protocol/packets/player/ClientMovement.java index 6757ef56..d37ec277 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/ClientMovement.java +++ b/src/com/hypixel/hytale/protocol/packets/player/ClientMovement.java @@ -3,9 +3,11 @@ package com.hypixel.hytale.protocol.packets.player; import com.hypixel.hytale.protocol.Direction; import com.hypixel.hytale.protocol.HalfFloatPosition; import com.hypixel.hytale.protocol.MovementStates; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.Position; import com.hypixel.hytale.protocol.TeleportAck; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.Vector3d; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -14,7 +16,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ClientMovement implements Packet { +public class ClientMovement implements Packet, ToServerPacket { public static final int PACKET_ID = 108; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 2; @@ -47,6 +49,11 @@ public class ClientMovement implements Packet { return 108; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ClientMovement() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/ClientPlaceBlock.java b/src/com/hypixel/hytale/protocol/packets/player/ClientPlaceBlock.java index 44995446..b7ad0c92 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/ClientPlaceBlock.java +++ b/src/com/hypixel/hytale/protocol/packets/player/ClientPlaceBlock.java @@ -2,14 +2,16 @@ package com.hypixel.hytale.protocol.packets.player; import com.hypixel.hytale.protocol.BlockPosition; import com.hypixel.hytale.protocol.BlockRotation; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ClientPlaceBlock implements Packet { +public class ClientPlaceBlock implements Packet, ToServerPacket { public static final int PACKET_ID = 117; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class ClientPlaceBlock implements Packet { return 117; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ClientPlaceBlock() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/ClientReady.java b/src/com/hypixel/hytale/protocol/packets/player/ClientReady.java index f68c938f..e500b3c7 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/ClientReady.java +++ b/src/com/hypixel/hytale/protocol/packets/player/ClientReady.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class ClientReady implements Packet { +public class ClientReady implements Packet, ToServerPacket { public static final int PACKET_ID = 105; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class ClientReady implements Packet { return 105; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ClientReady() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/ClientTeleport.java b/src/com/hypixel/hytale/protocol/packets/player/ClientTeleport.java index 105377b4..665c5bc5 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/ClientTeleport.java +++ b/src/com/hypixel/hytale/protocol/packets/player/ClientTeleport.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.player; import com.hypixel.hytale.protocol.ModelTransform; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ClientTeleport implements Packet { +public class ClientTeleport implements Packet, ToClientPacket { public static final int PACKET_ID = 109; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class ClientTeleport implements Packet { return 109; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ClientTeleport() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/DamageInfo.java b/src/com/hypixel/hytale/protocol/packets/player/DamageInfo.java index 3ccd7039..4871198e 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/DamageInfo.java +++ b/src/com/hypixel/hytale/protocol/packets/player/DamageInfo.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.player; import com.hypixel.hytale.protocol.DamageCause; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.Vector3d; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; @@ -9,7 +11,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class DamageInfo implements Packet { +public class DamageInfo implements Packet, ToClientPacket { public static final int PACKET_ID = 112; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class DamageInfo implements Packet { return 112; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public DamageInfo() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/DisplayDebug.java b/src/com/hypixel/hytale/protocol/packets/player/DisplayDebug.java index d9a943a0..a965a819 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/DisplayDebug.java +++ b/src/com/hypixel/hytale/protocol/packets/player/DisplayDebug.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.player; import com.hypixel.hytale.protocol.DebugShape; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.Vector3f; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -12,14 +14,14 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class DisplayDebug implements Packet { +public class DisplayDebug implements Packet, ToClientPacket { public static final int PACKET_ID = 114; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; - public static final int FIXED_BLOCK_SIZE = 19; + public static final int FIXED_BLOCK_SIZE = 23; public static final int VARIABLE_FIELD_COUNT = 2; - public static final int VARIABLE_BLOCK_START = 27; - public static final int MAX_SIZE = 32768037; + public static final int VARIABLE_BLOCK_START = 31; + public static final int MAX_SIZE = 32768041; @Nonnull public DebugShape shape = DebugShape.Sphere; @Nullable @@ -30,17 +32,29 @@ public class DisplayDebug implements Packet { public boolean fade; @Nullable public float[] frustumProjection; + public float opacity; @Override public int getId() { return 114; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public DisplayDebug() { } public DisplayDebug( - @Nonnull DebugShape shape, @Nullable float[] matrix, @Nullable Vector3f color, float time, boolean fade, @Nullable float[] frustumProjection + @Nonnull DebugShape shape, + @Nullable float[] matrix, + @Nullable Vector3f color, + float time, + boolean fade, + @Nullable float[] frustumProjection, + float opacity ) { this.shape = shape; this.matrix = matrix; @@ -48,6 +62,7 @@ public class DisplayDebug implements Packet { this.time = time; this.fade = fade; this.frustumProjection = frustumProjection; + this.opacity = opacity; } public DisplayDebug(@Nonnull DisplayDebug other) { @@ -57,6 +72,7 @@ public class DisplayDebug implements Packet { this.time = other.time; this.fade = other.fade; this.frustumProjection = other.frustumProjection; + this.opacity = other.opacity; } @Nonnull @@ -70,8 +86,9 @@ public class DisplayDebug implements Packet { obj.time = buf.getFloatLE(offset + 14); obj.fade = buf.getByte(offset + 18) != 0; + obj.opacity = buf.getFloatLE(offset + 19); if ((nullBits & 2) != 0) { - int varPos0 = offset + 27 + buf.getIntLE(offset + 19); + int varPos0 = offset + 31 + buf.getIntLE(offset + 23); int matrixCount = VarInt.peek(buf, varPos0); if (matrixCount < 0) { throw ProtocolException.negativeLength("Matrix", matrixCount); @@ -94,7 +111,7 @@ public class DisplayDebug implements Packet { } if ((nullBits & 4) != 0) { - int varPos1 = offset + 27 + buf.getIntLE(offset + 23); + int varPos1 = offset + 31 + buf.getIntLE(offset + 27); int frustumProjectionCount = VarInt.peek(buf, varPos1); if (frustumProjectionCount < 0) { throw ProtocolException.negativeLength("FrustumProjection", frustumProjectionCount); @@ -121,10 +138,10 @@ public class DisplayDebug implements Packet { public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) { byte nullBits = buf.getByte(offset); - int maxEnd = 27; + int maxEnd = 31; if ((nullBits & 2) != 0) { - int fieldOffset0 = buf.getIntLE(offset + 19); - int pos0 = offset + 27 + fieldOffset0; + int fieldOffset0 = buf.getIntLE(offset + 23); + int pos0 = offset + 31 + fieldOffset0; int arrLen = VarInt.peek(buf, pos0); pos0 += VarInt.length(buf, pos0) + arrLen * 4; if (pos0 - offset > maxEnd) { @@ -133,8 +150,8 @@ public class DisplayDebug implements Packet { } if ((nullBits & 4) != 0) { - int fieldOffset1 = buf.getIntLE(offset + 23); - int pos1 = offset + 27 + fieldOffset1; + int fieldOffset1 = buf.getIntLE(offset + 27); + int pos1 = offset + 31 + fieldOffset1; int arrLen = VarInt.peek(buf, pos1); pos1 += VarInt.length(buf, pos1) + arrLen * 4; if (pos1 - offset > maxEnd) { @@ -171,6 +188,7 @@ public class DisplayDebug implements Packet { buf.writeFloatLE(this.time); buf.writeByte(this.fade ? 1 : 0); + buf.writeFloatLE(this.opacity); int matrixOffsetSlot = buf.writerIndex(); buf.writeIntLE(0); int frustumProjectionOffsetSlot = buf.writerIndex(); @@ -209,7 +227,7 @@ public class DisplayDebug implements Packet { @Override public int computeSize() { - int size = 27; + int size = 31; if (this.matrix != null) { size += VarInt.size(this.matrix.length) + this.matrix.length * 4; } @@ -222,17 +240,17 @@ public class DisplayDebug implements Packet { } public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) { - if (buffer.readableBytes() - offset < 27) { - return ValidationResult.error("Buffer too small: expected at least 27 bytes"); + if (buffer.readableBytes() - offset < 31) { + return ValidationResult.error("Buffer too small: expected at least 31 bytes"); } else { byte nullBits = buffer.getByte(offset); if ((nullBits & 2) != 0) { - int matrixOffset = buffer.getIntLE(offset + 19); + int matrixOffset = buffer.getIntLE(offset + 23); if (matrixOffset < 0) { return ValidationResult.error("Invalid offset for Matrix"); } - int pos = offset + 27 + matrixOffset; + int pos = offset + 31 + matrixOffset; if (pos >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for Matrix"); } @@ -254,12 +272,12 @@ public class DisplayDebug implements Packet { } if ((nullBits & 4) != 0) { - int frustumProjectionOffset = buffer.getIntLE(offset + 23); + int frustumProjectionOffset = buffer.getIntLE(offset + 27); if (frustumProjectionOffset < 0) { return ValidationResult.error("Invalid offset for FrustumProjection"); } - int posx = offset + 27 + frustumProjectionOffset; + int posx = offset + 31 + frustumProjectionOffset; if (posx >= buffer.writerIndex()) { return ValidationResult.error("Offset out of bounds for FrustumProjection"); } @@ -292,6 +310,7 @@ public class DisplayDebug implements Packet { copy.time = this.time; copy.fade = this.fade; copy.frustumProjection = this.frustumProjection != null ? Arrays.copyOf(this.frustumProjection, this.frustumProjection.length) : null; + copy.opacity = this.opacity; return copy; } @@ -307,7 +326,8 @@ public class DisplayDebug implements Packet { && Objects.equals(this.color, other.color) && this.time == other.time && this.fade == other.fade - && Arrays.equals(this.frustumProjection, other.frustumProjection); + && Arrays.equals(this.frustumProjection, other.frustumProjection) + && this.opacity == other.opacity; } } @@ -319,6 +339,7 @@ public class DisplayDebug implements Packet { result = 31 * result + Objects.hashCode(this.color); result = 31 * result + Float.hashCode(this.time); result = 31 * result + Boolean.hashCode(this.fade); - return 31 * result + Arrays.hashCode(this.frustumProjection); + result = 31 * result + Arrays.hashCode(this.frustumProjection); + return 31 * result + Float.hashCode(this.opacity); } } diff --git a/src/com/hypixel/hytale/protocol/packets/player/JoinWorld.java b/src/com/hypixel/hytale/protocol/packets/player/JoinWorld.java index 126d5e36..6ffd9f97 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/JoinWorld.java +++ b/src/com/hypixel/hytale/protocol/packets/player/JoinWorld.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; @@ -8,7 +10,7 @@ import java.util.Objects; import java.util.UUID; import javax.annotation.Nonnull; -public class JoinWorld implements Packet { +public class JoinWorld implements Packet, ToClientPacket { public static final int PACKET_ID = 104; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +28,11 @@ public class JoinWorld implements Packet { return 104; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public JoinWorld() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/LoadHotbar.java b/src/com/hypixel/hytale/protocol/packets/player/LoadHotbar.java index 22440789..e9f1fa10 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/LoadHotbar.java +++ b/src/com/hypixel/hytale/protocol/packets/player/LoadHotbar.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class LoadHotbar implements Packet { +public class LoadHotbar implements Packet, ToServerPacket { public static final int PACKET_ID = 106; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class LoadHotbar implements Packet { return 106; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public LoadHotbar() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/MouseInteraction.java b/src/com/hypixel/hytale/protocol/packets/player/MouseInteraction.java index 494452d9..d77b5deb 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/MouseInteraction.java +++ b/src/com/hypixel/hytale/protocol/packets/player/MouseInteraction.java @@ -2,7 +2,9 @@ package com.hypixel.hytale.protocol.packets.player; import com.hypixel.hytale.protocol.MouseButtonEvent; import com.hypixel.hytale.protocol.MouseMotionEvent; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.Vector2f; import com.hypixel.hytale.protocol.WorldInteraction; import com.hypixel.hytale.protocol.io.PacketIO; @@ -14,7 +16,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class MouseInteraction implements Packet { +public class MouseInteraction implements Packet, ToServerPacket { public static final int PACKET_ID = 111; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -40,6 +42,11 @@ public class MouseInteraction implements Packet { return 111; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public MouseInteraction() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/RemoveMapMarker.java b/src/com/hypixel/hytale/protocol/packets/player/RemoveMapMarker.java index 7111984b..bb02fc0e 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/RemoveMapMarker.java +++ b/src/com/hypixel/hytale/protocol/packets/player/RemoveMapMarker.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class RemoveMapMarker implements Packet { +public class RemoveMapMarker implements Packet, ToServerPacket { public static final int PACKET_ID = 119; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class RemoveMapMarker implements Packet { return 119; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public RemoveMapMarker() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/ReticleEvent.java b/src/com/hypixel/hytale/protocol/packets/player/ReticleEvent.java index 1864e3db..e35e4d10 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/ReticleEvent.java +++ b/src/com/hypixel/hytale/protocol/packets/player/ReticleEvent.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class ReticleEvent implements Packet { +public class ReticleEvent implements Packet, ToClientPacket { public static final int PACKET_ID = 113; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class ReticleEvent implements Packet { return 113; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ReticleEvent() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/SaveHotbar.java b/src/com/hypixel/hytale/protocol/packets/player/SaveHotbar.java index cec3b579..696ca2e7 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/SaveHotbar.java +++ b/src/com/hypixel/hytale/protocol/packets/player/SaveHotbar.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SaveHotbar implements Packet { +public class SaveHotbar implements Packet, ToServerPacket { public static final int PACKET_ID = 107; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class SaveHotbar implements Packet { return 107; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SaveHotbar() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/SetBlockPlacementOverride.java b/src/com/hypixel/hytale/protocol/packets/player/SetBlockPlacementOverride.java index 13712666..051a7713 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/SetBlockPlacementOverride.java +++ b/src/com/hypixel/hytale/protocol/packets/player/SetBlockPlacementOverride.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetBlockPlacementOverride implements Packet { +public class SetBlockPlacementOverride implements Packet, ToClientPacket { public static final int PACKET_ID = 103; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class SetBlockPlacementOverride implements Packet { return 103; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetBlockPlacementOverride() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/SetClientId.java b/src/com/hypixel/hytale/protocol/packets/player/SetClientId.java index eca8b0be..444268f1 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/SetClientId.java +++ b/src/com/hypixel/hytale/protocol/packets/player/SetClientId.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetClientId implements Packet { +public class SetClientId implements Packet, ToClientPacket { public static final int PACKET_ID = 100; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class SetClientId implements Packet { return 100; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetClientId() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/SetGameMode.java b/src/com/hypixel/hytale/protocol/packets/player/SetGameMode.java index 9f86db93..6c23fd98 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/SetGameMode.java +++ b/src/com/hypixel/hytale/protocol/packets/player/SetGameMode.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.player; import com.hypixel.hytale.protocol.GameMode; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetGameMode implements Packet { +public class SetGameMode implements Packet, ToClientPacket { public static final int PACKET_ID = 101; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class SetGameMode implements Packet { return 101; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetGameMode() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/SetMovementStates.java b/src/com/hypixel/hytale/protocol/packets/player/SetMovementStates.java index c4de0af3..2a518d39 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/SetMovementStates.java +++ b/src/com/hypixel/hytale/protocol/packets/player/SetMovementStates.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.SavedMovementStates; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetMovementStates implements Packet { +public class SetMovementStates implements Packet, ToClientPacket { public static final int PACKET_ID = 102; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class SetMovementStates implements Packet { return 102; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetMovementStates() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/SyncPlayerPreferences.java b/src/com/hypixel/hytale/protocol/packets/player/SyncPlayerPreferences.java index 88fffd16..2d3097d6 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/SyncPlayerPreferences.java +++ b/src/com/hypixel/hytale/protocol/packets/player/SyncPlayerPreferences.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.PickupLocation; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SyncPlayerPreferences implements Packet { +public class SyncPlayerPreferences implements Packet, ToServerPacket { public static final int PACKET_ID = 116; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -38,6 +40,11 @@ public class SyncPlayerPreferences implements Packet { return 116; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SyncPlayerPreferences() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/UpdateMemoriesFeatureStatus.java b/src/com/hypixel/hytale/protocol/packets/player/UpdateMemoriesFeatureStatus.java index f9931582..45b7d9d5 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/UpdateMemoriesFeatureStatus.java +++ b/src/com/hypixel/hytale/protocol/packets/player/UpdateMemoriesFeatureStatus.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.player; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UpdateMemoriesFeatureStatus implements Packet { +public class UpdateMemoriesFeatureStatus implements Packet, ToClientPacket { public static final int PACKET_ID = 118; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class UpdateMemoriesFeatureStatus implements Packet { return 118; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateMemoriesFeatureStatus() { } diff --git a/src/com/hypixel/hytale/protocol/packets/player/UpdateMovementSettings.java b/src/com/hypixel/hytale/protocol/packets/player/UpdateMovementSettings.java index 591d1bc4..c4e2eed5 100644 --- a/src/com/hypixel/hytale/protocol/packets/player/UpdateMovementSettings.java +++ b/src/com/hypixel/hytale/protocol/packets/player/UpdateMovementSettings.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.player; import com.hypixel.hytale.protocol.MovementSettings; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateMovementSettings implements Packet { +public class UpdateMovementSettings implements Packet, ToClientPacket { public static final int PACKET_ID = 110; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class UpdateMovementSettings implements Packet { return 110; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateMovementSettings() { } diff --git a/src/com/hypixel/hytale/protocol/packets/serveraccess/RequestServerAccess.java b/src/com/hypixel/hytale/protocol/packets/serveraccess/RequestServerAccess.java index 75858234..716fb279 100644 --- a/src/com/hypixel/hytale/protocol/packets/serveraccess/RequestServerAccess.java +++ b/src/com/hypixel/hytale/protocol/packets/serveraccess/RequestServerAccess.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.serveraccess; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class RequestServerAccess implements Packet { +public class RequestServerAccess implements Packet, ToClientPacket { public static final int PACKET_ID = 250; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class RequestServerAccess implements Packet { return 250; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public RequestServerAccess() { } diff --git a/src/com/hypixel/hytale/protocol/packets/serveraccess/SetServerAccess.java b/src/com/hypixel/hytale/protocol/packets/serveraccess/SetServerAccess.java index c3195cee..8f89996e 100644 --- a/src/com/hypixel/hytale/protocol/packets/serveraccess/SetServerAccess.java +++ b/src/com/hypixel/hytale/protocol/packets/serveraccess/SetServerAccess.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.serveraccess; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetServerAccess implements Packet { +public class SetServerAccess implements Packet, ToServerPacket { public static final int PACKET_ID = 252; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class SetServerAccess implements Packet { return 252; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetServerAccess() { } diff --git a/src/com/hypixel/hytale/protocol/packets/serveraccess/UpdateServerAccess.java b/src/com/hypixel/hytale/protocol/packets/serveraccess/UpdateServerAccess.java index 8be67ebd..cf78dfa3 100644 --- a/src/com/hypixel/hytale/protocol/packets/serveraccess/UpdateServerAccess.java +++ b/src/com/hypixel/hytale/protocol/packets/serveraccess/UpdateServerAccess.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.serveraccess; import com.hypixel.hytale.protocol.HostAddress; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -11,7 +13,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateServerAccess implements Packet { +public class UpdateServerAccess implements Packet, ToServerPacket { public static final int PACKET_ID = 251; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class UpdateServerAccess implements Packet { return 251; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateServerAccess() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/AssetFinalize.java b/src/com/hypixel/hytale/protocol/packets/setup/AssetFinalize.java index b7ab6fca..acbe37d7 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/AssetFinalize.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/AssetFinalize.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class AssetFinalize implements Packet { +public class AssetFinalize implements Packet, ToClientPacket { public static final int PACKET_ID = 26; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class AssetFinalize implements Packet { return 26; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static AssetFinalize deserialize(@Nonnull ByteBuf buf, int offset) { return new AssetFinalize(); diff --git a/src/com/hypixel/hytale/protocol/packets/setup/AssetInitialize.java b/src/com/hypixel/hytale/protocol/packets/setup/AssetInitialize.java index 9fe4b2e1..9c25d68e 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/AssetInitialize.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/AssetInitialize.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.setup; import com.hypixel.hytale.protocol.Asset; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class AssetInitialize implements Packet { +public class AssetInitialize implements Packet, ToClientPacket { public static final int PACKET_ID = 24; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -24,6 +26,11 @@ public class AssetInitialize implements Packet { return 24; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetInitialize() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/AssetPart.java b/src/com/hypixel/hytale/protocol/packets/setup/AssetPart.java index a523baf6..5e790fc7 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/AssetPart.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/AssetPart.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class AssetPart implements Packet { +public class AssetPart implements Packet, ToClientPacket { public static final int PACKET_ID = 25; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class AssetPart implements Packet { return 25; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public AssetPart() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/PlayerOptions.java b/src/com/hypixel/hytale/protocol/packets/setup/PlayerOptions.java index 0329d831..1d0757ee 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/PlayerOptions.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/PlayerOptions.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.PlayerSkin; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class PlayerOptions implements Packet { +public class PlayerOptions implements Packet, ToServerPacket { public static final int PACKET_ID = 33; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class PlayerOptions implements Packet { return 33; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public PlayerOptions() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/RemoveAssets.java b/src/com/hypixel/hytale/protocol/packets/setup/RemoveAssets.java index 29319ac8..b7ea3c02 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/RemoveAssets.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/RemoveAssets.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.setup; import com.hypixel.hytale.protocol.Asset; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -10,7 +12,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class RemoveAssets implements Packet { +public class RemoveAssets implements Packet, ToClientPacket { public static final int PACKET_ID = 27; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class RemoveAssets implements Packet { return 27; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public RemoveAssets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/RequestAssets.java b/src/com/hypixel/hytale/protocol/packets/setup/RequestAssets.java index 2f92d5cf..0571b32f 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/RequestAssets.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/RequestAssets.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.setup; import com.hypixel.hytale.protocol.Asset; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -10,7 +12,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class RequestAssets implements Packet { +public class RequestAssets implements Packet, ToServerPacket { public static final int PACKET_ID = 23; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class RequestAssets implements Packet { return 23; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public RequestAssets() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/RequestCommonAssetsRebuild.java b/src/com/hypixel/hytale/protocol/packets/setup/RequestCommonAssetsRebuild.java index 1cf30bdb..cfb10ee5 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/RequestCommonAssetsRebuild.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/RequestCommonAssetsRebuild.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class RequestCommonAssetsRebuild implements Packet { +public class RequestCommonAssetsRebuild implements Packet, ToClientPacket { public static final int PACKET_ID = 28; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class RequestCommonAssetsRebuild implements Packet { return 28; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static RequestCommonAssetsRebuild deserialize(@Nonnull ByteBuf buf, int offset) { return new RequestCommonAssetsRebuild(); diff --git a/src/com/hypixel/hytale/protocol/packets/setup/ServerTags.java b/src/com/hypixel/hytale/protocol/packets/setup/ServerTags.java index cd119617..1d02d785 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/ServerTags.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/ServerTags.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -13,7 +15,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ServerTags implements Packet { +public class ServerTags implements Packet, ToClientPacket { public static final int PACKET_ID = 34; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -29,6 +31,11 @@ public class ServerTags implements Packet { return 34; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ServerTags() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/SetTimeDilation.java b/src/com/hypixel/hytale/protocol/packets/setup/SetTimeDilation.java index 01f7b9bd..010947cd 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/SetTimeDilation.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/SetTimeDilation.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetTimeDilation implements Packet { +public class SetTimeDilation implements Packet, ToClientPacket { public static final int PACKET_ID = 30; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class SetTimeDilation implements Packet { return 30; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetTimeDilation() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/SetUpdateRate.java b/src/com/hypixel/hytale/protocol/packets/setup/SetUpdateRate.java index b50015fb..fb8c04fb 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/SetUpdateRate.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/SetUpdateRate.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetUpdateRate implements Packet { +public class SetUpdateRate implements Packet, ToClientPacket { public static final int PACKET_ID = 29; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class SetUpdateRate implements Packet { return 29; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetUpdateRate() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/UpdateFeatures.java b/src/com/hypixel/hytale/protocol/packets/setup/UpdateFeatures.java index 31a66e12..0a2bc09c 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/UpdateFeatures.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/UpdateFeatures.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -12,7 +14,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateFeatures implements Packet { +public class UpdateFeatures implements Packet, ToClientPacket { public static final int PACKET_ID = 31; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class UpdateFeatures implements Packet { return 31; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateFeatures() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/ViewRadius.java b/src/com/hypixel/hytale/protocol/packets/setup/ViewRadius.java index 2f576b00..6cc45fcc 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/ViewRadius.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/ViewRadius.java @@ -1,12 +1,15 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class ViewRadius implements Packet { +public class ViewRadius implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 32; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +24,11 @@ public class ViewRadius implements Packet { return 32; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ViewRadius() { } diff --git a/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadFinished.java b/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadFinished.java index 4b66c09d..924279b9 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadFinished.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadFinished.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class WorldLoadFinished implements Packet { +public class WorldLoadFinished implements Packet, ToClientPacket { public static final int PACKET_ID = 22; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class WorldLoadFinished implements Packet { return 22; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static WorldLoadFinished deserialize(@Nonnull ByteBuf buf, int offset) { return new WorldLoadFinished(); diff --git a/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadProgress.java b/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadProgress.java index 044f540b..7b84287b 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadProgress.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/WorldLoadProgress.java @@ -1,25 +1,25 @@ package com.hypixel.hytale.protocol.packets.setup; +import com.hypixel.hytale.protocol.FormattedMessage; +import com.hypixel.hytale.protocol.NetworkChannel; 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.ToClientPacket; 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 WorldLoadProgress implements Packet { +public class WorldLoadProgress implements Packet, ToClientPacket { public static final int PACKET_ID = 21; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; 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; @@ -28,10 +28,15 @@ public class WorldLoadProgress implements Packet { return 21; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + 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 +56,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 +67,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 +84,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 +92,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 +105,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 +119,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/setup/WorldSettings.java b/src/com/hypixel/hytale/protocol/packets/setup/WorldSettings.java index e830d2f4..4b10c81c 100644 --- a/src/com/hypixel/hytale/protocol/packets/setup/WorldSettings.java +++ b/src/com/hypixel/hytale/protocol/packets/setup/WorldSettings.java @@ -1,7 +1,9 @@ package com.hypixel.hytale.protocol.packets.setup; import com.hypixel.hytale.protocol.Asset; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -10,7 +12,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class WorldSettings implements Packet { +public class WorldSettings implements Packet, ToClientPacket { public static final int PACKET_ID = 20; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class WorldSettings implements Packet { return 20; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public WorldSettings() { } diff --git a/src/com/hypixel/hytale/protocol/packets/window/ClientOpenWindow.java b/src/com/hypixel/hytale/protocol/packets/window/ClientOpenWindow.java index e8f0aa0c..6c04aa6c 100644 --- a/src/com/hypixel/hytale/protocol/packets/window/ClientOpenWindow.java +++ b/src/com/hypixel/hytale/protocol/packets/window/ClientOpenWindow.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.window; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class ClientOpenWindow implements Packet { +public class ClientOpenWindow implements Packet, ToServerPacket { public static final int PACKET_ID = 204; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class ClientOpenWindow implements Packet { return 204; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ClientOpenWindow() { } diff --git a/src/com/hypixel/hytale/protocol/packets/window/CloseWindow.java b/src/com/hypixel/hytale/protocol/packets/window/CloseWindow.java index f9664a5c..9ac27cc4 100644 --- a/src/com/hypixel/hytale/protocol/packets/window/CloseWindow.java +++ b/src/com/hypixel/hytale/protocol/packets/window/CloseWindow.java @@ -1,12 +1,15 @@ package com.hypixel.hytale.protocol.packets.window; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class CloseWindow implements Packet { +public class CloseWindow implements Packet, ToServerPacket, ToClientPacket { public static final int PACKET_ID = 202; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +24,11 @@ public class CloseWindow implements Packet { return 202; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public CloseWindow() { } diff --git a/src/com/hypixel/hytale/protocol/packets/window/OpenWindow.java b/src/com/hypixel/hytale/protocol/packets/window/OpenWindow.java index 72cb6834..bde3e616 100644 --- a/src/com/hypixel/hytale/protocol/packets/window/OpenWindow.java +++ b/src/com/hypixel/hytale/protocol/packets/window/OpenWindow.java @@ -2,7 +2,9 @@ package com.hypixel.hytale.protocol.packets.window; import com.hypixel.hytale.protocol.ExtraResources; import com.hypixel.hytale.protocol.InventorySection; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -12,7 +14,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class OpenWindow implements Packet { +public class OpenWindow implements Packet, ToClientPacket { public static final int PACKET_ID = 200; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -35,6 +37,11 @@ public class OpenWindow implements Packet { return 200; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public OpenWindow() { } diff --git a/src/com/hypixel/hytale/protocol/packets/window/SendWindowAction.java b/src/com/hypixel/hytale/protocol/packets/window/SendWindowAction.java index beb244db..428f6fd5 100644 --- a/src/com/hypixel/hytale/protocol/packets/window/SendWindowAction.java +++ b/src/com/hypixel/hytale/protocol/packets/window/SendWindowAction.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.window; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SendWindowAction implements Packet { +public class SendWindowAction implements Packet, ToServerPacket { public static final int PACKET_ID = 203; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -23,6 +25,11 @@ public class SendWindowAction implements Packet { return 203; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SendWindowAction() { } diff --git a/src/com/hypixel/hytale/protocol/packets/window/UpdateWindow.java b/src/com/hypixel/hytale/protocol/packets/window/UpdateWindow.java index 78f666b3..16dd4dcf 100644 --- a/src/com/hypixel/hytale/protocol/packets/window/UpdateWindow.java +++ b/src/com/hypixel/hytale/protocol/packets/window/UpdateWindow.java @@ -2,7 +2,9 @@ package com.hypixel.hytale.protocol.packets.window; import com.hypixel.hytale.protocol.ExtraResources; import com.hypixel.hytale.protocol.InventorySection; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -12,7 +14,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateWindow implements Packet { +public class UpdateWindow implements Packet, ToClientPacket { public static final int PACKET_ID = 201; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -33,6 +35,11 @@ public class UpdateWindow implements Packet { return 201; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateWindow() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/ClearEditorTimeOverride.java b/src/com/hypixel/hytale/protocol/packets/world/ClearEditorTimeOverride.java index 98ed3adc..177c43e3 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/ClearEditorTimeOverride.java +++ b/src/com/hypixel/hytale/protocol/packets/world/ClearEditorTimeOverride.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class ClearEditorTimeOverride implements Packet { +public class ClearEditorTimeOverride implements Packet, ToClientPacket { public static final int PACKET_ID = 148; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class ClearEditorTimeOverride implements Packet { return 148; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + @Nonnull public static ClearEditorTimeOverride deserialize(@Nonnull ByteBuf buf, int offset) { return new ClearEditorTimeOverride(); diff --git a/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEvent2D.java b/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEvent2D.java index 87c97336..444f5c07 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEvent2D.java +++ b/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEvent2D.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.SoundCategory; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class PlaySoundEvent2D implements Packet { +public class PlaySoundEvent2D implements Packet, ToClientPacket { public static final int PACKET_ID = 154; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +28,11 @@ public class PlaySoundEvent2D implements Packet { return 154; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public PlaySoundEvent2D() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEvent3D.java b/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEvent3D.java index 1c233eaf..60615cbb 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEvent3D.java +++ b/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEvent3D.java @@ -1,15 +1,17 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.Position; import com.hypixel.hytale.protocol.SoundCategory; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class PlaySoundEvent3D implements Packet { +public class PlaySoundEvent3D implements Packet, ToClientPacket { public static final int PACKET_ID = 155; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class PlaySoundEvent3D implements Packet { return 155; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public PlaySoundEvent3D() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEventEntity.java b/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEventEntity.java index 6d8d3b9f..0e235265 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEventEntity.java +++ b/src/com/hypixel/hytale/protocol/packets/world/PlaySoundEventEntity.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class PlaySoundEventEntity implements Packet { +public class PlaySoundEventEntity implements Packet, ToClientPacket { public static final int PACKET_ID = 156; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -24,6 +26,11 @@ public class PlaySoundEventEntity implements Packet { return 156; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public PlaySoundEventEntity() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/ServerSetBlock.java b/src/com/hypixel/hytale/protocol/packets/world/ServerSetBlock.java index 7189861f..c14cbaf1 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/ServerSetBlock.java +++ b/src/com/hypixel/hytale/protocol/packets/world/ServerSetBlock.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class ServerSetBlock implements Packet { +public class ServerSetBlock implements Packet, ToClientPacket { public static final int PACKET_ID = 140; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -26,6 +28,11 @@ public class ServerSetBlock implements Packet { return 140; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public ServerSetBlock() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/ServerSetBlocks.java b/src/com/hypixel/hytale/protocol/packets/world/ServerSetBlocks.java index 8a27087d..aec276e8 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/ServerSetBlocks.java +++ b/src/com/hypixel/hytale/protocol/packets/world/ServerSetBlocks.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -8,7 +10,7 @@ import io.netty.buffer.ByteBuf; import java.util.Arrays; import javax.annotation.Nonnull; -public class ServerSetBlocks implements Packet { +public class ServerSetBlocks implements Packet, ToClientPacket { public static final int PACKET_ID = 141; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -27,6 +29,11 @@ public class ServerSetBlocks implements Packet { return 141; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public ServerSetBlocks() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/ServerSetFluid.java b/src/com/hypixel/hytale/protocol/packets/world/ServerSetFluid.java index 71add375..7b98b76d 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/ServerSetFluid.java +++ b/src/com/hypixel/hytale/protocol/packets/world/ServerSetFluid.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class ServerSetFluid implements Packet { +public class ServerSetFluid implements Packet, ToClientPacket { public static final int PACKET_ID = 142; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -25,6 +27,11 @@ public class ServerSetFluid implements Packet { return 142; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public ServerSetFluid() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/ServerSetFluids.java b/src/com/hypixel/hytale/protocol/packets/world/ServerSetFluids.java index f9d070da..1fb83c95 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/ServerSetFluids.java +++ b/src/com/hypixel/hytale/protocol/packets/world/ServerSetFluids.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -8,7 +10,7 @@ import io.netty.buffer.ByteBuf; import java.util.Arrays; import javax.annotation.Nonnull; -public class ServerSetFluids implements Packet { +public class ServerSetFluids implements Packet, ToClientPacket { public static final int PACKET_ID = 143; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -27,6 +29,11 @@ public class ServerSetFluids implements Packet { return 143; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public ServerSetFluids() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/ServerSetPaused.java b/src/com/hypixel/hytale/protocol/packets/world/ServerSetPaused.java index a6a8fb52..7d9de493 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/ServerSetPaused.java +++ b/src/com/hypixel/hytale/protocol/packets/world/ServerSetPaused.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class ServerSetPaused implements Packet { +public class ServerSetPaused implements Packet, ToClientPacket { public static final int PACKET_ID = 159; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class ServerSetPaused implements Packet { return 159; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public ServerSetPaused() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/SetChunk.java b/src/com/hypixel/hytale/protocol/packets/world/SetChunk.java index 68275918..3ed1b81d 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/SetChunk.java +++ b/src/com/hypixel/hytale/protocol/packets/world/SetChunk.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetChunk implements Packet { +public class SetChunk implements Packet, ToClientPacket { public static final int PACKET_ID = 131; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -32,6 +34,11 @@ public class SetChunk implements Packet { return 131; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public SetChunk() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/SetChunkEnvironments.java b/src/com/hypixel/hytale/protocol/packets/world/SetChunkEnvironments.java index e8e4365a..a65c7085 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/SetChunkEnvironments.java +++ b/src/com/hypixel/hytale/protocol/packets/world/SetChunkEnvironments.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetChunkEnvironments implements Packet { +public class SetChunkEnvironments implements Packet, ToClientPacket { public static final int PACKET_ID = 134; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class SetChunkEnvironments implements Packet { return 134; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public SetChunkEnvironments() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/SetChunkHeightmap.java b/src/com/hypixel/hytale/protocol/packets/world/SetChunkHeightmap.java index e83f20b7..7a3ca9ae 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/SetChunkHeightmap.java +++ b/src/com/hypixel/hytale/protocol/packets/world/SetChunkHeightmap.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetChunkHeightmap implements Packet { +public class SetChunkHeightmap implements Packet, ToClientPacket { public static final int PACKET_ID = 132; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class SetChunkHeightmap implements Packet { return 132; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public SetChunkHeightmap() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/SetChunkTintmap.java b/src/com/hypixel/hytale/protocol/packets/world/SetChunkTintmap.java index 920fef13..9a8526c6 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/SetChunkTintmap.java +++ b/src/com/hypixel/hytale/protocol/packets/world/SetChunkTintmap.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetChunkTintmap implements Packet { +public class SetChunkTintmap implements Packet, ToClientPacket { public static final int PACKET_ID = 133; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class SetChunkTintmap implements Packet { return 133; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public SetChunkTintmap() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/SetFluids.java b/src/com/hypixel/hytale/protocol/packets/world/SetFluids.java index 4d7b3472..70127003 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/SetFluids.java +++ b/src/com/hypixel/hytale/protocol/packets/world/SetFluids.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -9,7 +11,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SetFluids implements Packet { +public class SetFluids implements Packet, ToClientPacket { public static final int PACKET_ID = 136; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class SetFluids implements Packet { return 136; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public SetFluids() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/SetPaused.java b/src/com/hypixel/hytale/protocol/packets/world/SetPaused.java index 5eeef8cd..27abb5bd 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/SetPaused.java +++ b/src/com/hypixel/hytale/protocol/packets/world/SetPaused.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class SetPaused implements Packet { +public class SetPaused implements Packet, ToServerPacket { public static final int PACKET_ID = 158; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class SetPaused implements Packet { return 158; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SetPaused() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/SpawnBlockParticleSystem.java b/src/com/hypixel/hytale/protocol/packets/world/SpawnBlockParticleSystem.java index 622393f9..bf65fa2c 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/SpawnBlockParticleSystem.java +++ b/src/com/hypixel/hytale/protocol/packets/world/SpawnBlockParticleSystem.java @@ -1,15 +1,17 @@ package com.hypixel.hytale.protocol.packets.world; import com.hypixel.hytale.protocol.BlockParticleEvent; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.Position; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SpawnBlockParticleSystem implements Packet { +public class SpawnBlockParticleSystem implements Packet, ToClientPacket { public static final int PACKET_ID = 153; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -28,6 +30,11 @@ public class SpawnBlockParticleSystem implements Packet { return 153; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SpawnBlockParticleSystem() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/SpawnParticleSystem.java b/src/com/hypixel/hytale/protocol/packets/world/SpawnParticleSystem.java index e870116d..d26f85bc 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/SpawnParticleSystem.java +++ b/src/com/hypixel/hytale/protocol/packets/world/SpawnParticleSystem.java @@ -2,8 +2,10 @@ package com.hypixel.hytale.protocol.packets.world; import com.hypixel.hytale.protocol.Color; import com.hypixel.hytale.protocol.Direction; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.Position; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -13,7 +15,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class SpawnParticleSystem implements Packet { +public class SpawnParticleSystem implements Packet, ToClientPacket { public static final int PACKET_ID = 152; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -36,6 +38,11 @@ public class SpawnParticleSystem implements Packet { return 152; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public SpawnParticleSystem() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UnloadChunk.java b/src/com/hypixel/hytale/protocol/packets/world/UnloadChunk.java index aefff6de..11f6d266 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UnloadChunk.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UnloadChunk.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UnloadChunk implements Packet { +public class UnloadChunk implements Packet, ToClientPacket { public static final int PACKET_ID = 135; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class UnloadChunk implements Packet { return 135; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public UnloadChunk() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateBlockDamage.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateBlockDamage.java index a58cefea..8630af8d 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateBlockDamage.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateBlockDamage.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.world; import com.hypixel.hytale.protocol.BlockPosition; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateBlockDamage implements Packet { +public class UpdateBlockDamage implements Packet, ToClientPacket { public static final int PACKET_ID = 144; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class UpdateBlockDamage implements Packet { return 144; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Chunks; + } + public UpdateBlockDamage() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateEditorTimeOverride.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateEditorTimeOverride.java index 36cd54e7..1fd64083 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateEditorTimeOverride.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateEditorTimeOverride.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.world; import com.hypixel.hytale.protocol.InstantData; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateEditorTimeOverride implements Packet { +public class UpdateEditorTimeOverride implements Packet, ToClientPacket { public static final int PACKET_ID = 147; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -25,6 +27,11 @@ public class UpdateEditorTimeOverride implements Packet { return 147; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateEditorTimeOverride() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateEditorWeatherOverride.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateEditorWeatherOverride.java index 407dcfdf..4d3e43d7 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateEditorWeatherOverride.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateEditorWeatherOverride.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UpdateEditorWeatherOverride implements Packet { +public class UpdateEditorWeatherOverride implements Packet, ToClientPacket { public static final int PACKET_ID = 150; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class UpdateEditorWeatherOverride implements Packet { return 150; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateEditorWeatherOverride() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateEnvironmentMusic.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateEnvironmentMusic.java index 67fc6180..4d386d4a 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateEnvironmentMusic.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateEnvironmentMusic.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UpdateEnvironmentMusic implements Packet { +public class UpdateEnvironmentMusic implements Packet, ToClientPacket { public static final int PACKET_ID = 151; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class UpdateEnvironmentMusic implements Packet { return 151; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateEnvironmentMusic() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdatePostFxSettings.java b/src/com/hypixel/hytale/protocol/packets/world/UpdatePostFxSettings.java index 4259333d..dde35163 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdatePostFxSettings.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdatePostFxSettings.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UpdatePostFxSettings implements Packet { +public class UpdatePostFxSettings implements Packet, ToClientPacket { public static final int PACKET_ID = 361; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -25,6 +27,11 @@ public class UpdatePostFxSettings implements Packet { return 361; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdatePostFxSettings() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateSleepState.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateSleepState.java index 40a554e8..9062d23b 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateSleepState.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateSleepState.java @@ -1,13 +1,15 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateSleepState implements Packet { +public class UpdateSleepState implements Packet, ToClientPacket { public static final int PACKET_ID = 157; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -27,6 +29,11 @@ public class UpdateSleepState implements Packet { return 157; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateSleepState() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateSunSettings.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateSunSettings.java index 45892241..420e9786 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateSunSettings.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateSunSettings.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UpdateSunSettings implements Packet { +public class UpdateSunSettings implements Packet, ToClientPacket { public static final int PACKET_ID = 360; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class UpdateSunSettings implements Packet { return 360; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateSunSettings() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateTime.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateTime.java index e3311fe9..1e919737 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateTime.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateTime.java @@ -1,14 +1,16 @@ package com.hypixel.hytale.protocol.packets.world; import com.hypixel.hytale.protocol.InstantData; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateTime implements Packet { +public class UpdateTime implements Packet, ToClientPacket { public static final int PACKET_ID = 146; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -24,6 +26,11 @@ public class UpdateTime implements Packet { return 146; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateTime() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateTimeSettings.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateTimeSettings.java index 3dc6b57e..bc27d309 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateTimeSettings.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateTimeSettings.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UpdateTimeSettings implements Packet { +public class UpdateTimeSettings implements Packet, ToClientPacket { public static final int PACKET_ID = 145; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -24,6 +26,11 @@ public class UpdateTimeSettings implements Packet { return 145; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateTimeSettings() { } diff --git a/src/com/hypixel/hytale/protocol/packets/world/UpdateWeather.java b/src/com/hypixel/hytale/protocol/packets/world/UpdateWeather.java index 5e83a193..6d5113d3 100644 --- a/src/com/hypixel/hytale/protocol/packets/world/UpdateWeather.java +++ b/src/com/hypixel/hytale/protocol/packets/world/UpdateWeather.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.world; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UpdateWeather implements Packet { +public class UpdateWeather implements Packet, ToClientPacket { public static final int PACKET_ID = 149; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class UpdateWeather implements Packet { return 149; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateWeather() { } diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/ClearWorldMap.java b/src/com/hypixel/hytale/protocol/packets/worldmap/ClearWorldMap.java index 0151a2e3..be17ce47 100644 --- a/src/com/hypixel/hytale/protocol/packets/worldmap/ClearWorldMap.java +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/ClearWorldMap.java @@ -1,11 +1,13 @@ package com.hypixel.hytale.protocol.packets.worldmap; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; -public class ClearWorldMap implements Packet { +public class ClearWorldMap implements Packet, ToClientPacket { public static final int PACKET_ID = 242; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -19,6 +21,11 @@ public class ClearWorldMap implements Packet { return 242; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.WorldMap; + } + @Nonnull public static ClearWorldMap deserialize(@Nonnull ByteBuf buf, int offset) { return new ClearWorldMap(); 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..a27c1317 --- /dev/null +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/CreateUserMarker.java @@ -0,0 +1,287 @@ +package com.hypixel.hytale.protocol.packets.worldmap; + +import com.hypixel.hytale.protocol.Color; +import com.hypixel.hytale.protocol.NetworkChannel; +import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; +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, ToServerPacket { + 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; + } + + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + + 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/TeleportToWorldMapMarker.java b/src/com/hypixel/hytale/protocol/packets/worldmap/TeleportToWorldMapMarker.java index e7d44ace..9192d9f6 100644 --- a/src/com/hypixel/hytale/protocol/packets/worldmap/TeleportToWorldMapMarker.java +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/TeleportToWorldMapMarker.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.worldmap; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class TeleportToWorldMapMarker implements Packet { +public class TeleportToWorldMapMarker implements Packet, ToServerPacket { public static final int PACKET_ID = 244; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -26,6 +28,11 @@ public class TeleportToWorldMapMarker implements Packet { return 244; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public TeleportToWorldMapMarker() { } diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/TeleportToWorldMapPosition.java b/src/com/hypixel/hytale/protocol/packets/worldmap/TeleportToWorldMapPosition.java index 8490f9a9..3466bab2 100644 --- a/src/com/hypixel/hytale/protocol/packets/worldmap/TeleportToWorldMapPosition.java +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/TeleportToWorldMapPosition.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.worldmap; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class TeleportToWorldMapPosition implements Packet { +public class TeleportToWorldMapPosition implements Packet, ToServerPacket { public static final int PACKET_ID = 245; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -22,6 +24,11 @@ public class TeleportToWorldMapPosition implements Packet { return 245; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public TeleportToWorldMapPosition() { } 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/UpdateWorldMap.java b/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMap.java index 207d7757..6874dedf 100644 --- a/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMap.java +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMap.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.worldmap; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.PacketIO; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; @@ -10,7 +12,7 @@ import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateWorldMap implements Packet { +public class UpdateWorldMap implements Packet, ToClientPacket { public static final int PACKET_ID = 241; public static final boolean IS_COMPRESSED = true; public static final int NULLABLE_BIT_FIELD_SIZE = 1; @@ -30,6 +32,11 @@ public class UpdateWorldMap implements Packet { return 241; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.WorldMap; + } + public UpdateWorldMap() { } diff --git a/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapSettings.java b/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapSettings.java index 65c0d3ec..7ad5b745 100644 --- a/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapSettings.java +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapSettings.java @@ -1,6 +1,8 @@ package com.hypixel.hytale.protocol.packets.worldmap; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.io.ProtocolException; import com.hypixel.hytale.protocol.io.ValidationResult; import com.hypixel.hytale.protocol.io.VarInt; @@ -12,19 +14,23 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class UpdateWorldMapSettings implements Packet { +public class UpdateWorldMapSettings implements Packet, ToClientPacket { 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; @@ -34,6 +40,11 @@ public class UpdateWorldMapSettings implements Packet { return 240; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateWorldMapSettings() { } @@ -42,6 +53,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 +65,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 +79,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 +95,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 +132,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 +157,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 +180,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 +195,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 +241,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 +262,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 +275,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/protocol/packets/worldmap/UpdateWorldMapVisible.java b/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapVisible.java index 4d52dc60..6e916851 100644 --- a/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapVisible.java +++ b/src/com/hypixel/hytale/protocol/packets/worldmap/UpdateWorldMapVisible.java @@ -1,12 +1,14 @@ package com.hypixel.hytale.protocol.packets.worldmap; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.ValidationResult; import io.netty.buffer.ByteBuf; import java.util.Objects; import javax.annotation.Nonnull; -public class UpdateWorldMapVisible implements Packet { +public class UpdateWorldMapVisible implements Packet, ToServerPacket { public static final int PACKET_ID = 243; public static final boolean IS_COMPRESSED = false; public static final int NULLABLE_BIT_FIELD_SIZE = 0; @@ -21,6 +23,11 @@ public class UpdateWorldMapVisible implements Packet { return 243; } + @Override + public NetworkChannel getChannel() { + return NetworkChannel.Default; + } + public UpdateWorldMapVisible() { } diff --git a/src/com/hypixel/hytale/registry/Registry.java b/src/com/hypixel/hytale/registry/Registry.java index ffe4281a..d5a05dfb 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; @@ -48,6 +50,16 @@ public abstract class Registry { this.enabled = false; } + public void shutdownAndCleanup(boolean shutdown) { + this.enabled = false; + + for (int i = this.registrations.size() - 1; i >= 0; i--) { + this.registrations.get(i).accept(shutdown); + } + + this.registrations.clear(); + } + public T register(@Nonnull T registration) { if (!this.enabled) { registration.unregister(); diff --git a/src/com/hypixel/hytale/server/core/Constants.java b/src/com/hypixel/hytale/server/core/Constants.java index e47428d7..9fe67f00 100644 --- a/src/com/hypixel/hytale/server/core/Constants.java +++ b/src/com/hypixel/hytale/server/core/Constants.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.server.core.cosmetics.CosmeticsModule; import com.hypixel.hytale.server.core.io.ServerManager; import com.hypixel.hytale.server.core.modules.LegacyModule; import com.hypixel.hytale.server.core.modules.accesscontrol.AccessControlModule; +import com.hypixel.hytale.server.core.modules.anchoraction.AnchorActionModule; import com.hypixel.hytale.server.core.modules.block.BlockModule; import com.hypixel.hytale.server.core.modules.blockhealth.BlockHealthModule; import com.hypixel.hytale.server.core.modules.blockset.BlockSetModule; @@ -70,6 +71,7 @@ public final class Constants { BlockHealthModule.MANIFEST, PrefabSpawnerModule.MANIFEST, TimeModule.MANIFEST, + AnchorActionModule.MANIFEST, InteractionModule.MANIFEST, EntityModule.MANIFEST, EntityStatsModule.MANIFEST, @@ -104,4 +106,8 @@ public final class Constants { private static Path getUniversePath() { return OPTION_SET.has(Options.UNIVERSE) ? OPTION_SET.valueOf(Options.UNIVERSE) : Path.of("universe"); } + + public static boolean shouldSkipModValidation() { + return OPTION_SET.has(Options.SKIP_MOD_VALIDATION) || HytaleServer.get().getConfig().shouldSkipModValidation(); + } } diff --git a/src/com/hypixel/hytale/server/core/HytaleServer.java b/src/com/hypixel/hytale/server/core/HytaleServer.java index 5cafb933..2a60afc3 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(); @@ -126,6 +129,11 @@ public class HytaleServer { options.setEnvironment("release"); options.setTag("patchline", ManifestUtil.getPatchline()); options.setServerName(NetworkUtil.getHostName()); + UUID distinctId = HardwareUtil.getUUID(); + if (distinctId != null) { + options.setDistinctId(distinctId.toString()); + } + options.setBeforeSend((event, hint) -> { Throwable throwable = event.getThrowable(); if (PluginClassLoader.isFromThirdPartyPlugin(throwable)) { @@ -151,6 +159,7 @@ public class HytaleServer { } HashMap pluginsContext = new HashMap<>(); + boolean hasExternalPlugins = false; for (PluginBase plugin : this.pluginManager.getPlugins()) { PluginManifest manifestxx = plugin.getManifest(); @@ -158,10 +167,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 +187,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); @@ -201,6 +219,7 @@ public class HytaleServer { } }); Sentry.init(options); + Sentry.startSession(); Sentry.configureScope( scope -> { UUID hardwareUUID = HardwareUtil.getUUID(); @@ -314,8 +333,8 @@ public class HytaleServer { if (loadAssetEvent.isShouldShutdown()) { List reasons = loadAssetEvent.getReasons(); - String join = String.join(", ", reasons); - LOGGER.at(Level.SEVERE).log("Asset validation FAILED with %d reason(s): %s", reasons.size(), join); + String join = String.join("\n", reasons); + LOGGER.at(Level.SEVERE).log("Asset validation FAILED with %d reason(s):\n%s", reasons.size(), join); this.shutdownServer(ShutdownReason.VALIDATE_ERROR.withMessage(join)); return; } @@ -418,7 +437,7 @@ public class HytaleServer { Objects.requireNonNull(reason, "Server shutdown reason can't be null!"); if (this.shutdown.getAndSet(reason) == null) { if (reason.getMessage() != null) { - this.sendSingleplayerSignal("-=|Shutdown|" + reason.getMessage()); + this.sendSingleplayerSignal("-=|Shutdown|" + reason.getMessage().replace("\n", "\\n")); } Thread shutdownThread = new Thread(() -> this.shutdown0(reason), "ShutdownThread"); @@ -449,6 +468,7 @@ public class HytaleServer { this.aliveLock.release(); HytaleLogManager.resetFinally(); + Sentry.endSession(); SCHEDULED_EXECUTOR.schedule(() -> { LOGGER.at(Level.SEVERE).log("Forcing shutdown!"); Runtime.getRuntime().halt(reason.getExitCode()); @@ -526,6 +546,12 @@ public class HytaleServer { } } + public void reportSingleplayerStatus(String message, double progress) { + if (Constants.SINGLEPLAYER) { + HytaleLoggerBackend.rawLog("-=|" + message + "|" + progress); + } + } + public void reportSaveProgress(@Nonnull World world, int saved, int total) { if (this.isShuttingDown()) { double progress = MathUtil.round((double)saved / total, 2) * 100.0; diff --git a/src/com/hypixel/hytale/server/core/HytaleServerConfig.java b/src/com/hypixel/hytale/server/core/HytaleServerConfig.java index de96474b..83918038 100644 --- a/src/com/hypixel/hytale/server/core/HytaleServerConfig.java +++ b/src/com/hypixel/hytale/server/core/HytaleServerConfig.java @@ -5,17 +5,20 @@ import com.hypixel.hytale.codec.DocumentContainingCodec; import com.hypixel.hytale.codec.ExtraInfo; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; -import com.hypixel.hytale.codec.codecs.EnumCodec; import com.hypixel.hytale.codec.codecs.map.MapCodec; import com.hypixel.hytale.codec.codecs.map.ObjectMapCodec; import com.hypixel.hytale.codec.lookup.Priority; import com.hypixel.hytale.codec.util.RawJsonReader; import com.hypixel.hytale.common.plugin.PluginIdentifier; -import com.hypixel.hytale.common.semver.SemverRange; +import com.hypixel.hytale.common.util.java.ManifestUtil; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.protocol.GameMode; import com.hypixel.hytale.server.core.auth.AuthCredentialStoreProvider; import com.hypixel.hytale.server.core.codec.ProtocolCodecs; +import com.hypixel.hytale.server.core.config.BackupConfig; +import com.hypixel.hytale.server.core.config.ModConfig; +import com.hypixel.hytale.server.core.config.RateLimitConfig; +import com.hypixel.hytale.server.core.config.UpdateConfig; import com.hypixel.hytale.server.core.universe.playerdata.DefaultPlayerStorageProvider; import com.hypixel.hytale.server.core.universe.playerdata.DiskPlayerStorageProvider; import com.hypixel.hytale.server.core.universe.playerdata.PlayerStorageProvider; @@ -37,14 +40,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) @@ -59,7 +62,7 @@ public class HytaleServerConfig { .add() .append(new KeyedCodec<>("ConnectionTimeouts", HytaleServerConfig.TimeoutProfile.CODEC), (o, m) -> o.connectionTimeouts = m, o -> o.connectionTimeouts) .add() - .append(new KeyedCodec<>("RateLimit", HytaleServerConfig.RateLimitConfig.CODEC), (o, m) -> o.rateLimitConfig = m, o -> o.rateLimitConfig) + .append(new KeyedCodec<>("RateLimit", RateLimitConfig.CODEC), (o, m) -> o.rateLimitConfig = m, o -> o.rateLimitConfig) .add() .append(new KeyedCodec<>("Modules", new MapCodec<>(HytaleServerConfig.Module.CODEC, ConcurrentHashMap::new, false)), (o, m) -> { o.modules = m; @@ -73,10 +76,7 @@ public class HytaleServerConfig { .add() .append( new KeyedCodec<>( - "Plugins", - new ObjectMapCodec<>( - HytaleServerConfig.ModConfig.CODEC, Object2ObjectOpenHashMap::new, PluginIdentifier::toString, PluginIdentifier::fromString, false - ) + "Plugins", new ObjectMapCodec<>(ModConfig.CODEC, Object2ObjectOpenHashMap::new, PluginIdentifier::toString, PluginIdentifier::fromString, false) ), (o, i) -> o.legacyPluginConfig = i, o -> null @@ -85,13 +85,15 @@ public class HytaleServerConfig { .add() .append( new KeyedCodec<>( - "Mods", - new ObjectMapCodec<>(HytaleServerConfig.ModConfig.CODEC, ConcurrentHashMap::new, PluginIdentifier::toString, PluginIdentifier::fromString, false) + "Mods", new ObjectMapCodec<>(ModConfig.CODEC, ConcurrentHashMap::new, PluginIdentifier::toString, PluginIdentifier::fromString, false) ), (o, i) -> o.modConfig = i, 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, @@ -102,22 +104,35 @@ public class HytaleServerConfig { .add() .append(new KeyedCodec<>("AuthCredentialStore", Codec.BSON_DOCUMENT), (o, value) -> o.authCredentialStoreConfig = value, o -> o.authCredentialStoreConfig) .add() - .append(new KeyedCodec<>("Update", HytaleServerConfig.UpdateConfig.CODEC), (o, value) -> o.updateConfig = value, o -> o.updateConfig) + .append(new KeyedCodec<>("Update", UpdateConfig.CODEC), (o, value) -> o.updateConfig = value, o -> o.updateConfig) .add() - .afterDecode(config -> { + .append(new KeyedCodec<>("SkipModValidationForVersion", Codec.STRING), (o, v) -> o.skipModValidationForVersion = v, o -> o.skipModValidationForVersion) + .add() + .append(new KeyedCodec<>("Backup", BackupConfig.CODEC), (o, value) -> o.backupConfig = value, o -> o.backupConfig) + .add() + .afterDecode((config, extraInfo) -> { config.defaults.hytaleServerConfig = config; config.connectionTimeouts.setHytaleServerConfig(config); - config.rateLimitConfig.hytaleServerConfig = config; - config.updateConfig.hytaleServerConfig = config; + config.rateLimitConfig.setHytaleServerConfig(config); + config.updateConfig.setHytaleServerConfig(config); + config.backupConfig.setHytaleServerConfig(config); config.modules.values().forEach(m -> m.setHytaleServerConfig(config)); if (config.legacyPluginConfig != null && !config.legacyPluginConfig.isEmpty()) { - for (Entry entry : config.legacyPluginConfig.entrySet()) { + for (Entry entry : config.legacyPluginConfig.entrySet()) { config.modConfig.putIfAbsent(entry.getKey(), entry.getValue()); } config.legacyPluginConfig = null; config.markChanged(); } + + if (config.defaultModsEnabled == null && extraInfo.getVersion() < 4) { + config.defaultModsEnabled = true; + } + + if (extraInfo.getVersion() != 4) { + config.markChanged(); + } }) .build(); @Nonnull @@ -132,15 +147,17 @@ public class HytaleServerConfig { @Nonnull private HytaleServerConfig.TimeoutProfile connectionTimeouts = new HytaleServerConfig.TimeoutProfile(this); @Nonnull - private HytaleServerConfig.RateLimitConfig rateLimitConfig = new HytaleServerConfig.RateLimitConfig(this); + private RateLimitConfig rateLimitConfig = new RateLimitConfig(this); @Nonnull private Map modules = new ConcurrentHashMap<>(); @Nonnull private Map logLevels = Collections.emptyMap(); @Nullable - private transient Map legacyPluginConfig; + private transient Map legacyPluginConfig; @Nonnull - private Map modConfig = new ConcurrentHashMap<>(); + private Map modConfig = new ConcurrentHashMap<>(); + @Nullable + private Boolean defaultModsEnabled; @Nonnull private Map unmodifiableModules = Collections.unmodifiableMap(this.modules); @Nonnull @@ -153,7 +170,15 @@ public class HytaleServerConfig { private transient AuthCredentialStoreProvider authCredentialStoreProvider = null; private boolean displayTmpTagsInStrings; @Nonnull - private HytaleServerConfig.UpdateConfig updateConfig = new HytaleServerConfig.UpdateConfig(this); + private UpdateConfig updateConfig = new UpdateConfig(this); + @Nonnull + private BackupConfig backupConfig = new BackupConfig(this); + @Nullable + private String skipModValidationForVersion; + + public static void setBoot(@Nonnull HytaleServerConfig serverConfig, @Nonnull PluginIdentifier identifier, boolean enabled) { + serverConfig.modConfig.computeIfAbsent(identifier, id -> new ModConfig()).setEnabled(enabled); + } public String getServerName() { return this.serverName; @@ -229,11 +254,11 @@ public class HytaleServerConfig { } @Nonnull - public HytaleServerConfig.RateLimitConfig getRateLimitConfig() { + public RateLimitConfig getRateLimitConfig() { return this.rateLimitConfig; } - public void setRateLimitConfig(@Nonnull HytaleServerConfig.RateLimitConfig rateLimitConfig) { + public void setRateLimitConfig(@Nonnull RateLimitConfig rateLimitConfig) { this.rateLimitConfig = rateLimitConfig; this.markChanged(); } @@ -264,15 +289,19 @@ public class HytaleServerConfig { } @Nonnull - public Map getModConfig() { + public Map getModConfig() { return this.modConfig; } - public void setModConfig(@Nonnull Map modConfig) { + public void setModConfig(@Nonnull Map modConfig) { this.modConfig = modConfig; this.markChanged(); } + public boolean getDefaultModsEnabled() { + return this.defaultModsEnabled != null ? this.defaultModsEnabled : !Constants.SINGLEPLAYER; + } + @Nonnull public PlayerStorageProvider getPlayerStorageProvider() { return this.playerStorageProvider; @@ -305,15 +334,29 @@ public class HytaleServerConfig { } @Nonnull - public HytaleServerConfig.UpdateConfig getUpdateConfig() { + public UpdateConfig getUpdateConfig() { return this.updateConfig; } - public void setUpdateConfig(@Nonnull HytaleServerConfig.UpdateConfig updateConfig) { + public void setUpdateConfig(@Nonnull UpdateConfig updateConfig) { this.updateConfig = updateConfig; this.markChanged(); } + @Nonnull + public BackupConfig getBackupConfig() { + return this.backupConfig; + } + + public void setBackupConfig(@Nonnull BackupConfig backupConfig) { + this.backupConfig = backupConfig; + this.markChanged(); + } + + public boolean shouldSkipModValidation() { + return this.skipModValidationForVersion != null && this.skipModValidationForVersion.equals(ManifestUtil.getImplementationRevisionId()); + } + public void removeModule(@Nonnull String module) { this.modules.remove(module); this.markChanged(); @@ -416,47 +459,6 @@ public class HytaleServerConfig { } } - public static class ModConfig { - public static final BuilderCodec CODEC = BuilderCodec.builder( - HytaleServerConfig.ModConfig.class, HytaleServerConfig.ModConfig::new - ) - .append(new KeyedCodec<>("Enabled", Codec.BOOLEAN), (modConfig, enabled) -> modConfig.enabled = enabled, modConfig -> modConfig.enabled) - .add() - .append( - new KeyedCodec<>("RequiredVersion", SemverRange.CODEC), - (modConfig, semverRange) -> modConfig.requiredVersion = semverRange, - modConfig -> modConfig.requiredVersion - ) - .add() - .build(); - @Nullable - private Boolean enabled; - @Nullable - private SemverRange requiredVersion; - - @Nullable - public Boolean getEnabled() { - return this.enabled; - } - - public void setEnabled(Boolean enabled) { - this.enabled = enabled; - } - - @Nullable - public SemverRange getRequiredVersion() { - return this.requiredVersion; - } - - public void setRequiredVersion(SemverRange requiredVersion) { - this.requiredVersion = requiredVersion; - } - - public static void setBoot(HytaleServerConfig serverConfig, PluginIdentifier identifier, boolean enabled) { - serverConfig.getModConfig().computeIfAbsent(identifier, id -> new HytaleServerConfig.ModConfig()).enabled = enabled; - } - } - public static class Module { @Nonnull protected static BuilderCodec.Builder BUILDER_CODEC_BUILDER = BuilderCodec.builder( @@ -555,62 +557,6 @@ public class HytaleServerConfig { } } - public static class RateLimitConfig { - public static final int DEFAULT_PACKETS_PER_SECOND = 2000; - public static final int DEFAULT_BURST_CAPACITY = 500; - public static final Codec CODEC = BuilderCodec.builder( - HytaleServerConfig.RateLimitConfig.class, HytaleServerConfig.RateLimitConfig::new - ) - .addField(new KeyedCodec<>("Enabled", Codec.BOOLEAN), (o, b) -> o.enabled = b, o -> o.enabled) - .addField(new KeyedCodec<>("PacketsPerSecond", Codec.INTEGER), (o, i) -> o.packetsPerSecond = i, o -> o.packetsPerSecond) - .addField(new KeyedCodec<>("BurstCapacity", Codec.INTEGER), (o, i) -> o.burstCapacity = i, o -> o.burstCapacity) - .build(); - private Boolean enabled; - private Integer packetsPerSecond; - private Integer burstCapacity; - transient HytaleServerConfig hytaleServerConfig; - - public RateLimitConfig() { - } - - public RateLimitConfig(HytaleServerConfig hytaleServerConfig) { - this.hytaleServerConfig = hytaleServerConfig; - } - - public boolean isEnabled() { - return this.enabled != null ? this.enabled : true; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - public int getPacketsPerSecond() { - return this.packetsPerSecond != null ? this.packetsPerSecond : 2000; - } - - public void setPacketsPerSecond(int packetsPerSecond) { - this.packetsPerSecond = packetsPerSecond; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - public int getBurstCapacity() { - return this.burstCapacity != null ? this.burstCapacity : 500; - } - - public void setBurstCapacity(int burstCapacity) { - this.burstCapacity = burstCapacity; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - } - public static class TimeoutProfile { private static final HytaleServerConfig.TimeoutProfile SINGLEPLAYER_DEFAULTS = new HytaleServerConfig.TimeoutProfile( Duration.ofSeconds(30L), @@ -812,136 +758,4 @@ public class HytaleServerConfig { this.hytaleServerConfig = hytaleServerConfig; } } - - public static class UpdateConfig { - public static final int DEFAULT_CHECK_INTERVAL_SECONDS = 3600; - public static final Codec CODEC = BuilderCodec.builder( - HytaleServerConfig.UpdateConfig.class, HytaleServerConfig.UpdateConfig::new - ) - .addField(new KeyedCodec<>("Enabled", Codec.BOOLEAN), (o, b) -> o.enabled = b, o -> o.enabled) - .addField(new KeyedCodec<>("CheckIntervalSeconds", Codec.INTEGER), (o, i) -> o.checkIntervalSeconds = i, o -> o.checkIntervalSeconds) - .addField(new KeyedCodec<>("NotifyPlayersOnAvailable", Codec.BOOLEAN), (o, b) -> o.notifyPlayersOnAvailable = b, o -> o.notifyPlayersOnAvailable) - .addField(new KeyedCodec<>("Patchline", Codec.STRING), (o, s) -> o.patchline = s, o -> o.patchline) - .addField(new KeyedCodec<>("RunBackupBeforeUpdate", Codec.BOOLEAN), (o, b) -> o.runBackupBeforeUpdate = b, o -> o.runBackupBeforeUpdate) - .addField(new KeyedCodec<>("BackupConfigBeforeUpdate", Codec.BOOLEAN), (o, b) -> o.backupConfigBeforeUpdate = b, o -> o.backupConfigBeforeUpdate) - .addField( - new KeyedCodec<>("AutoApplyMode", new EnumCodec<>(HytaleServerConfig.UpdateConfig.AutoApplyMode.class)), - (o, m) -> o.autoApplyMode = m, - o -> o.autoApplyMode - ) - .addField(new KeyedCodec<>("AutoApplyDelayMinutes", Codec.INTEGER), (o, i) -> o.autoApplyDelayMinutes = i, o -> o.autoApplyDelayMinutes) - .build(); - private Boolean enabled; - private Integer checkIntervalSeconds; - private Boolean notifyPlayersOnAvailable; - private String patchline; - private Boolean runBackupBeforeUpdate; - private Boolean backupConfigBeforeUpdate; - private HytaleServerConfig.UpdateConfig.AutoApplyMode autoApplyMode; - private Integer autoApplyDelayMinutes; - transient HytaleServerConfig hytaleServerConfig; - - public UpdateConfig() { - } - - public UpdateConfig(HytaleServerConfig hytaleServerConfig) { - this.hytaleServerConfig = hytaleServerConfig; - } - - public boolean isEnabled() { - return this.enabled != null ? this.enabled : true; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - public int getCheckIntervalSeconds() { - return this.checkIntervalSeconds != null ? this.checkIntervalSeconds : 3600; - } - - public void setCheckIntervalSeconds(int checkIntervalSeconds) { - this.checkIntervalSeconds = checkIntervalSeconds; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - public boolean isNotifyPlayersOnAvailable() { - return this.notifyPlayersOnAvailable != null ? this.notifyPlayersOnAvailable : true; - } - - public void setNotifyPlayersOnAvailable(boolean notifyPlayersOnAvailable) { - this.notifyPlayersOnAvailable = notifyPlayersOnAvailable; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - @Nullable - public String getPatchline() { - return this.patchline; - } - - public void setPatchline(@Nullable String patchline) { - this.patchline = patchline; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - public boolean isRunBackupBeforeUpdate() { - return this.runBackupBeforeUpdate != null ? this.runBackupBeforeUpdate : true; - } - - public void setRunBackupBeforeUpdate(boolean runBackupBeforeUpdate) { - this.runBackupBeforeUpdate = runBackupBeforeUpdate; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - public boolean isBackupConfigBeforeUpdate() { - return this.backupConfigBeforeUpdate != null ? this.backupConfigBeforeUpdate : true; - } - - public void setBackupConfigBeforeUpdate(boolean backupConfigBeforeUpdate) { - this.backupConfigBeforeUpdate = backupConfigBeforeUpdate; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - @Nonnull - public HytaleServerConfig.UpdateConfig.AutoApplyMode getAutoApplyMode() { - return this.autoApplyMode != null ? this.autoApplyMode : HytaleServerConfig.UpdateConfig.AutoApplyMode.DISABLED; - } - - public void setAutoApplyMode(@Nonnull HytaleServerConfig.UpdateConfig.AutoApplyMode autoApplyMode) { - this.autoApplyMode = autoApplyMode; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - public int getAutoApplyDelayMinutes() { - return this.autoApplyDelayMinutes != null ? this.autoApplyDelayMinutes : 30; - } - - public void setAutoApplyDelayMinutes(int autoApplyDelayMinutes) { - this.autoApplyDelayMinutes = autoApplyDelayMinutes; - if (this.hytaleServerConfig != null) { - this.hytaleServerConfig.markChanged(); - } - } - - public static enum AutoApplyMode { - DISABLED, - WHEN_EMPTY, - SCHEDULED; - } - } } diff --git a/src/com/hypixel/hytale/server/core/Options.java b/src/com/hypixel/hytale/server/core/Options.java index 0dbba4a4..f1d59262 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()); @@ -118,6 +122,9 @@ public class Options { ) .withRequiredArg() .withValuesSeparatedBy(','); + public static final OptionSpec SKIP_MOD_VALIDATION = PARSER.accepts( + "skip-mod-validation", "Skips mod validation, attempting to allow the server to boot even if one fails to load" + ); public static final String ALLOW_SELF_OP_COMMAND_STRING = "allow-op"; public static final OptionSpec ALLOW_SELF_OP_COMMAND = PARSER.accepts("allow-op"); public static final OptionSpec AUTH_MODE = PARSER.accepts("auth-mode", "Authentication mode") @@ -167,6 +174,30 @@ public class Options { HytaleLoggerBackend.loadLevels(List.of(Map.entry("", Level.WARNING))); } + for (Path path : optionSet.valuesOf(ASSET_DIRECTORY)) { + PathUtil.addTrustedRoot(path); + } + + for (Path path : optionSet.valuesOf(MODS_DIRECTORIES)) { + PathUtil.addTrustedRoot(path); + } + + for (Path path : optionSet.valuesOf(EARLY_PLUGIN_DIRECTORIES)) { + PathUtil.addTrustedRoot(path); + } + + if (optionSet.has(WORLD_GEN_DIRECTORY)) { + PathUtil.addTrustedRoot(optionSet.valueOf(WORLD_GEN_DIRECTORY)); + } + + if (optionSet.has(BACKUP_DIRECTORY)) { + PathUtil.addTrustedRoot(optionSet.valueOf(BACKUP_DIRECTORY)); + } + + if (optionSet.has(UNIVERSE)) { + PathUtil.addTrustedRoot(optionSet.valueOf(UNIVERSE)); + } + return false; } } diff --git a/src/com/hypixel/hytale/server/core/ShutdownReason.java b/src/com/hypixel/hytale/server/core/ShutdownReason.java index c63b32aa..218c518a 100644 --- a/src/com/hypixel/hytale/server/core/ShutdownReason.java +++ b/src/com/hypixel/hytale/server/core/ShutdownReason.java @@ -13,6 +13,7 @@ public class ShutdownReason { public static final ShutdownReason VALIDATE_ERROR = new ShutdownReason(6); public static final ShutdownReason MISSING_ASSETS = new ShutdownReason(7); public static final ShutdownReason UPDATE = new ShutdownReason(8); + public static final ShutdownReason MOD_ERROR = new ShutdownReason(9); private final int exitCode; private final String message; diff --git a/src/com/hypixel/hytale/server/core/asset/AssetModule.java b/src/com/hypixel/hytale/server/core/asset/AssetModule.java index bffe73a1..1af4a947 100644 --- a/src/com/hypixel/hytale/server/core/asset/AssetModule.java +++ b/src/com/hypixel/hytale/server/core/asset/AssetModule.java @@ -13,10 +13,14 @@ import com.hypixel.hytale.codec.util.RawJsonReader; import com.hypixel.hytale.common.plugin.PluginIdentifier; import com.hypixel.hytale.common.plugin.PluginManifest; import com.hypixel.hytale.common.util.FormatUtil; +import com.hypixel.hytale.common.util.PathUtil; +import com.hypixel.hytale.common.util.java.ManifestUtil; import com.hypixel.hytale.event.EventPriority; import com.hypixel.hytale.logger.HytaleLogger; +import com.hypixel.hytale.server.core.Constants; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.HytaleServerConfig; +import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.Options; import com.hypixel.hytale.server.core.ShutdownReason; import com.hypixel.hytale.server.core.asset.monitor.AssetMonitor; @@ -24,10 +28,14 @@ import com.hypixel.hytale.server.core.asset.type.gameplay.respawn.HomeOrSpawnPoi import com.hypixel.hytale.server.core.asset.type.gameplay.respawn.RespawnController; import com.hypixel.hytale.server.core.asset.type.gameplay.respawn.WorldSpawnPoint; import com.hypixel.hytale.server.core.asset.type.item.DroplistCommand; +import com.hypixel.hytale.server.core.config.ModConfig; +import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.event.events.BootEvent; +import com.hypixel.hytale.server.core.event.events.player.AddPlayerToWorldEvent; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; import com.hypixel.hytale.server.core.plugin.PluginManager; +import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.worldgen.IWorldGen; import com.hypixel.hytale.server.core.universe.world.worldgen.ValidatableWorldGen; import com.hypixel.hytale.server.core.universe.world.worldgen.WorldGenLoadException; @@ -35,6 +43,8 @@ import com.hypixel.hytale.server.core.universe.world.worldgen.provider.IWorldGen import com.hypixel.hytale.server.core.universe.world.worldmap.IWorldMap; import com.hypixel.hytale.server.core.universe.world.worldmap.provider.IWorldMapProvider; import com.hypixel.hytale.sneakythrow.SneakyThrow; +import it.unimi.dsi.fastutil.objects.ObjectBooleanPair; +import java.awt.Color; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; @@ -44,6 +54,8 @@ import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -59,6 +71,8 @@ public class AssetModule extends JavaPlugin { private AssetMonitor assetMonitor; @Nonnull private final List assetPacks = new CopyOnWriteArrayList<>(); + private final List> pendingAssetPacks = new ArrayList<>(); + private boolean hasSetup = false; private boolean hasLoaded = false; private final List> pendingAssetStores = new CopyOnWriteArrayList<>(); @@ -79,15 +93,32 @@ public class AssetModule extends JavaPlugin { try { this.assetMonitor = new AssetMonitor(); this.getLogger().at(Level.INFO).log("Asset monitor enabled!"); - } catch (IOException var4) { - this.getLogger().at(Level.SEVERE).withCause(var4).log("Failed to create asset monitor!"); + } catch (IOException var8) { + this.getLogger().at(Level.SEVERE).withCause(var8).log("Failed to create asset monitor!"); } } for (Path path : Options.getOptionSet().valuesOf(Options.ASSET_DIRECTORY)) { - this.loadAndRegisterPack(path); + this.loadAndRegisterPack(path, false); } + this.hasSetup = true; + + for (ObjectBooleanPair p : this.pendingAssetPacks) { + if (this.getAssetPack(p.left().getName()) != null) { + if (!p.rightBoolean()) { + throw new IllegalStateException("Asset pack with name '" + p.left().getName() + "' already exists"); + } + + this.getLogger() + .at(Level.WARNING) + .log("Asset pack with name '%s' already exists, skipping registration from path: %s", p.left().getName(), p.left().getRoot()); + } else { + this.assetPacks.add(p.left()); + } + } + + this.pendingAssetPacks.clear(); this.loadPacksFromDirectory(PluginManager.MODS_PATH); for (Path modsPath : Options.getOptionSet().valuesOf(Options.MODS_DIRECTORIES)) { @@ -97,6 +128,59 @@ public class AssetModule extends JavaPlugin { if (this.assetPacks.isEmpty()) { HytaleServer.get().shutdownServer(ShutdownReason.MISSING_ASSETS.withMessage("Failed to load any asset packs")); } else { + boolean hasOutdatedPacks = false; + String serverVersion = ManifestUtil.getVersion(); + + for (AssetPack pack : this.assetPacks) { + if (!pack.getName().equals("Hytale:Hytale")) { + PluginManifest manifest = pack.getManifest(); + String targetServerVersion = manifest.getServerVersion(); + if (targetServerVersion == null || !targetServerVersion.equals(serverVersion)) { + hasOutdatedPacks = true; + if (targetServerVersion != null && !"*".equals(targetServerVersion)) { + this.getLogger() + .at(Level.WARNING) + .log( + "Plugin '%s' targets a different server version %s. You may encounter issues, please check for plugin updates.", + pack.getName(), + serverVersion + ); + } else { + this.getLogger() + .at(Level.WARNING) + .log( + "Plugin '%s' does not specify a target server version. You may encounter issues, please check for plugin updates. This will be a hard error in the future", + pack.getName() + ); + } + } + } + } + + if (hasOutdatedPacks && System.getProperty("hytale.allow_outdated_mods") == null) { + this.getLogger() + .at(Level.SEVERE) + .log("One or more asset packs are targeting an older server version. It is recommended to update these plugins to ensure compatibility."); + + try { + if (!Constants.SINGLEPLAYER) { + Thread.sleep(Duration.ofSeconds(2L)); + } + } catch (InterruptedException var9) { + throw new RuntimeException(var9); + } + + HytaleServer.get().getEventBus().registerGlobal(AddPlayerToWorldEvent.class, event -> { + PlayerRef playerRef = event.getHolder().getComponent(PlayerRef.getComponentType()); + Player player = event.getHolder().getComponent(Player.getComponentType()); + if (playerRef != null && player != null) { + if (player.hasPermission("hytale.mods.outdated.notify")) { + playerRef.sendMessage(Message.translation("server.assetModule.outOfDatePacks").color(Color.RED)); + } + } + }); + } + this.getEventRegistry().register((short)-16, LoadAssetEvent.class, event -> { if (this.hasLoaded) { throw new IllegalStateException("LoadAssetEvent has already been dispatched"); @@ -107,8 +191,8 @@ public class AssetModule extends JavaPlugin { this.hasLoaded = true; AssetRegistryLoader.preLoadAssets(event); - for (AssetPack pack : this.assetPacks) { - AssetRegistryLoader.loadAssets(event, pack); + for (AssetPack packx : this.assetPacks) { + AssetRegistryLoader.loadAssets(event, packx); } } finally { AssetRegistry.ASSET_LOCK.writeLock().unlock(); @@ -194,6 +278,17 @@ public class AssetModule extends JavaPlugin { return null; } + public boolean isWithinPackSubDir(@Nonnull Path path, @Nonnull String subDir) { + for (AssetPack pack : this.assetPacks) { + Path packSubDir = pack.getRoot().resolve(subDir); + if (PathUtil.isChildOf(packSubDir, path)) { + return true; + } + } + + return false; + } + public boolean isAssetPathImmutable(@Nonnull Path path) { AssetPack pack = this.findAssetPackForPath(path); return pack != null && pack.isImmutable(); @@ -244,7 +339,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 +348,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,24 +356,31 @@ 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(); + 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); + this.registerPack(packId, packPath, manifest, false); this.getLogger().at(Level.INFO).log("Loaded pack: %s from %s", packId, packPath.getFileName()); } else { this.getLogger().at(Level.INFO).log("Skipped disabled pack: %s", packId); } } - public void registerPack(@Nonnull String name, @Nonnull Path path, @Nonnull PluginManifest manifest) { + public void registerPack(@Nonnull String name, @Nonnull Path path, @Nonnull PluginManifest manifest, boolean ignoreIfExists) { Path absolutePath = path.toAbsolutePath().normalize(); Path packLocation = absolutePath; FileSystem fileSystem = null; @@ -291,22 +393,35 @@ public class AssetModule extends JavaPlugin { fileSystem = FileSystems.newFileSystem(absolutePath, (ClassLoader)null); absolutePath = fileSystem.getPath("").toAbsolutePath().normalize(); isImmutable = true; - } catch (IOException var13) { - throw SneakyThrow.sneakyThrow(var13); + } catch (IOException var14) { + throw SneakyThrow.sneakyThrow(var14); } } AssetPack pack = new AssetPack(packLocation, name, absolutePath, fileSystem, isImmutable, manifest); - this.assetPacks.add(pack); - AssetRegistry.ASSET_LOCK.writeLock().lock(); - - try { - if (this.hasLoaded) { - HytaleServer.get().getEventBus().dispatchFor(AssetPackRegisterEvent.class).dispatch(new AssetPackRegisterEvent(pack)); - return; + if (!this.hasSetup) { + this.pendingAssetPacks.add(ObjectBooleanPair.of(pack, ignoreIfExists)); + } else if (this.getAssetPack(name) != null) { + if (ignoreIfExists) { + this.getLogger().at(Level.WARNING).log("Asset pack with name '%s' already exists, skipping registration from path: %s", name, path); + } else { + throw new IllegalStateException("Asset pack with name '" + name + "' already exists"); + } + } else { + this.assetPacks.add(pack); + AssetRegistry.ASSET_LOCK.writeLock().lock(); + + try { + if (this.hasLoaded) { + HytaleServer.get() + .getEventBus() + .dispatchFor(AssetPackRegisterEvent.class) + .dispatch(new AssetPackRegisterEvent(pack)); + return; + } + } finally { + AssetRegistry.ASSET_LOCK.writeLock().unlock(); } - } finally { - AssetRegistry.ASSET_LOCK.writeLock().unlock(); } } diff --git a/src/com/hypixel/hytale/server/core/asset/AssetRegistryLoader.java b/src/com/hypixel/hytale/server/core/asset/AssetRegistryLoader.java index 5b4c0b63..21836d2e 100644 --- a/src/com/hypixel/hytale/server/core/asset/AssetRegistryLoader.java +++ b/src/com/hypixel/hytale/server/core/asset/AssetRegistryLoader.java @@ -19,7 +19,8 @@ import com.hypixel.hytale.codec.schema.SchemaContext; import com.hypixel.hytale.codec.schema.config.Schema; import com.hypixel.hytale.common.util.FormatUtil; import com.hypixel.hytale.logger.HytaleLogger; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.server.core.Constants; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.Options; import com.hypixel.hytale.server.core.ShutdownReason; @@ -247,6 +248,7 @@ public class AssetRegistryLoader { Path serverAssetDirectory = assetPack.getRoot().resolve("Server"); HytaleLogger.getLogger().at(Level.INFO).log("Loading assets from: %s", serverAssetDirectory); long startAll = System.nanoTime(); + boolean shouldFail = Options.getOptionSet().has(Options.VALIDATE_ASSETS) || !Constants.shouldSkipModValidation(); boolean failedToLoadAsset = false; LOGGER.at(Level.INFO).log("Loading assets from %s", serverAssetDirectory); Collection> values = AssetRegistry.getStoreMap().values(); @@ -277,19 +279,23 @@ public class AssetRegistryLoader { failedToLoadAsset |= loadResult.hasFailed(); } } - } catch (Exception var18) { + } catch (Exception var19) { failedToLoadAsset = true; + if (event != null) { + event.failed(shouldFail, "Asset pack " + assetPack.getName() + " failed to load " + assetClass.getSimpleName() + " - " + var19.getMessage()); + } + long end = System.nanoTime(); long diff = end - start; if (iterator.isBeingWaitedFor(assetStore)) { throw new RuntimeException( String.format("Failed to load %s from path '%s' took %s", assetClass.getSimpleName(), assetStore.getPath(), FormatUtil.nanosToString(diff)), - var18 + var19 ); } LOGGER.at(Level.SEVERE) - .withCause(var18) + .withCause(var19) .log("Failed to load %s from path '%s' took %s", assetClass.getSimpleName(), assetStore.getPath(), FormatUtil.nanosToString(diff)); } } @@ -313,33 +319,25 @@ public class AssetRegistryLoader { long diffAll = endAll - startAll; LOGGER.at(Level.INFO).log("Took %s to load all assets", FormatUtil.nanosToString(diffAll)); if (failedToLoadAsset && event != null) { - event.failed(Options.getOptionSet().has(Options.VALIDATE_ASSETS), "failed to validate assets"); + if ("Hytale:Hytale".equals(assetPack.getName())) { + event.failed(shouldFail, "Assets " + assetPack.getName() + " failed to load."); + } else { + event.failed(shouldFail, "Mod " + assetPack.getName() + " failed to load. Check for mod updates or contact the mod author."); + } } } public static void sendAssets(@Nonnull PacketHandler packetHandler) { - Consumer packetConsumer = packetHandler::write; - Consumer singlePacketConsumer = packetHandler::write; - AssetRegistry.ASSET_LOCK.writeLock().lock(); - - try { - HytaleAssetStore.SETUP_PACKET_CONSUMERS.add(singlePacketConsumer); - } finally { - AssetRegistry.ASSET_LOCK.writeLock().unlock(); - } + Consumer packetConsumer = packetHandler::write; + Consumer singlePacketConsumer = packetHandler::write; + HytaleAssetStore.SETUP_PACKET_CONSUMERS.add(singlePacketConsumer); try { for (AssetStore assetStore : AssetRegistry.getStoreMap().values()) { ((HytaleAssetStore)assetStore).sendAssets(packetConsumer); } } finally { - AssetRegistry.ASSET_LOCK.writeLock().lock(); - - try { - HytaleAssetStore.SETUP_PACKET_CONSUMERS.remove(singlePacketConsumer); - } finally { - AssetRegistry.ASSET_LOCK.writeLock().unlock(); - } + HytaleAssetStore.SETUP_PACKET_CONSUMERS.remove(singlePacketConsumer); } } diff --git a/src/com/hypixel/hytale/server/core/asset/HytaleAssetStore.java b/src/com/hypixel/hytale/server/core/asset/HytaleAssetStore.java index 31dc4a27..66028787 100644 --- a/src/com/hypixel/hytale/server/core/asset/HytaleAssetStore.java +++ b/src/com/hypixel/hytale/server/core/asset/HytaleAssetStore.java @@ -11,7 +11,7 @@ import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.event.EventBus; import com.hypixel.hytale.event.IEventDispatcher; import com.hypixel.hytale.protocol.ItemWithAllMetadata; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.interface_.NotificationStyle; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.Message; @@ -24,15 +24,16 @@ import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.util.NotificationUtil; import com.hypixel.hytale.server.core.util.io.FileUtil; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectList; import java.io.IOException; import java.lang.ref.SoftReference; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.Objects; +import java.util.Queue; import java.util.Set; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.Consumer; import java.util.function.Function; import java.util.logging.Level; @@ -41,11 +42,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class HytaleAssetStore, M extends AssetMap> extends AssetStore { - public static final ObjectList> SETUP_PACKET_CONSUMERS = new ObjectArrayList<>(); + public static final Queue> SETUP_PACKET_CONSUMERS = new ConcurrentLinkedQueue<>(); protected final AssetPacketGenerator packetGenerator; protected final Function notificationItemFunction; @Nullable - protected SoftReference cachedInitPackets; + protected SoftReference cachedInitPackets; public HytaleAssetStore(@Nonnull HytaleAssetStore.Builder builder) { super(builder); @@ -89,21 +90,19 @@ public class HytaleAssetStore, M extends Ass Universe universe = Universe.get(); if (universe.getPlayerCount() != 0 || !SETUP_PACKET_CONSUMERS.isEmpty()) { if (toBeRemoved != null && !toBeRemoved.isEmpty()) { - Packet packet = this.packetGenerator.generateRemovePacket(this.assetMap, toBeRemoved, query); + ToClientPacket packet = this.packetGenerator.generateRemovePacket(this.assetMap, toBeRemoved, query); universe.broadcastPacketNoCache(packet); - for (int i = 0; i < SETUP_PACKET_CONSUMERS.size(); i++) { - Consumer c = SETUP_PACKET_CONSUMERS.get(i); + for (Consumer c : SETUP_PACKET_CONSUMERS) { c.accept(packet); } } if (toBeUpdated != null && !toBeUpdated.isEmpty()) { - Packet packet = this.packetGenerator.generateUpdatePacket(this.assetMap, toBeUpdated, query); + ToClientPacket packet = this.packetGenerator.generateUpdatePacket(this.assetMap, toBeUpdated, query); universe.broadcastPacketNoCache(packet); - for (int i = 0; i < SETUP_PACKET_CONSUMERS.size(); i++) { - Consumer c = SETUP_PACKET_CONSUMERS.get(i); + for (Consumer c : SETUP_PACKET_CONSUMERS) { c.accept(packet); } } @@ -111,15 +110,15 @@ public class HytaleAssetStore, M extends Ass } } - public void sendAssets(@Nonnull Consumer packetConsumer) { + public void sendAssets(@Nonnull Consumer packetConsumer) { if (this.packetGenerator != null) { - Packet[] packets = this.cachedInitPackets == null ? null : this.cachedInitPackets.get(); + ToClientPacket[] packets = this.cachedInitPackets == null ? null : this.cachedInitPackets.get(); if (packets != null) { packetConsumer.accept(packets); } else { Map map = this.assetMap.getAssetMap(); - Packet packet = this.packetGenerator.generateInitPacket(this.assetMap, map); - this.cachedInitPackets = new SoftReference<>(packets = new Packet[]{packet}); + ToClientPacket packet = this.packetGenerator.generateInitPacket(this.assetMap, map); + this.cachedInitPackets = new SoftReference<>(packets = new ToClientPacket[]{packet}); packetConsumer.accept(packets); } } 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..7261563e 100644 --- a/src/com/hypixel/hytale/server/core/asset/common/CommonAssetModule.java +++ b/src/com/hypixel/hytale/server/core/asset/common/CommonAssetModule.java @@ -13,7 +13,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.logger.sentry.SkipSentryException; import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.protocol.Asset; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.interface_.Notification; import com.hypixel.hytale.protocol.packets.interface_.NotificationStyle; import com.hypixel.hytale.protocol.packets.setup.AssetFinalize; @@ -483,7 +483,7 @@ public class CommonAssetModule extends JavaPlugin { CommonAsset thisAsset = toSend.get(i); byte[] allBytes = thisAsset.getBlob().join(); byte[][] parts = ArrayUtil.split(allBytes, 2621440); - Packet[] packets = new Packet[2 + parts.length]; + ToClientPacket[] packets = new ToClientPacket[2 + parts.length]; packets[0] = new AssetInitialize(thisAsset.toPacket(), allBytes.length); for (int partIndex = 0; partIndex < parts.length; partIndex++) { @@ -505,11 +505,15 @@ public class CommonAssetModule extends JavaPlugin { CommonAsset thisAsset = toSend.get(i); byte[] allBytes = thisAsset.getBlob().join(); byte[][] parts = ArrayUtil.split(allBytes, 2621440); - Packet[] packets = new Packet[2 + parts.length * 2]; + ToClientPacket[] packets = new ToClientPacket[2 + parts.length * 2]; 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]); } @@ -528,7 +532,7 @@ public class CommonAssetModule extends JavaPlugin { this.getLogger().at(Level.WARNING).log("Failed to send asset: %s, %s", asset.getName(), asset.getHash()); } else { byte[][] parts = ArrayUtil.split(allBytes, 2621440); - Packet[] packets = new Packet[2 + (forceRebuild ? 1 : 0) + parts.length]; + ToClientPacket[] packets = new ToClientPacket[2 + (forceRebuild ? 1 : 0) + parts.length]; packets[0] = new AssetInitialize(asset.toPacket(), allBytes.length); for (int i = 0; i < parts.length; i++) { @@ -554,7 +558,7 @@ public class CommonAssetModule extends JavaPlugin { Message message = Message.translation("server.general.assetstore.removedAssets").param("class", "Common").color("#FF3874"); int packetCountThreshold = 5; int packetsCount = 1 + (forceRebuild ? 1 : 0) + (assets.size() < 5 ? assets.size() : 1); - Packet[] packets = new Packet[packetsCount]; + ToClientPacket[] packets = new ToClientPacket[packetsCount]; int i = 0; for (CommonAssetRegistry.PackAsset asset : assets) { diff --git a/src/com/hypixel/hytale/server/core/asset/packet/AssetPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/packet/AssetPacketGenerator.java index d0c01fbf..ca9d195f 100644 --- a/src/com/hypixel/hytale/server/core/asset/packet/AssetPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/packet/AssetPacketGenerator.java @@ -3,17 +3,17 @@ package com.hypixel.hytale.server.core.asset.packet; import com.hypixel.hytale.assetstore.AssetMap; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.JsonAssetWithMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class AssetPacketGenerator, M extends AssetMap> { - public abstract Packet generateInitPacket(M var1, Map var2); + public abstract ToClientPacket generateInitPacket(M var1, Map var2); - public abstract Packet generateUpdatePacket(M var1, Map var2, @Nonnull AssetUpdateQuery var3); + public abstract ToClientPacket generateUpdatePacket(M var1, Map var2, @Nonnull AssetUpdateQuery var3); @Nullable - public abstract Packet generateRemovePacket(M var1, Set var2, @Nonnull AssetUpdateQuery var3); + public abstract ToClientPacket generateRemovePacket(M var1, Set var2, @Nonnull AssetUpdateQuery var3); } diff --git a/src/com/hypixel/hytale/server/core/asset/packet/DefaultAssetPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/packet/DefaultAssetPacketGenerator.java index fc9284f9..51a7805e 100644 --- a/src/com/hypixel/hytale/server/core/asset/packet/DefaultAssetPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/packet/DefaultAssetPacketGenerator.java @@ -2,26 +2,26 @@ package com.hypixel.hytale.server.core.asset.packet; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; import com.hypixel.hytale.assetstore.map.JsonAssetWithMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; public abstract class DefaultAssetPacketGenerator>> extends SimpleAssetPacketGenerator> { - public abstract Packet generateInitPacket(DefaultAssetMap var1, Map var2); + public abstract ToClientPacket generateInitPacket(DefaultAssetMap var1, Map var2); - public abstract Packet generateUpdatePacket(Map var1); + public abstract ToClientPacket generateUpdatePacket(Map var1); @Nullable - public abstract Packet generateRemovePacket(Set var1); + public abstract ToClientPacket generateRemovePacket(Set var1); - public final Packet generateUpdatePacket(DefaultAssetMap assetMap, Map loadedAssets) { + public final ToClientPacket generateUpdatePacket(DefaultAssetMap assetMap, Map loadedAssets) { return this.generateUpdatePacket(loadedAssets); } @Nullable - public final Packet generateRemovePacket(DefaultAssetMap assetMap, Set removed) { + public final ToClientPacket generateRemovePacket(DefaultAssetMap assetMap, Set removed) { return this.generateRemovePacket(removed); } } diff --git a/src/com/hypixel/hytale/server/core/asset/packet/SimpleAssetPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/packet/SimpleAssetPacketGenerator.java index fae7f1a6..beaf35b3 100644 --- a/src/com/hypixel/hytale/server/core/asset/packet/SimpleAssetPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/packet/SimpleAssetPacketGenerator.java @@ -3,7 +3,7 @@ package com.hypixel.hytale.server.core.asset.packet; import com.hypixel.hytale.assetstore.AssetMap; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.JsonAssetWithMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; @@ -11,20 +11,20 @@ import javax.annotation.Nullable; public abstract class SimpleAssetPacketGenerator, M extends AssetMap> extends AssetPacketGenerator { @Override - public abstract Packet generateInitPacket(M var1, Map var2); + public abstract ToClientPacket generateInitPacket(M var1, Map var2); @Override - public Packet generateUpdatePacket(M assetMap, Map loadedAssets, @Nonnull AssetUpdateQuery query) { + public ToClientPacket generateUpdatePacket(M assetMap, Map loadedAssets, @Nonnull AssetUpdateQuery query) { return this.generateUpdatePacket(assetMap, loadedAssets); } @Override - public Packet generateRemovePacket(M assetMap, Set removed, @Nonnull AssetUpdateQuery query) { + public ToClientPacket generateRemovePacket(M assetMap, Set removed, @Nonnull AssetUpdateQuery query) { return this.generateRemovePacket(assetMap, removed); } - protected abstract Packet generateUpdatePacket(M var1, Map var2); + protected abstract ToClientPacket generateUpdatePacket(M var1, Map var2); @Nullable - protected abstract Packet generateRemovePacket(M var1, Set var2); + protected abstract ToClientPacket generateRemovePacket(M var1, Set var2); } diff --git a/src/com/hypixel/hytale/server/core/asset/type/ambiencefx/AmbienceFXPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/ambiencefx/AmbienceFXPacketGenerator.java index f690eeb5..f1f45c9d 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/ambiencefx/AmbienceFXPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/ambiencefx/AmbienceFXPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.ambiencefx; import com.hypixel.hytale.assetstore.map.IndexedAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateAmbienceFX; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class AmbienceFXPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Map assets) { UpdateAmbienceFX packet = new UpdateAmbienceFX(); packet.type = UpdateType.Init; packet.ambienceFX = new Object2ObjectOpenHashMap<>(); @@ -34,7 +34,7 @@ public class AmbienceFXPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Map loadedAssets) { UpdateAmbienceFX packet = new UpdateAmbienceFX(); packet.type = UpdateType.AddOrUpdate; packet.ambienceFX = new Object2ObjectOpenHashMap<>(); @@ -54,7 +54,7 @@ public class AmbienceFXPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedAssetMap assetMap, @Nonnull Set removed) { UpdateAmbienceFX packet = new UpdateAmbienceFX(); packet.type = UpdateType.Remove; packet.ambienceFX = new Object2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/audiocategory/AudioCategoryPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/audiocategory/AudioCategoryPacketGenerator.java index 9422f9c0..11aa8805 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/audiocategory/AudioCategoryPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/audiocategory/AudioCategoryPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.audiocategory; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateAudioCategories; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class AudioCategoryPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateAudioCategories packet = new UpdateAudioCategories(); packet.type = UpdateType.Init; packet.categories = new Int2ObjectOpenHashMap<>(assets.size()); @@ -34,7 +34,9 @@ public class AudioCategoryPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets + ) { UpdateAudioCategories packet = new UpdateAudioCategories(); packet.type = UpdateType.AddOrUpdate; packet.categories = new Int2ObjectOpenHashMap<>(loadedAssets.size()); @@ -54,7 +56,7 @@ public class AudioCategoryPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateAudioCategories packet = new UpdateAudioCategories(); packet.type = UpdateType.Remove; packet.categories = new Int2ObjectOpenHashMap<>(removed.size()); diff --git a/src/com/hypixel/hytale/server/core/asset/type/blockbreakingdecal/BlockBreakingDecalPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/blockbreakingdecal/BlockBreakingDecalPacketGenerator.java index 77171d79..85d7ea29 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blockbreakingdecal/BlockBreakingDecalPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blockbreakingdecal/BlockBreakingDecalPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.blockbreakingdecal; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateBlockBreakingDecals; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -17,7 +17,7 @@ import javax.annotation.Nullable; public class BlockBreakingDecalPacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(@Nonnull DefaultAssetMap assetMap, Map assets) { + public ToClientPacket generateInitPacket(@Nonnull DefaultAssetMap assetMap, Map assets) { UpdateBlockBreakingDecals packet = new UpdateBlockBreakingDecals(); packet.type = UpdateType.Init; packet.blockBreakingDecals = assetMap.getAssetMap().entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().toPacket())); @@ -26,7 +26,7 @@ public class BlockBreakingDecalPacketGenerator extends DefaultAssetPacketGenerat @Nonnull @Override - public Packet generateUpdatePacket(@Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map loadedAssets) { UpdateBlockBreakingDecals packet = new UpdateBlockBreakingDecals(); packet.type = UpdateType.AddOrUpdate; packet.blockBreakingDecals = loadedAssets.entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().toPacket())); @@ -35,7 +35,7 @@ public class BlockBreakingDecalPacketGenerator extends DefaultAssetPacketGenerat @Nullable @Override - public Packet generateRemovePacket(@Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull Set removed) { UpdateBlockBreakingDecals packet = new UpdateBlockBreakingDecals(); packet.type = UpdateType.Remove; packet.blockBreakingDecals = new Object2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/blockhitbox/BlockBoundingBoxesPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/blockhitbox/BlockBoundingBoxesPacketGenerator.java index 71af9b7b..c61c5195 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blockhitbox/BlockBoundingBoxesPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blockhitbox/BlockBoundingBoxesPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.asset.type.blockhitbox; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; import com.hypixel.hytale.protocol.Hitbox; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateBlockHitboxes; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -15,7 +15,9 @@ import javax.annotation.Nonnull; public class BlockBoundingBoxesPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets + ) { UpdateBlockHitboxes packet = new UpdateBlockHitboxes(); packet.type = UpdateType.Init; Map hitboxes = new Int2ObjectOpenHashMap<>(); @@ -36,7 +38,7 @@ public class BlockBoundingBoxesPacketGenerator } @Nonnull - public Packet generateUpdatePacket( + public ToClientPacket generateUpdatePacket( @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets ) { UpdateBlockHitboxes packet = new UpdateBlockHitboxes(); @@ -59,7 +61,7 @@ public class BlockBoundingBoxesPacketGenerator } @Nonnull - public Packet generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateBlockHitboxes packet = new UpdateBlockHitboxes(); packet.type = UpdateType.Remove; Map hitboxes = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/blockparticle/BlockParticleSetPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/blockparticle/BlockParticleSetPacketGenerator.java index 9dfb9257..a67b0090 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blockparticle/BlockParticleSetPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blockparticle/BlockParticleSetPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.blockparticle; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateBlockParticleSets; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; public class BlockParticleSetPacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { UpdateBlockParticleSets packet = new UpdateBlockParticleSets(); packet.type = UpdateType.Init; packet.blockParticleSets = new Object2ObjectOpenHashMap<>(); @@ -29,7 +29,7 @@ public class BlockParticleSetPacketGenerator extends DefaultAssetPacketGenerator @Nonnull @Override - public Packet generateUpdatePacket(@Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map loadedAssets) { UpdateBlockParticleSets packet = new UpdateBlockParticleSets(); packet.type = UpdateType.AddOrUpdate; packet.blockParticleSets = new Object2ObjectOpenHashMap<>(); @@ -43,7 +43,7 @@ public class BlockParticleSetPacketGenerator extends DefaultAssetPacketGenerator @Nonnull @Override - public Packet generateRemovePacket(@Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull Set removed) { UpdateBlockParticleSets packet = new UpdateBlockParticleSets(); packet.type = UpdateType.Remove; packet.blockParticleSets = new Object2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/blockset/BlockSetPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/blockset/BlockSetPacketGenerator.java index 78c8d675..dd11a4d8 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blockset/BlockSetPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blockset/BlockSetPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.asset.type.blockset; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateBlockSets; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -17,7 +17,7 @@ import javax.annotation.Nullable; public class BlockSetPacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, Map assets) { UpdateBlockSets packet = new UpdateBlockSets(); packet.type = UpdateType.Init; packet.blockSets = assetMap.getAssetMap().entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().toPacket())); @@ -25,7 +25,7 @@ public class BlockSetPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query ) { UpdateBlockSets packet = new UpdateBlockSets(); @@ -35,7 +35,9 @@ public class BlockSetPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query) { + public ToClientPacket generateRemovePacket( + IndexedLookupTableAssetMap assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query + ) { UpdateBlockSets packet = new UpdateBlockSets(); packet.type = UpdateType.Remove; packet.blockSets = new Object2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocksound/BlockSoundSetPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/blocksound/BlockSoundSetPacketGenerator.java index 552b4d80..7c54d35d 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blocksound/BlockSoundSetPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blocksound/BlockSoundSetPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.blocksound; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateBlockSoundSets; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class BlockSoundSetPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateBlockSoundSets packet = new UpdateBlockSoundSets(); packet.type = UpdateType.Init; packet.blockSoundSets = new Int2ObjectOpenHashMap<>(); @@ -34,7 +34,9 @@ public class BlockSoundSetPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets + ) { UpdateBlockSoundSets packet = new UpdateBlockSoundSets(); packet.type = UpdateType.AddOrUpdate; packet.blockSoundSets = new Int2ObjectOpenHashMap<>(); @@ -54,7 +56,7 @@ public class BlockSoundSetPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateBlockSoundSets packet = new UpdateBlockSoundSets(); packet.type = UpdateType.Remove; packet.blockSoundSets = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocktick/config/RandomTickProcedure.java b/src/com/hypixel/hytale/server/core/asset/type/blocktick/config/RandomTickProcedure.java new file mode 100644 index 00000000..06411d56 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/asset/type/blocktick/config/RandomTickProcedure.java @@ -0,0 +1,14 @@ +package com.hypixel.hytale.server.core.asset.type.blocktick.config; + +import com.hypixel.hytale.codec.lookup.CodecMapCodec; +import com.hypixel.hytale.component.CommandBuffer; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; + +public interface RandomTickProcedure { + CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + + void onRandomTick(Store var1, CommandBuffer var2, BlockSection var3, int var4, int var5, int var6, int var7, BlockType var8); +} diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocktype/BlockGroupPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/blocktype/BlockGroupPacketGenerator.java index c23805ae..6b40a91f 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blocktype/BlockGroupPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blocktype/BlockGroupPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.blocktype; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateBlockGroups; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -17,7 +17,7 @@ import javax.annotation.Nullable; public class BlockGroupPacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(@Nonnull DefaultAssetMap assetMap, Map assets) { + public ToClientPacket generateInitPacket(@Nonnull DefaultAssetMap assetMap, Map assets) { UpdateBlockGroups packet = new UpdateBlockGroups(); packet.type = UpdateType.Init; packet.groups = assetMap.getAssetMap().entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().toPacket())); @@ -26,7 +26,7 @@ public class BlockGroupPacketGenerator extends DefaultAssetPacketGenerator loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map loadedAssets) { UpdateBlockGroups packet = new UpdateBlockGroups(); packet.type = UpdateType.AddOrUpdate; packet.groups = loadedAssets.entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().toPacket())); @@ -35,7 +35,7 @@ public class BlockGroupPacketGenerator extends DefaultAssetPacketGenerator removed) { + public ToClientPacket generateRemovePacket(@Nonnull Set removed) { UpdateBlockGroups packet = new UpdateBlockGroups(); packet.type = UpdateType.Remove; packet.groups = new Object2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocktype/BlockTypePacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/blocktype/BlockTypePacketGenerator.java index cfb86173..be416b1b 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blocktype/BlockTypePacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blocktype/BlockTypePacketGenerator.java @@ -3,7 +3,7 @@ package com.hypixel.hytale.server.core.asset.type.blocktype; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap; import com.hypixel.hytale.protocol.CachedPacket; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateBlockTypes; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -16,7 +16,7 @@ import javax.annotation.Nonnull; public class BlockTypePacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull BlockTypeAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull BlockTypeAssetMap assetMap, @Nonnull Map assets) { UpdateBlockTypes packet = new UpdateBlockTypes(); packet.type = UpdateType.Init; Map blockTypes = new Int2ObjectOpenHashMap<>(); @@ -41,7 +41,7 @@ public class BlockTypePacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query ) { UpdateBlockTypes packet = new UpdateBlockTypes(); @@ -69,7 +69,9 @@ public class BlockTypePacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query) { + public ToClientPacket generateRemovePacket( + @Nonnull BlockTypeAssetMap assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query + ) { UpdateBlockTypes packet = new UpdateBlockTypes(); packet.type = UpdateType.Remove; Map blockTypes = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.java b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.java index 212f540c..a0f8522f 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.java @@ -54,6 +54,8 @@ public class BlockPlacementSettings implements NetworkSerializable placementSettings.ceilingPlacementOverrideBlockId ) .add() + .append(new KeyedCodec<>("AllowBreakReplace", Codec.BOOLEAN), (o, v) -> o.allowBreakReplace = v, o -> o.allowBreakReplace) + .add() .build(); protected String wallPlacementOverrideBlockId; protected String floorPlacementOverrideBlockId; @@ -62,6 +64,7 @@ public class BlockPlacementSettings implements NetworkSerializable (Ljava/lang/String;Ljava/lang/Throwable;)V - // 04d: athrow - // 04e: getstatic com/hypixel/hytale/protocol/BlockPreviewVisibility.Default Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; - // 051: goto 063 - // 054: getstatic com/hypixel/hytale/protocol/BlockPreviewVisibility.Default Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; - // 057: goto 063 - // 05a: getstatic com/hypixel/hytale/protocol/BlockPreviewVisibility.AlwaysHidden Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; - // 05d: goto 063 - // 060: getstatic com/hypixel/hytale/protocol/BlockPreviewVisibility.AlwaysVisible Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; - // 063: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.previewVisibility Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; - // 066: aload 1 - // 067: aload 0 - // 068: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.rotationMode Lcom/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings$RotationMode; - // 06b: astore 2 - // 06c: bipush 0 - // 06d: istore 3 - // 06e: aload 2 - // 06f: iload 3 - // 070: 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;, null.invoke Ljava/lang/Enum$EnumDesc;, null.invoke Ljava/lang/Enum$EnumDesc;, null.invoke Ljava/lang/Enum$EnumDesc; ] - // 075: tableswitch 35 -1 3 45 51 57 63 69 - // 098: new java/lang/MatchException - // 09b: dup - // 09c: aconst_null - // 09d: aconst_null - // 09e: invokespecial java/lang/MatchException. (Ljava/lang/String;Ljava/lang/Throwable;)V - // 0a1: athrow - // 0a2: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.Default Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; - // 0a5: goto 0bd - // 0a8: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.Default Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; - // 0ab: goto 0bd - // 0ae: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.FacingPlayer Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; - // 0b1: goto 0bd - // 0b4: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.StairFacingPlayer Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; - // 0b7: goto 0bd - // 0ba: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.BlockNormal Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; - // 0bd: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.rotationMode Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; - // 0c0: aload 1 - // 0c1: aload 0 - // 0c2: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.wallPlacementOverrideBlockId Ljava/lang/String; - // 0c5: ifnonnull 0cc - // 0c8: bipush -1 - // 0c9: goto 0d6 - // 0cc: invokestatic com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.getAssetMap ()Lcom/hypixel/hytale/assetstore/map/BlockTypeAssetMap; - // 0cf: aload 0 - // 0d0: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.wallPlacementOverrideBlockId Ljava/lang/String; - // 0d3: invokevirtual com/hypixel/hytale/assetstore/map/BlockTypeAssetMap.getIndex (Ljava/lang/Object;)I - // 0d6: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.wallPlacementOverrideBlockId I - // 0d9: aload 1 - // 0da: getfield com/hypixel/hytale/protocol/BlockPlacementSettings.wallPlacementOverrideBlockId I - // 0dd: ldc -2147483648 - // 0df: if_icmpne 0f3 - // 0e2: new java/lang/IllegalArgumentException - // 0e5: dup - // 0e6: aload 0 - // 0e7: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.wallPlacementOverrideBlockId Ljava/lang/String; - // 0ea: invokedynamic makeConcatWithConstants (Ljava/lang/String;)Ljava/lang/String; bsm=java/lang/invoke/StringConcatFactory.makeConcatWithConstants (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; args=[ "Unknown key! \u0001" ] - // 0ef: invokespecial java/lang/IllegalArgumentException. (Ljava/lang/String;)V - // 0f2: athrow - // 0f3: aload 1 - // 0f4: aload 0 - // 0f5: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.floorPlacementOverrideBlockId Ljava/lang/String; - // 0f8: ifnonnull 0ff - // 0fb: bipush -1 - // 0fc: goto 109 - // 0ff: invokestatic com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.getAssetMap ()Lcom/hypixel/hytale/assetstore/map/BlockTypeAssetMap; - // 102: aload 0 - // 103: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.floorPlacementOverrideBlockId Ljava/lang/String; - // 106: invokevirtual com/hypixel/hytale/assetstore/map/BlockTypeAssetMap.getIndex (Ljava/lang/Object;)I - // 109: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.floorPlacementOverrideBlockId I - // 10c: aload 1 - // 10d: getfield com/hypixel/hytale/protocol/BlockPlacementSettings.floorPlacementOverrideBlockId I - // 110: ldc -2147483648 - // 112: if_icmpne 126 - // 115: new java/lang/IllegalArgumentException - // 118: dup - // 119: aload 0 - // 11a: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.floorPlacementOverrideBlockId Ljava/lang/String; - // 11d: invokedynamic makeConcatWithConstants (Ljava/lang/String;)Ljava/lang/String; bsm=java/lang/invoke/StringConcatFactory.makeConcatWithConstants (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; args=[ "Unknown key! \u0001" ] - // 122: invokespecial java/lang/IllegalArgumentException. (Ljava/lang/String;)V - // 125: athrow - // 126: aload 1 - // 127: aload 0 - // 128: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.ceilingPlacementOverrideBlockId Ljava/lang/String; - // 12b: ifnonnull 132 - // 12e: bipush -1 - // 12f: goto 13c - // 132: invokestatic com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.getAssetMap ()Lcom/hypixel/hytale/assetstore/map/BlockTypeAssetMap; - // 135: aload 0 - // 136: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.ceilingPlacementOverrideBlockId Ljava/lang/String; - // 139: invokevirtual com/hypixel/hytale/assetstore/map/BlockTypeAssetMap.getIndex (Ljava/lang/Object;)I - // 13c: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.ceilingPlacementOverrideBlockId I - // 13f: aload 1 - // 140: getfield com/hypixel/hytale/protocol/BlockPlacementSettings.ceilingPlacementOverrideBlockId I - // 143: ldc -2147483648 - // 145: if_icmpne 159 - // 148: new java/lang/IllegalArgumentException - // 14b: dup - // 14c: aload 0 - // 14d: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.ceilingPlacementOverrideBlockId Ljava/lang/String; - // 150: invokedynamic makeConcatWithConstants (Ljava/lang/String;)Ljava/lang/String; bsm=java/lang/invoke/StringConcatFactory.makeConcatWithConstants (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; args=[ "Unknown key! \u0001" ] - // 155: invokespecial java/lang/IllegalArgumentException. (Ljava/lang/String;)V - // 158: athrow - // 159: aload 1 - // 15a: areturn + // 01a: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.allowBreakReplace Z + // 01d: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.allowBreakReplace Z + // 020: aload 1 + // 021: aload 0 + // 022: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.previewVisibility Lcom/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings$BlockPreviewVisibility; + // 025: astore 2 + // 026: bipush 0 + // 027: istore 3 + // 028: aload 2 + // 029: iload 3 + // 02a: 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;, null.invoke Ljava/lang/Enum$EnumDesc;, null.invoke Ljava/lang/Enum$EnumDesc; ] + // 02f: tableswitch 29 -1 2 39 45 51 57 + // 04c: new java/lang/MatchException + // 04f: dup + // 050: aconst_null + // 051: aconst_null + // 052: invokespecial java/lang/MatchException. (Ljava/lang/String;Ljava/lang/Throwable;)V + // 055: athrow + // 056: getstatic com/hypixel/hytale/protocol/BlockPreviewVisibility.Default Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; + // 059: goto 06b + // 05c: getstatic com/hypixel/hytale/protocol/BlockPreviewVisibility.Default Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; + // 05f: goto 06b + // 062: getstatic com/hypixel/hytale/protocol/BlockPreviewVisibility.AlwaysHidden Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; + // 065: goto 06b + // 068: getstatic com/hypixel/hytale/protocol/BlockPreviewVisibility.AlwaysVisible Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; + // 06b: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.previewVisibility Lcom/hypixel/hytale/protocol/BlockPreviewVisibility; + // 06e: aload 1 + // 06f: aload 0 + // 070: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.rotationMode Lcom/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings$RotationMode; + // 073: astore 2 + // 074: bipush 0 + // 075: istore 3 + // 076: aload 2 + // 077: iload 3 + // 078: 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;, null.invoke Ljava/lang/Enum$EnumDesc;, null.invoke Ljava/lang/Enum$EnumDesc;, null.invoke Ljava/lang/Enum$EnumDesc; ] + // 07d: tableswitch 35 -1 3 45 51 57 63 69 + // 0a0: new java/lang/MatchException + // 0a3: dup + // 0a4: aconst_null + // 0a5: aconst_null + // 0a6: invokespecial java/lang/MatchException. (Ljava/lang/String;Ljava/lang/Throwable;)V + // 0a9: athrow + // 0aa: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.Default Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; + // 0ad: goto 0c5 + // 0b0: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.Default Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; + // 0b3: goto 0c5 + // 0b6: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.FacingPlayer Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; + // 0b9: goto 0c5 + // 0bc: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.StairFacingPlayer Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; + // 0bf: goto 0c5 + // 0c2: getstatic com/hypixel/hytale/protocol/BlockPlacementRotationMode.BlockNormal Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; + // 0c5: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.rotationMode Lcom/hypixel/hytale/protocol/BlockPlacementRotationMode; + // 0c8: aload 1 + // 0c9: aload 0 + // 0ca: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.wallPlacementOverrideBlockId Ljava/lang/String; + // 0cd: ifnonnull 0d4 + // 0d0: bipush -1 + // 0d1: goto 0de + // 0d4: invokestatic com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.getAssetMap ()Lcom/hypixel/hytale/assetstore/map/BlockTypeAssetMap; + // 0d7: aload 0 + // 0d8: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.wallPlacementOverrideBlockId Ljava/lang/String; + // 0db: invokevirtual com/hypixel/hytale/assetstore/map/BlockTypeAssetMap.getIndex (Ljava/lang/Object;)I + // 0de: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.wallPlacementOverrideBlockId I + // 0e1: aload 1 + // 0e2: getfield com/hypixel/hytale/protocol/BlockPlacementSettings.wallPlacementOverrideBlockId I + // 0e5: ldc -2147483648 + // 0e7: if_icmpne 0fb + // 0ea: new java/lang/IllegalArgumentException + // 0ed: dup + // 0ee: aload 0 + // 0ef: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.wallPlacementOverrideBlockId Ljava/lang/String; + // 0f2: invokedynamic makeConcatWithConstants (Ljava/lang/String;)Ljava/lang/String; bsm=java/lang/invoke/StringConcatFactory.makeConcatWithConstants (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; args=[ "Unknown key! \u0001" ] + // 0f7: invokespecial java/lang/IllegalArgumentException. (Ljava/lang/String;)V + // 0fa: athrow + // 0fb: aload 1 + // 0fc: aload 0 + // 0fd: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.floorPlacementOverrideBlockId Ljava/lang/String; + // 100: ifnonnull 107 + // 103: bipush -1 + // 104: goto 111 + // 107: invokestatic com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.getAssetMap ()Lcom/hypixel/hytale/assetstore/map/BlockTypeAssetMap; + // 10a: aload 0 + // 10b: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.floorPlacementOverrideBlockId Ljava/lang/String; + // 10e: invokevirtual com/hypixel/hytale/assetstore/map/BlockTypeAssetMap.getIndex (Ljava/lang/Object;)I + // 111: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.floorPlacementOverrideBlockId I + // 114: aload 1 + // 115: getfield com/hypixel/hytale/protocol/BlockPlacementSettings.floorPlacementOverrideBlockId I + // 118: ldc -2147483648 + // 11a: if_icmpne 12e + // 11d: new java/lang/IllegalArgumentException + // 120: dup + // 121: aload 0 + // 122: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.floorPlacementOverrideBlockId Ljava/lang/String; + // 125: invokedynamic makeConcatWithConstants (Ljava/lang/String;)Ljava/lang/String; bsm=java/lang/invoke/StringConcatFactory.makeConcatWithConstants (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; args=[ "Unknown key! \u0001" ] + // 12a: invokespecial java/lang/IllegalArgumentException. (Ljava/lang/String;)V + // 12d: athrow + // 12e: aload 1 + // 12f: aload 0 + // 130: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.ceilingPlacementOverrideBlockId Ljava/lang/String; + // 133: ifnonnull 13a + // 136: bipush -1 + // 137: goto 144 + // 13a: invokestatic com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.getAssetMap ()Lcom/hypixel/hytale/assetstore/map/BlockTypeAssetMap; + // 13d: aload 0 + // 13e: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.ceilingPlacementOverrideBlockId Ljava/lang/String; + // 141: invokevirtual com/hypixel/hytale/assetstore/map/BlockTypeAssetMap.getIndex (Ljava/lang/Object;)I + // 144: putfield com/hypixel/hytale/protocol/BlockPlacementSettings.ceilingPlacementOverrideBlockId I + // 147: aload 1 + // 148: getfield com/hypixel/hytale/protocol/BlockPlacementSettings.ceilingPlacementOverrideBlockId I + // 14b: ldc -2147483648 + // 14d: if_icmpne 161 + // 150: new java/lang/IllegalArgumentException + // 153: dup + // 154: aload 0 + // 155: getfield com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockPlacementSettings.ceilingPlacementOverrideBlockId Ljava/lang/String; + // 158: invokedynamic makeConcatWithConstants (Ljava/lang/String;)Ljava/lang/String; bsm=java/lang/invoke/StringConcatFactory.makeConcatWithConstants (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; args=[ "Unknown key! \u0001" ] + // 15d: invokespecial java/lang/IllegalArgumentException. (Ljava/lang/String;)V + // 160: athrow + // 161: aload 1 + // 162: areturn } public String getWallPlacementOverrideBlockId() { diff --git a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.java b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.java index 30c38a38..6cea1d0f 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.java +++ b/src/com/hypixel/hytale/server/core/asset/type/blocktype/config/BlockType.java @@ -52,6 +52,7 @@ import com.hypixel.hytale.server.core.asset.type.blockbreakingdecal.config.Block import com.hypixel.hytale.server.core.asset.type.blockhitbox.BlockBoundingBoxes; import com.hypixel.hytale.server.core.asset.type.blockparticle.config.BlockParticleSet; import com.hypixel.hytale.server.core.asset.type.blocksound.config.BlockSoundSet; +import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure; import com.hypixel.hytale.server.core.asset.type.blocktick.config.TickProcedure; import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.Bench; import com.hypixel.hytale.server.core.asset.type.blocktype.config.farming.FarmingData; @@ -246,6 +247,13 @@ public class BlockType implements JsonAssetWithMap blockType.tickProcedure = parent.tickProcedure ) .add() + .appendInherited( + new KeyedCodec<>("RandomTickProcedure", RandomTickProcedure.CODEC), + (blockType, v) -> blockType.randomTickProcedure = v, + blockType -> blockType.randomTickProcedure, + (blockType, parent) -> blockType.randomTickProcedure = parent.randomTickProcedure + ) + .add() .appendInherited( new KeyedCodec<>("ConnectedBlockRuleSet", ConnectedBlockRuleSet.CODEC), (blockType, connectedBlockRuleSet) -> blockType.connectedBlockRuleSet = connectedBlockRuleSet, @@ -847,6 +855,7 @@ public class BlockType implements JsonAssetWithMap("Weight", Codec.INTEGER), (customModelTexture, i) -> customModelTexture.weight = i, customModelTexture -> customModelTexture.weight ) + .add() .build(); private String texture; private int weight; 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/buildertool/config/BrushData.java b/src/com/hypixel/hytale/server/core/asset/type/buildertool/config/BrushData.java index 7ffd0f00..f71bede7 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/buildertool/config/BrushData.java +++ b/src/com/hypixel/hytale/server/core/asset/type/buildertool/config/BrushData.java @@ -171,7 +171,7 @@ public class BrushData implements NetworkSerializable { protected IntArg height = new IntArg(5, 1, 100); protected IntArg thickness = new IntArg(0, 0, 100); protected BoolArg capped = new BoolArg(false); - protected BrushShapeArg shape = new BrushShapeArg(BrushShape.Cube); + protected BrushShapeArg shape = new BrushShapeArg(BrushShape.Sphere); protected BrushOriginArg origin = new BrushOriginArg(BrushOrigin.Center); protected BoolArg originRotation = new BoolArg(false); protected BrushAxisArg rotationAxis = new BrushAxisArg(BrushAxis.None); diff --git a/src/com/hypixel/hytale/server/core/asset/type/buildertool/config/PrefabListAsset.java b/src/com/hypixel/hytale/server/core/asset/type/buildertool/config/PrefabListAsset.java index f38af830..cb693f85 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/buildertool/config/PrefabListAsset.java +++ b/src/com/hypixel/hytale/server/core/asset/type/buildertool/config/PrefabListAsset.java @@ -13,6 +13,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.codecs.EnumCodec; import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import com.hypixel.hytale.codec.validation.ValidatorCache; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.server.core.prefab.PrefabStore; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.io.IOException; @@ -126,22 +127,33 @@ public class PrefabListAsset implements JsonAssetWithMap walk = Files.walk(this.rootDirectory.getPrefabPath().resolve(this.unprocessedPrefabPath), this.recursive ? 5 : 1)) { - walk.filter(x$0 -> Files.isRegularFile(x$0)).filter(path -> path.toString().endsWith(".prefab.json")).forEach(this.prefabPaths::add); - } catch (IOException var6) { - PrefabListAsset.getAssetStore() - .getLogger() - .at(Level.SEVERE) - .withCause(var6) - .log("Failed to process prefab path: %s", this.unprocessedPrefabPath); - } - } else { + Path prefabRoot = this.rootDirectory.getPrefabPath(); + if (!this.unprocessedPrefabPath.endsWith("/")) { if (!this.unprocessedPrefabPath.endsWith(".prefab.json")) { this.unprocessedPrefabPath = this.unprocessedPrefabPath + ".prefab.json"; } - this.prefabPaths.add(this.rootDirectory.getPrefabPath().resolve(this.unprocessedPrefabPath)); + Path resolved = PathUtil.resolvePathWithinDir(prefabRoot, this.unprocessedPrefabPath); + if (resolved == null) { + PrefabListAsset.getAssetStore().getLogger().at(Level.SEVERE).log("Invalid prefab path: %s", this.unprocessedPrefabPath); + } else { + this.prefabPaths.add(resolved); + } + } else { + Path resolved = PathUtil.resolvePathWithinDir(prefabRoot, this.unprocessedPrefabPath); + if (resolved == null) { + PrefabListAsset.getAssetStore().getLogger().at(Level.SEVERE).log("Invalid prefab path: %s", this.unprocessedPrefabPath); + } else { + try (Stream walk = Files.walk(resolved, this.recursive ? 5 : 1)) { + walk.filter(x$0 -> Files.isRegularFile(x$0)).filter(path -> path.toString().endsWith(".prefab.json")).forEach(this.prefabPaths::add); + } catch (IOException var8) { + PrefabListAsset.getAssetStore() + .getLogger() + .at(Level.SEVERE) + .withCause(var8) + .log("Failed to process prefab path: %s", this.unprocessedPrefabPath); + } + } } } } diff --git a/src/com/hypixel/hytale/server/core/asset/type/entityeffect/EntityEffectPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/entityeffect/EntityEffectPacketGenerator.java index 87519c61..ee0bb887 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/entityeffect/EntityEffectPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/entityeffect/EntityEffectPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.entityeffect; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateEntityEffects; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class EntityEffectPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateEntityEffects packet = new UpdateEntityEffects(); packet.type = UpdateType.Init; packet.entityEffects = new Int2ObjectOpenHashMap<>(assets.size()); @@ -34,7 +34,9 @@ public class EntityEffectPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + protected ToClientPacket generateUpdatePacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets + ) { UpdateEntityEffects packet = new UpdateEntityEffects(); packet.type = UpdateType.AddOrUpdate; packet.entityEffects = new Int2ObjectOpenHashMap<>(loadedAssets.size()); @@ -54,7 +56,7 @@ public class EntityEffectPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + protected ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateEntityEffects packet = new UpdateEntityEffects(); packet.type = UpdateType.Remove; packet.entityEffects = new Int2ObjectOpenHashMap<>(removed.size()); diff --git a/src/com/hypixel/hytale/server/core/asset/type/entityeffect/config/EntityEffect.java b/src/com/hypixel/hytale/server/core/asset/type/entityeffect/config/EntityEffect.java index 8caca2d7..6442253d 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/entityeffect/config/EntityEffect.java +++ b/src/com/hypixel/hytale/server/core/asset/type/entityeffect/config/EntityEffect.java @@ -192,7 +192,7 @@ public class EntityEffect entityEffect -> entityEffect.locale, (entityEffect, parent) -> entityEffect.locale = parent.locale ) - .documentation("An optional translation key, used to display the damage cause upon death.") + .documentation("[Deprecated - DeathMessageKey instead] Use An optional translation key, used to display the damage cause upon death.") .add() .appendInherited( new KeyedCodec<>("StatusEffectIcon", Codec.STRING), @@ -226,6 +226,14 @@ public class EntityEffect ) .addValidator(DamageCause.VALIDATOR_CACHE.getMapKeyValidator()) .add() + .appendInherited( + new KeyedCodec<>("DeathMessageKey", Codec.STRING), + (entityEffect, s) -> entityEffect.deathMessageKey = s, + entityEffect -> entityEffect.deathMessageKey, + (entityEffect, parent) -> entityEffect.deathMessageKey = parent.deathMessageKey + ) + .documentation("Localization key used on the death screen when this EntityEffect kills a player.") + .add() .afterDecode(entityEffect -> { entityEffect.entityStats = EntityStatsModule.resolveEntityStats(entityEffect.unknownEntityStats); entityEffect.statModifiers = EntityStatsModule.resolveEntityStats(entityEffect.rawStatModifiers); @@ -287,6 +295,7 @@ public class EntityEffect @Nullable protected String locale; protected boolean invulnerable = false; + protected String deathMessageKey; @Nullable protected Map rawStatModifiers; @Nullable @@ -418,6 +427,10 @@ public class EntityEffect return this.damageResistanceValues; } + public String getDeathMessageKey() { + return this.deathMessageKey; + } + @Nonnull public com.hypixel.hytale.protocol.EntityEffect toPacket() { com.hypixel.hytale.protocol.EntityEffect cached = this.cachedPacket == null ? null : this.cachedPacket.get(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/environment/EnvironmentPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/environment/EnvironmentPacketGenerator.java index d591419f..6ad75e57 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/environment/EnvironmentPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/environment/EnvironmentPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.asset.type.environment; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateEnvironments; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; public class EnvironmentPacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { Map assetsFromMap = assetMap.getAssetMap(); if (assets.size() != assetsFromMap.size()) { throw new UnsupportedOperationException("Environments can not handle partial init packets!!!"); @@ -41,7 +41,7 @@ public class EnvironmentPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query ) { UpdateEnvironments packet = new UpdateEnvironments(); @@ -64,7 +64,7 @@ public class EnvironmentPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query ) { UpdateEnvironments packet = new UpdateEnvironments(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/equalizereffect/EqualizerEffectPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/equalizereffect/EqualizerEffectPacketGenerator.java index dc9aad6f..60f9d36f 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/equalizereffect/EqualizerEffectPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/equalizereffect/EqualizerEffectPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.equalizereffect; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateEqualizerEffects; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class EqualizerEffectPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateEqualizerEffects packet = new UpdateEqualizerEffects(); packet.type = UpdateType.Init; packet.effects = new Int2ObjectOpenHashMap<>(assets.size()); @@ -34,7 +34,9 @@ public class EqualizerEffectPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets + ) { UpdateEqualizerEffects packet = new UpdateEqualizerEffects(); packet.type = UpdateType.AddOrUpdate; packet.effects = new Int2ObjectOpenHashMap<>(loadedAssets.size()); @@ -54,7 +56,7 @@ public class EqualizerEffectPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateEqualizerEffects packet = new UpdateEqualizerEffects(); packet.type = UpdateType.Remove; packet.effects = new Int2ObjectOpenHashMap<>(removed.size()); diff --git a/src/com/hypixel/hytale/server/core/asset/type/fluid/DefaultFluidTicker.java b/src/com/hypixel/hytale/server/core/asset/type/fluid/DefaultFluidTicker.java index 4ec56458..299155bf 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/fluid/DefaultFluidTicker.java +++ b/src/com/hypixel/hytale/server/core/asset/type/fluid/DefaultFluidTicker.java @@ -110,7 +110,7 @@ public class DefaultFluidTicker extends FluidTicker { int z = offset.y; int blockX = worldX + x; int blockZ = worldZ + z; - if (!blocksFluidFrom(sourceBlock, sourceRotationIndex, -x, -z, sourceFiller)) { + if (!this.blocksFluidFrom(sourceBlock, sourceRotationIndex, -x, -z, sourceFiller)) { boolean isDifferentSection = !ChunkUtil.isSameChunkSection(worldX, worldY, worldZ, blockX, worldY, blockZ); FluidSection otherFluidSection = isDifferentSection ? accessor.getFluidSectionByBlock(blockX, worldY, blockZ) : fluidSection; BlockSection otherBlockSection = isDifferentSection ? accessor.getBlockSectionByBlock(blockX, worldY, blockZ) : blockSection; @@ -121,7 +121,7 @@ public class DefaultFluidTicker extends FluidTicker { BlockType block = blockMap.getAsset(otherBlockSection.get(blockX, worldY, blockZ)); int rotationIndex = otherBlockSection.getRotationIndex(blockX, worldY, blockZ); int destFiller = otherBlockSection.getFiller(blockX, worldY, blockZ); - if (!blocksFluidFrom(block, rotationIndex, x, z, destFiller)) { + if (!this.blocksFluidFrom(block, rotationIndex, x, z, destFiller)) { int otherFluidId = otherFluidSection.getFluidId(blockX, worldY, blockZ); if (otherFluidId != 0 && otherFluidId != spreadFluidId) { DefaultFluidTicker.FluidCollisionConfig config = this.getCollisionMap().get(otherFluidId); diff --git a/src/com/hypixel/hytale/server/core/asset/type/fluid/FireFluidTicker.java b/src/com/hypixel/hytale/server/core/asset/type/fluid/FireFluidTicker.java new file mode 100644 index 00000000..b9f4046a --- /dev/null +++ b/src/com/hypixel/hytale/server/core/asset/type/fluid/FireFluidTicker.java @@ -0,0 +1,319 @@ +package com.hypixel.hytale.server.core.asset.type.fluid; + +import com.hypixel.hytale.assetstore.AssetExtraInfo; +import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap; +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.util.ChunkUtil; +import com.hypixel.hytale.math.vector.Vector3i; +import com.hypixel.hytale.protocol.SoundCategory; +import com.hypixel.hytale.server.core.asset.type.blocktick.BlockTickStrategy; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; +import com.hypixel.hytale.server.core.asset.type.soundevent.config.SoundEvent; +import com.hypixel.hytale.server.core.asset.type.tagpattern.config.TagPattern; +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.BlockSection; +import com.hypixel.hytale.server.core.universe.world.chunk.section.FluidSection; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntSet; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class FireFluidTicker extends FluidTicker { + public static final BuilderCodec CODEC = BuilderCodec.builder(FireFluidTicker.class, FireFluidTicker::new, BASE_CODEC) + .appendInherited( + new KeyedCodec<>("SpreadFluid", Codec.STRING), + (ticker, o) -> ticker.spreadFluid = o, + ticker -> ticker.spreadFluid, + (ticker, parent) -> ticker.spreadFluid = parent.spreadFluid + ) + .addValidator(Fluid.VALIDATOR_CACHE.getValidator().late()) + .add() + .appendInherited( + new KeyedCodec<>("Flammability", new ArrayCodec<>(FireFluidTicker.FlammabilityConfig.CODEC, FireFluidTicker.FlammabilityConfig[]::new)), + (ticker, o) -> { + List combined = new ArrayList<>(); + if (ticker.rawFlammabilityConfigs != null) { + Collections.addAll(combined, ticker.rawFlammabilityConfigs); + } + + Collections.addAll(combined, o); + ticker.rawFlammabilityConfigs = combined.toArray(new FireFluidTicker.FlammabilityConfig[0]); + }, + ticker -> ticker.rawFlammabilityConfigs, + (ticker, parent) -> ticker.rawFlammabilityConfigs = parent.rawFlammabilityConfigs + ) + .documentation("Defines flammability configs per tag pattern") + .add() + .build(); + public static final FireFluidTicker INSTANCE = new FireFluidTicker(); + private static final Vector3i[] OFFSETS = new Vector3i[]{ + new Vector3i(0, -1, 0), new Vector3i(0, 1, 0), new Vector3i(0, 0, -1), new Vector3i(0, 0, 1), new Vector3i(-1, 0, 0), new Vector3i(1, 0, 0) + }; + private String spreadFluid; + private int spreadFluidId; + private FireFluidTicker.FlammabilityConfig[] rawFlammabilityConfigs = new FireFluidTicker.FlammabilityConfig[0]; + @Nullable + private transient List sortedFlammabilityConfigs = null; + + @Nonnull + @Override + protected FluidTicker.AliveStatus isAlive( + @Nonnull FluidTicker.Accessor accessor, + @Nonnull FluidSection fluidSection, + @Nonnull BlockSection blockSection, + Fluid fluid, + int fluidId, + byte fluidLevel, + int worldX, + int worldY, + int worldZ + ) { + return FluidTicker.AliveStatus.ALIVE; + } + + @Nonnull + @Override + protected BlockTickStrategy spread( + @Nonnull World world, + long tick, + @Nonnull FluidTicker.Accessor accessor, + @Nonnull FluidSection fluidSection, + BlockSection blockSection, + @Nonnull Fluid fluid, + int fluidId, + byte fluidLevel, + int worldX, + int worldY, + int worldZ + ) { + BlockTypeAssetMap blockMap = BlockType.getAssetMap(); + int spreadFluidId = this.getSpreadFluidId(fluidId); + BlockType currentBlock = blockMap.getAsset(blockSection.get(worldX, worldY, worldZ)); + int maxLevel = fluid.getMaxFluidLevel(); + if (fluidLevel < maxLevel) { + fluidSection.setFluid(worldX, worldY, worldZ, fluidId, ++fluidLevel); + } + + for (Vector3i offset : OFFSETS) { + int x = offset.x; + int y = offset.y; + int z = offset.z; + int blockX = worldX + x; + int blockY = worldY + y; + int blockZ = worldZ + z; + if (blockY >= 0 && blockY < 320) { + boolean isDifferentSection = !ChunkUtil.isSameChunkSection(worldX, worldY, worldZ, blockX, blockY, blockZ); + FluidSection otherFluidSection = isDifferentSection ? accessor.getFluidSectionByBlock(blockX, blockY, blockZ) : fluidSection; + BlockSection otherBlockSection = isDifferentSection ? accessor.getBlockSectionByBlock(blockX, blockY, blockZ) : blockSection; + if (otherFluidSection == null || otherBlockSection == null) { + return BlockTickStrategy.WAIT_FOR_ADJACENT_CHUNK_LOAD; + } + + int otherBlockId = otherBlockSection.get(blockX, blockY, blockZ); + BlockType otherBlock = blockMap.getAsset(otherBlockId); + int otherFluidId = otherFluidSection.getFluidId(blockX, blockY, blockZ); + if (otherFluidId == 0) { + boolean isFlammable = this.getFlammabilityForBlock(otherBlock) != null; + if (isFlammable) { + otherFluidSection.setFluid(blockX, blockY, blockZ, spreadFluidId, (byte)1); + otherBlockSection.setTicking(blockX, blockY, blockZ, true); + } + } + } + } + + FireFluidTicker.FlammabilityConfig currentFlammability = this.getFlammabilityForBlock(currentBlock); + if (currentFlammability == null) { + fluidSection.setFluid(worldX, worldY, worldZ, 0, (byte)0); + return BlockTickStrategy.SLEEP; + } else { + ThreadLocalRandom random = ThreadLocalRandom.current(); + if (fluidLevel >= currentFlammability.getBurnLevel() && random.nextFloat() < currentFlammability.getBurnChance()) { + this.tryBurn(world, accessor, fluidSection, blockSection, currentFlammability, worldX, worldY, worldZ); + return BlockTickStrategy.SLEEP; + } else { + return BlockTickStrategy.CONTINUE; + } + } + } + + @Nullable + private FireFluidTicker.FlammabilityConfig getFlammabilityForBlock(@Nonnull BlockType block) { + List configs = this.getSortedFlammabilityConfigs(); + AssetExtraInfo.Data data = block.getData(); + if (data == null) { + return null; + } else { + Int2ObjectMap blockTags = data.getTags(); + + for (FireFluidTicker.FlammabilityConfig config : configs) { + TagPattern tagPattern = config.getTagPattern(); + if (tagPattern != null && tagPattern.test(blockTags)) { + return config; + } + } + + return null; + } + } + + @Override + public boolean canOccupySolidBlocks() { + return true; + } + + private boolean tryBurn( + @Nonnull World world, + @Nonnull FluidTicker.Accessor accessor, + @Nonnull FluidSection fluidSection, + BlockSection blockSection, + @Nonnull FireFluidTicker.FlammabilityConfig config, + int blockX, + int blockY, + int blockZ + ) { + int resultingBlockIndex = config.getResultingBlockIndex(); + if (resultingBlockIndex != Integer.MIN_VALUE) { + int originalRotation = blockSection.getRotationIndex(blockX, blockY, blockZ); + int originalFiller = blockSection.getFiller(blockX, blockY, blockZ); + blockSection.set(blockX, blockY, blockZ, resultingBlockIndex, originalRotation, originalFiller); + setTickingSurrounding(accessor, blockSection, blockX, blockY, blockZ); + } + + int soundEvent = config.getSoundEventIndex(); + if (soundEvent != Integer.MIN_VALUE) { + world.execute(() -> SoundUtil.playSoundEvent3d(soundEvent, SoundCategory.SFX, blockX, blockY, blockZ, world.getEntityStore().getStore())); + } + + fluidSection.setFluid(blockX, blockY, blockZ, 0, (byte)0); + return true; + } + + @Override + public boolean isSelfFluid(int selfFluidId, int otherFluidId) { + return super.isSelfFluid(selfFluidId, otherFluidId) || otherFluidId == this.getSpreadFluidId(selfFluidId); + } + + private int getSpreadFluidId(int fluidId) { + if (this.spreadFluidId == 0) { + if (this.spreadFluid != null) { + this.spreadFluidId = Fluid.getAssetMap().getIndex(this.spreadFluid); + } else { + this.spreadFluidId = Integer.MIN_VALUE; + } + } + + return this.spreadFluidId == Integer.MIN_VALUE ? fluidId : this.spreadFluidId; + } + + @Nonnull + public List getSortedFlammabilityConfigs() { + if (this.sortedFlammabilityConfigs == null) { + List configs = new ArrayList<>(); + if (this.rawFlammabilityConfigs != null) { + Collections.addAll(configs, this.rawFlammabilityConfigs); + } + + configs.sort(Comparator.comparingInt(FireFluidTicker.FlammabilityConfig::getPriority).reversed()); + this.sortedFlammabilityConfigs = configs; + } + + return this.sortedFlammabilityConfigs; + } + + public static class FlammabilityConfig { + public static final BuilderCodec CODEC = BuilderCodec.builder( + FireFluidTicker.FlammabilityConfig.class, FireFluidTicker.FlammabilityConfig::new + ) + .appendInherited( + new KeyedCodec<>("TagPattern", TagPattern.CHILD_ASSET_CODEC), + (o, v) -> o.tagPatternId = v, + o -> o.tagPatternId, + (o, p) -> o.tagPatternId = p.tagPatternId + ) + .addValidator(TagPattern.VALIDATOR_CACHE.getValidator()) + .documentation("TagPattern to match blocks that this config applies to") + .add() + .appendInherited(new KeyedCodec<>("Priority", Codec.INTEGER), (o, v) -> o.priority = v, o -> o.priority, (o, p) -> o.priority = p.priority) + .documentation("Priority for pattern matching - higher values are checked first") + .add() + .appendInherited(new KeyedCodec<>("BurnLevel", Codec.BYTE), (o, v) -> o.burnLevel = v, o -> o.burnLevel, (o, p) -> o.burnLevel = p.burnLevel) + .documentation("The fluid level the fluid has to be greater than or equal to to burn this block") + .add() + .appendInherited( + new KeyedCodec<>("BurnChance", Codec.FLOAT), (o, v) -> o.burnChance = v, o -> o.burnChance, (o, p) -> o.burnChance = p.burnChance + ) + .documentation("Probability (0.0 to 1.0) that the block will burn each tick when above the burn level") + .add() + .appendInherited( + new KeyedCodec<>("ResultingBlock", Codec.STRING), + (o, v) -> o.resultingBlock = v, + o -> o.resultingBlock, + (o, p) -> o.resultingBlock = p.resultingBlock + ) + .documentation("The block to place after burning, if any") + .add() + .appendInherited( + new KeyedCodec<>("SoundEvent", Codec.STRING), (o, v) -> o.soundEvent = v, o -> o.soundEvent, (o, p) -> o.soundEvent = p.soundEvent + ) + .addValidator(SoundEvent.VALIDATOR_CACHE.getValidator()) + .add() + .build(); + private String tagPatternId; + @Nullable + private transient TagPattern tagPattern = null; + private int priority; + private byte burnLevel = 1; + private float burnChance = 0.1F; + private String resultingBlock = "Empty"; + private int resultingBlockIndex = Integer.MIN_VALUE; + private String soundEvent; + private int soundEventIndex = Integer.MIN_VALUE; + + @Nullable + public TagPattern getTagPattern() { + if (this.tagPattern == null && this.tagPatternId != null) { + this.tagPattern = TagPattern.getAssetMap().getAsset(this.tagPatternId); + } + + return this.tagPattern; + } + + public int getPriority() { + return this.priority; + } + + public byte getBurnLevel() { + return this.burnLevel; + } + + public float getBurnChance() { + return this.burnChance; + } + + public int getResultingBlockIndex() { + if (this.resultingBlockIndex == Integer.MIN_VALUE && this.resultingBlock != null) { + this.resultingBlockIndex = BlockType.getBlockIdOrUnknown(this.resultingBlock, "Unknown block type %s", this.resultingBlock); + } + + return this.resultingBlockIndex; + } + + public int getSoundEventIndex() { + if (this.soundEventIndex == Integer.MIN_VALUE && this.soundEvent != null) { + this.soundEventIndex = SoundEvent.getAssetMap().getIndex(this.soundEvent); + } + + return this.soundEventIndex; + } + } +} diff --git a/src/com/hypixel/hytale/server/core/asset/type/fluid/Fluid.java b/src/com/hypixel/hytale/server/core/asset/type/fluid/Fluid.java index 03047785..70dc07ad 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/fluid/Fluid.java +++ b/src/com/hypixel/hytale/server/core/asset/type/fluid/Fluid.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.codecs.EnumCodec; import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import com.hypixel.hytale.codec.codecs.map.EnumMapCodec; +import com.hypixel.hytale.codec.schema.metadata.ui.UIDefaultCollapsedState; import com.hypixel.hytale.codec.schema.metadata.ui.UIEditorSectionStart; import com.hypixel.hytale.codec.schema.metadata.ui.UIPropertyTitle; import com.hypixel.hytale.codec.schema.metadata.ui.UIRebuildCaches; @@ -21,6 +22,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.protocol.BlockTextures; import com.hypixel.hytale.protocol.Color; import com.hypixel.hytale.protocol.ColorLight; +import com.hypixel.hytale.protocol.FluidDrawType; import com.hypixel.hytale.protocol.InteractionType; import com.hypixel.hytale.protocol.Opacity; import com.hypixel.hytale.protocol.ShaderType; @@ -28,6 +30,7 @@ import com.hypixel.hytale.server.core.asset.type.blockparticle.config.BlockParti import com.hypixel.hytale.server.core.asset.type.blocksound.config.BlockSoundSet; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockTypeTextures; import com.hypixel.hytale.server.core.asset.type.fluidfx.config.FluidFX; +import com.hypixel.hytale.server.core.asset.type.model.config.ModelParticle; import com.hypixel.hytale.server.core.codec.ProtocolCodecs; import com.hypixel.hytale.server.core.io.NetworkSerializable; import com.hypixel.hytale.server.core.modules.interaction.interaction.config.InteractionTypeUtils; @@ -61,7 +64,7 @@ public class Fluid implements JsonAssetWithMap fluid.textures, (fluid, parent) -> fluid.textures = parent.textures ) - .metadata(new UIPropertyTitle("Block Textures")) + .metadata(new UIPropertyTitle("Fluid Textures")) .metadata(new UIRebuildCaches(UIRebuildCaches.ClientCache.MODELS, UIRebuildCaches.ClientCache.BLOCK_TEXTURES)) .add() .appendInherited( @@ -72,6 +75,16 @@ public class Fluid implements JsonAssetWithMapappendInherited( + new KeyedCodec<>("DrawType", new EnumCodec<>(FluidDrawType.class)), + (fluid, o) -> fluid.drawType = o, + fluid -> fluid.drawType, + (fluid, parent) -> fluid.drawType = parent.drawType + ) + .addValidator(Validators.nonNull()) + .metadata(new UIRebuildCaches(UIRebuildCaches.ClientCache.MODELS, UIRebuildCaches.ClientCache.BLOCK_TEXTURES, UIRebuildCaches.ClientCache.MODEL_TEXTURES)) + .metadata(new UIEditorSectionStart("Rendering")) + .add() .appendInherited( new KeyedCodec<>("Opacity", new EnumCodec<>(Opacity.class)), (fluid, o) -> fluid.opacity = o, @@ -96,6 +109,18 @@ public class Fluid implements JsonAssetWithMapappendInherited( + new KeyedCodec<>("Particles", ModelParticle.ARRAY_CODEC), + (fluid, s) -> fluid.particles = s, + fluid -> fluid.particles, + (fluid, parent) -> fluid.particles = parent.particles + ) + .documentation("The particles defined here will be spawned on top of fluids of this type placed in the world.") + .metadata(new UIPropertyTitle("Fluid Particles")) + .metadata(new UIRebuildCaches(UIRebuildCaches.ClientCache.MODELS)) + .metadata(UIDefaultCollapsedState.UNCOLLAPSED) + .addValidator(Validators.nonNullArrayElements()) + .add() .appendInherited( new KeyedCodec<>("Ticker", FluidTicker.CODEC), (fluid, o) -> fluid.ticker = o, fluid -> fluid.ticker, (fluid, parent) -> fluid.ticker = parent.ticker ) @@ -195,6 +220,8 @@ public class Fluid implements JsonAssetWithMap 0) { + packet.particles = new com.hypixel.hytale.protocol.ModelParticle[this.particles.length]; + + for (int i = 0; i < this.particles.length; i++) { + packet.particles[i] = this.particles[i].toPacket(); + } + } + + packet.drawType = this.drawType; packet.requiresAlphaBlending = this.requiresAlphaBlending; packet.blockSoundSetIndex = this.blockSoundSetIndex; packet.blockParticleSetId = this.blockParticleSetId; diff --git a/src/com/hypixel/hytale/server/core/asset/type/fluid/FluidTicker.java b/src/com/hypixel/hytale/server/core/asset/type/fluid/FluidTicker.java index 34080fe7..4f7280b5 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/fluid/FluidTicker.java +++ b/src/com/hypixel/hytale/server/core/asset/type/fluid/FluidTicker.java @@ -92,7 +92,7 @@ public abstract class FluidTicker { int worldZ ) { int block = blockSection.get(worldX, worldY, worldZ); - if (isFullySolid(BlockType.getAssetMap().getAsset(block))) { + if (!this.canOccupySolidBlocks() && isFullySolid(BlockType.getAssetMap().getAsset(block))) { fluidSection.setFluid(worldX, worldY, worldZ, 0, (byte)0); setTickingSurrounding(cachedAccessor, blockSection, worldX, worldY, worldZ); return BlockTickStrategy.SLEEP; @@ -107,6 +107,10 @@ public abstract class FluidTicker { } } + public boolean canOccupySolidBlocks() { + return false; + } + public BlockTickStrategy process( World world, long tick, @@ -185,8 +189,8 @@ public abstract class FluidTicker { if (sourceBlock != null) { int sourceRotation = otherBlockSection.getRotationIndex(blockX, worldY, blockZ); int sourceFiller = otherBlockSection.getFiller(blockX, worldY, blockZ); - if (!blocksFluidFrom(sourceBlock, sourceRotation, x, z, sourceFiller) - && !blocksFluidFrom(thisBlock, thisRotation, -x, -z, thisFiller)) { + if (!this.blocksFluidFrom(sourceBlock, sourceRotation, x, z, sourceFiller) + && !this.blocksFluidFrom(thisBlock, thisRotation, -x, -z, thisFiller)) { return FluidTicker.AliveStatus.ALIVE; } } @@ -197,8 +201,8 @@ public abstract class FluidTicker { if (sourceBlock != null) { int sourceRotation = otherBlockSection.getRotationIndex(blockX, worldY, blockZ); int sourceFiller = otherBlockSection.getFiller(blockX, worldY, blockZ); - if (!blocksFluidFrom(sourceBlock, sourceRotation, x, z, sourceFiller) - && !blocksFluidFrom(thisBlock, thisRotation, -x, -z, thisFiller)) { + if (!this.blocksFluidFrom(sourceBlock, sourceRotation, x, z, sourceFiller) + && !this.blocksFluidFrom(thisBlock, thisRotation, -x, -z, thisFiller)) { return FluidTicker.AliveStatus.ALIVE; } } @@ -351,11 +355,11 @@ public abstract class FluidTicker { return drawType == DrawType.Cube || drawType == DrawType.CubeWithModel; } - public static boolean blocksFluidFrom(@Nonnull BlockType blockType, int rotationIndex, int offsetX, int offsetZ) { - return blocksFluidFrom(blockType, rotationIndex, offsetX, offsetZ, 0); + public boolean blocksFluidFrom(@Nonnull BlockType blockType, int rotationIndex, int offsetX, int offsetZ) { + return this.blocksFluidFrom(blockType, rotationIndex, offsetX, offsetZ, 0); } - public static boolean blocksFluidFrom(@Nonnull BlockType blockType, int rotationIndex, int offsetX, int offsetZ, int filler) { + public boolean blocksFluidFrom(@Nonnull BlockType blockType, int rotationIndex, int offsetX, int offsetZ, int filler) { if (blockType.getMaterial() != BlockMaterial.Solid) { return false; } else if (isFullySolid(blockType)) { @@ -503,7 +507,7 @@ public abstract class FluidTicker { void setBlock(int var1, int var2, int var3, int var4); } - protected static enum AliveStatus { + public static enum AliveStatus { ALIVE, DEMOTE, WAIT_FOR_ADJACENT_CHUNK; diff --git a/src/com/hypixel/hytale/server/core/asset/type/fluid/FluidTypePacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/fluid/FluidTypePacketGenerator.java index 76447b32..34893e80 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/fluid/FluidTypePacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/fluid/FluidTypePacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.asset.type.fluid; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateFluids; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class FluidTypePacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateFluids packet = new UpdateFluids(); packet.type = UpdateType.Init; HashMap fluidTypes = new HashMap<>(); @@ -34,7 +34,7 @@ public class FluidTypePacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query ) { UpdateFluids packet = new UpdateFluids(); @@ -56,7 +56,7 @@ public class FluidTypePacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query ) { UpdateFluids packet = new UpdateFluids(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/fluidfx/FluidFXPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/fluidfx/FluidFXPacketGenerator.java index 013f17b8..94944a7e 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/fluidfx/FluidFXPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/fluidfx/FluidFXPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.fluidfx; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateFluidFX; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class FluidFXPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateFluidFX packet = new UpdateFluidFX(); packet.type = UpdateType.Init; packet.fluidFX = new Int2ObjectOpenHashMap<>(); @@ -34,7 +34,7 @@ public class FluidFXPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets) { UpdateFluidFX packet = new UpdateFluidFX(); packet.type = UpdateType.AddOrUpdate; packet.fluidFX = new Int2ObjectOpenHashMap<>(); @@ -54,7 +54,7 @@ public class FluidFXPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateFluidFX packet = new UpdateFluidFX(); packet.type = UpdateType.Remove; packet.fluidFX = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/gameplay/WorldConfig.java b/src/com/hypixel/hytale/server/core/asset/type/gameplay/WorldConfig.java index 457f3cb2..803f64dc 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/gameplay/WorldConfig.java +++ b/src/com/hypixel/hytale/server/core/asset/type/gameplay/WorldConfig.java @@ -3,6 +3,7 @@ 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.sleep.SleepConfig; import javax.annotation.Nonnull; public class WorldConfig { 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/SleepConfig.java b/src/com/hypixel/hytale/server/core/asset/type/gameplay/sleep/SleepConfig.java similarity index 88% rename from src/com/hypixel/hytale/server/core/asset/type/gameplay/SleepConfig.java rename to src/com/hypixel/hytale/server/core/asset/type/gameplay/sleep/SleepConfig.java index 71aec8c8..e927d33d 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/gameplay/SleepConfig.java +++ b/src/com/hypixel/hytale/server/core/asset/type/gameplay/sleep/SleepConfig.java @@ -1,4 +1,4 @@ -package com.hypixel.hytale.server.core.asset.type.gameplay; +package com.hypixel.hytale.server.core.asset.type.gameplay.sleep; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; @@ -22,10 +22,13 @@ public class SleepConfig { .addValidator(Validators.doubleArraySize(2)) .documentation("The in-game hours during which players can sleep to skip to the WakeUpHour. If missing, there is no restriction.") .add() + .append(new KeyedCodec<>("Sounds", SleepSoundsConfig.CODEC), (sleepConfig, i) -> sleepConfig.sounds = i, sleepConfig -> sleepConfig.sounds) + .add() .build(); public static final SleepConfig DEFAULT = new SleepConfig(); private float wakeUpHour = 5.5F; private double[] allowedSleepHoursRange; + private SleepSoundsConfig sounds = new SleepSoundsConfig(); public float getWakeUpHour() { return this.wakeUpHour; @@ -36,6 +39,10 @@ public class SleepConfig { return this.allowedSleepHoursRange; } + public SleepSoundsConfig getSounds() { + return this.sounds; + } + @Nullable public LocalTime getSleepStartTime() { if (this.allowedSleepHoursRange == null) { diff --git a/src/com/hypixel/hytale/server/core/asset/type/gameplay/sleep/SleepSoundsConfig.java b/src/com/hypixel/hytale/server/core/asset/type/gameplay/sleep/SleepSoundsConfig.java new file mode 100644 index 00000000..67b7440f --- /dev/null +++ b/src/com/hypixel/hytale/server/core/asset/type/gameplay/sleep/SleepSoundsConfig.java @@ -0,0 +1,90 @@ +package com.hypixel.hytale.server.core.asset.type.gameplay.sleep; + +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.Nullable; + +public class SleepSoundsConfig { + public static final BuilderCodec CODEC = BuilderCodec.builder(SleepSoundsConfig.class, SleepSoundsConfig::new) + .append(new KeyedCodec<>("Success", Codec.STRING), (config, o) -> config.success = o, config -> config.success) + .addValidator(SoundEvent.VALIDATOR_CACHE.getValidator()) + .add() + .append(new KeyedCodec<>("Fail", Codec.STRING), (config, o) -> config.fail = o, config -> config.fail) + .addValidator(SoundEvent.VALIDATOR_CACHE.getValidator()) + .add() + .append(new KeyedCodec<>("Notification", Codec.STRING), (config, o) -> config.notification = o, config -> config.notification) + .addValidator(SoundEvent.VALIDATOR_CACHE.getValidator()) + .add() + .append(new KeyedCodec<>("NotificationLoop", Codec.STRING), (config, o) -> config.notificationLoop = o, config -> config.notificationLoop) + .addValidator(SoundEvent.VALIDATOR_CACHE.getValidator()) + .add() + .append( + new KeyedCodec<>("NotificationCooldownSeconds", Codec.INTEGER), + (config, o) -> config.notificationCooldownSeconds = o, + config -> config.notificationCooldownSeconds + ) + .add() + .append( + new KeyedCodec<>("NotificationLoopEnabled", Codec.BOOLEAN), + (config, o) -> config.notificationLoopEnabled = o, + config -> config.notificationLoopEnabled + ) + .add() + .build(); + private String success = "SFX_Sleep_Success"; + private String fail = "SFX_Sleep_Fail"; + private String notification = "SFX_Sleep_Notification"; + private String notificationLoop = "SFX_Sleep_Notification_Loop"; + private int notificationCooldownSeconds = 30; + private boolean notificationLoopEnabled = true; + + @Nullable + public String getSuccess() { + return this.success; + } + + public int getSuccessIndex() { + return SoundEvent.getAssetMap().getIndex(this.success); + } + + @Nullable + public String getFail() { + return this.fail; + } + + public int getFailIndex() { + return SoundEvent.getAssetMap().getIndex(this.fail); + } + + @Nullable + public String getNotification() { + return this.notification; + } + + public int getNotificationIndex() { + return SoundEvent.getAssetMap().getIndex(this.notification); + } + + @Nullable + public String getNotificationLoop() { + return this.notificationLoop; + } + + public int getNotificationLoopIndex() { + return SoundEvent.getAssetMap().getIndex(this.notificationLoop); + } + + public long getNotificationCooldownSeconds() { + return this.notificationCooldownSeconds; + } + + public long getNotificationLoopCooldownMs() { + return this.notificationCooldownSeconds * 1000; + } + + public boolean isNotificationLoopEnabled() { + return this.notificationLoopEnabled; + } +} 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/item/FieldcraftCategoryPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/item/FieldcraftCategoryPacketGenerator.java index 624ba0de..0aef093d 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/item/FieldcraftCategoryPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/item/FieldcraftCategoryPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.asset.type.item; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; import com.hypixel.hytale.protocol.ItemCategory; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateFieldcraftCategories; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class FieldcraftCategoryPacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(@Nonnull DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull DefaultAssetMap assetMap, @Nonnull Map assets) { Map assetsFromMap = assetMap.getAssetMap(); if (assets.size() != assetsFromMap.size()) { throw new UnsupportedOperationException("Item categories can not handle partial init packets!!!"); @@ -35,7 +35,7 @@ public class FieldcraftCategoryPacketGenerator extends DefaultAssetPacketGenerat @Nonnull @Override - public Packet generateUpdatePacket(@Nonnull Map assets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map assets) { UpdateFieldcraftCategories packet = new UpdateFieldcraftCategories(); packet.type = UpdateType.AddOrUpdate; ItemCategory[] arr = new ItemCategory[assets.size()]; @@ -50,7 +50,7 @@ public class FieldcraftCategoryPacketGenerator extends DefaultAssetPacketGenerat } @Override - public Packet generateRemovePacket(Set removed) { + public ToClientPacket generateRemovePacket(Set removed) { throw new IllegalArgumentException("We don't support removing item categories at this time!"); } } diff --git a/src/com/hypixel/hytale/server/core/asset/type/item/ItemCategoryPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/item/ItemCategoryPacketGenerator.java index 55c5fe5e..b91dc5b6 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/item/ItemCategoryPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/item/ItemCategoryPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.item; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateItemCategories; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -13,7 +13,7 @@ import javax.annotation.Nonnull; public class ItemCategoryPacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(@Nonnull DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull DefaultAssetMap assetMap, @Nonnull Map assets) { Map assetsFromMap = assetMap.getAssetMap(); if (assets.size() != assetsFromMap.size()) { throw new UnsupportedOperationException("Item categories can not handle partial init packets!!!"); @@ -34,7 +34,7 @@ public class ItemCategoryPacketGenerator extends DefaultAssetPacketGenerator assets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map assets) { UpdateItemCategories packet = new UpdateItemCategories(); packet.type = UpdateType.AddOrUpdate; com.hypixel.hytale.protocol.ItemCategory[] arr = new com.hypixel.hytale.protocol.ItemCategory[assets.size()]; @@ -50,7 +50,7 @@ public class ItemCategoryPacketGenerator extends DefaultAssetPacketGenerator removed) { + public ToClientPacket generateRemovePacket(@Nonnull Set removed) { UpdateItemCategories packet = new UpdateItemCategories(); packet.type = UpdateType.Remove; com.hypixel.hytale.protocol.ItemCategory[] arr = new com.hypixel.hytale.protocol.ItemCategory[removed.size()]; diff --git a/src/com/hypixel/hytale/server/core/asset/type/item/ResourceTypePacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/item/ResourceTypePacketGenerator.java index 38e04222..73c6f515 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/item/ResourceTypePacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/item/ResourceTypePacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.item; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateResourceTypes; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; public class ResourceTypePacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(@Nonnull DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull DefaultAssetMap assetMap, @Nonnull Map assets) { Map assetsFromMap = assetMap.getAssetMap(); if (assets.size() != assetsFromMap.size()) { throw new UnsupportedOperationException("Resource types can not handle partial init packets!!!"); @@ -34,7 +34,7 @@ public class ResourceTypePacketGenerator extends DefaultAssetPacketGenerator loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map loadedAssets) { UpdateResourceTypes packet = new UpdateResourceTypes(); packet.type = UpdateType.AddOrUpdate; packet.resourceTypes = new Object2ObjectOpenHashMap<>(); @@ -48,7 +48,7 @@ public class ResourceTypePacketGenerator extends DefaultAssetPacketGenerator removed) { + public ToClientPacket generateRemovePacket(@Nonnull Set removed) { UpdateResourceTypes packet = new UpdateResourceTypes(); packet.type = UpdateType.Remove; packet.resourceTypes = new Object2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/item/config/CraftingRecipe.java b/src/com/hypixel/hytale/server/core/asset/type/item/config/CraftingRecipe.java index a4231d60..170c42e2 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/item/config/CraftingRecipe.java +++ b/src/com/hypixel/hytale/server/core/asset/type/item/config/CraftingRecipe.java @@ -65,8 +65,12 @@ public class CraftingRecipe implements JsonAssetWithMap benchRequirement.type = benchType, benchRequirement -> benchRequirement.type ) + .addValidator(Validators.nonNull()) .add() - .append(new KeyedCodec<>("Id", Codec.STRING), (benchRequirement, s) -> benchRequirement.id = s, benchRequirement -> benchRequirement.id) + .append( + new KeyedCodec<>("Id", Codec.STRING), (benchRequirement, s) -> benchRequirement.id = s, benchRequirement -> benchRequirement.id + ) + .addValidator(Validators.nonNull()) .add() .append( new KeyedCodec<>("Categories", Codec.STRING_ARRAY), diff --git a/src/com/hypixel/hytale/server/core/asset/type/item/config/Item.java b/src/com/hypixel/hytale/server/core/asset/type/item/config/Item.java index 12892a86..4df97969 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/item/config/Item.java +++ b/src/com/hypixel/hytale/server/core/asset/type/item/config/Item.java @@ -381,6 +381,14 @@ public class Item implements JsonAssetWithMap item.durabilityLossOnHit = parent.durabilityLossOnHit ) .add() + .appendInherited( + new KeyedCodec<>("DurabilityLossOnDeath", Codec.BOOLEAN), + (item, s) -> item.durabilityLossOnDeath = s, + item -> item.durabilityLossOnDeath, + (item, parent) -> item.durabilityLossOnDeath = parent.durabilityLossOnDeath + ) + .documentation("Whether this item should loose durability on death, if so configured in DeathConfig.") + .add() .appendInherited( new KeyedCodec<>("BlockType", new ContainedAssetCodec<>(BlockType.class, BlockType.CODEC, ContainedAssetCodec.Mode.INHERIT_ID_AND_PARENT)), (item, s) -> item.hasBlockType = true, @@ -542,6 +550,7 @@ public class Item implements JsonAssetWithMap cachedPacket; public static AssetStore> getAssetStore() { @@ -990,6 +999,10 @@ public class Item implements JsonAssetWithMap { @Nonnull @Override - public Packet generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { UpdateItemPlayerAnimations packet = new UpdateItemPlayerAnimations(); packet.type = UpdateType.Init; packet.itemPlayerAnimations = new Object2ObjectOpenHashMap<>(assets.size()); @@ -28,7 +28,7 @@ public class ItemPlayerAnimationsPacketGenerator extends DefaultAssetPacketGener @Nonnull @Override - public Packet generateUpdatePacket(@Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map loadedAssets) { UpdateItemPlayerAnimations packet = new UpdateItemPlayerAnimations(); packet.type = UpdateType.AddOrUpdate; packet.itemPlayerAnimations = new Object2ObjectOpenHashMap<>(loadedAssets.size()); @@ -42,7 +42,7 @@ public class ItemPlayerAnimationsPacketGenerator extends DefaultAssetPacketGener @Nonnull @Override - public Packet generateRemovePacket(@Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull Set removed) { UpdateItemPlayerAnimations packet = new UpdateItemPlayerAnimations(); packet.type = UpdateType.Remove; packet.itemPlayerAnimations = new Object2ObjectOpenHashMap<>(removed.size()); diff --git a/src/com/hypixel/hytale/server/core/asset/type/itemsound/ItemSoundSetPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/itemsound/ItemSoundSetPacketGenerator.java index 47ade803..2694f752 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/itemsound/ItemSoundSetPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/itemsound/ItemSoundSetPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.itemsound; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateItemSoundSets; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class ItemSoundSetPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateItemSoundSets packet = new UpdateItemSoundSets(); packet.type = UpdateType.Init; packet.itemSoundSets = new Int2ObjectOpenHashMap<>(); @@ -34,7 +34,9 @@ public class ItemSoundSetPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets + ) { UpdateItemSoundSets packet = new UpdateItemSoundSets(); packet.type = UpdateType.AddOrUpdate; packet.itemSoundSets = new Int2ObjectOpenHashMap<>(); @@ -54,7 +56,7 @@ public class ItemSoundSetPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateItemSoundSets packet = new UpdateItemSoundSets(); packet.type = UpdateType.Remove; packet.itemSoundSets = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/model/config/Model.java b/src/com/hypixel/hytale/server/core/asset/type/model/config/Model.java index ce216c2d..97ffa983 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/model/config/Model.java +++ b/src/com/hypixel/hytale/server/core/asset/type/model/config/Model.java @@ -40,12 +40,18 @@ public class Model implements NetworkSerializable animationSetMap; private final CameraSettings camera; private final ColorLight light; @@ -69,6 +75,8 @@ public class Model implements NetworkSerializable animationSetMap, CameraSettings camera, ColorLight light, @@ -90,6 +98,8 @@ public class Model implements NetworkSerializable map = new Object2ObjectOpenHashMap<>(this.animationSetMap.size()); @@ -241,8 +265,12 @@ public class Model implements NetworkSerializable getAnimationSetMap() { return this.animationSetMap != null ? this.animationSetMap : Collections.emptyMap(); } @@ -350,7 +396,13 @@ public class Model implements NetworkSerializableappend( new KeyedCodec<>("CursedItems", Codec.STRING_ARRAY), (portalType, o) -> portalType.cursedItems = o == null ? Collections.emptySet() : Set.of(o), @@ -65,7 +60,6 @@ public class PortalType implements JsonAssetWithMap cursedItems = Collections.emptySet(); public static AssetStore> getAssetStore() { @@ -96,11 +90,6 @@ public class PortalType implements JsonAssetWithMap getCursedItems() { return this.cursedItems; } diff --git a/src/com/hypixel/hytale/server/core/asset/type/projectile/config/Projectile.java b/src/com/hypixel/hytale/server/core/asset/type/projectile/config/Projectile.java index 0657ef43..483c5262 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/projectile/config/Projectile.java +++ b/src/com/hypixel/hytale/server/core/asset/type/projectile/config/Projectile.java @@ -389,6 +389,7 @@ public class Projectile implements JsonAssetWithMap> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateReverbEffects packet = new UpdateReverbEffects(); packet.type = UpdateType.Init; packet.effects = new Int2ObjectOpenHashMap<>(assets.size()); @@ -34,7 +34,9 @@ public class ReverbEffectPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets + ) { UpdateReverbEffects packet = new UpdateReverbEffects(); packet.type = UpdateType.AddOrUpdate; packet.effects = new Int2ObjectOpenHashMap<>(loadedAssets.size()); @@ -54,7 +56,7 @@ public class ReverbEffectPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateReverbEffects packet = new UpdateReverbEffects(); packet.type = UpdateType.Remove; packet.effects = new Int2ObjectOpenHashMap<>(removed.size()); diff --git a/src/com/hypixel/hytale/server/core/asset/type/soundevent/SoundEventPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/soundevent/SoundEventPacketGenerator.java index c79227a6..8a1258aa 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/soundevent/SoundEventPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/soundevent/SoundEventPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.soundevent; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateSoundEvents; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class SoundEventPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateSoundEvents packet = new UpdateSoundEvents(); packet.type = UpdateType.Init; packet.soundEvents = new Int2ObjectOpenHashMap<>(assets.size()); @@ -34,7 +34,7 @@ public class SoundEventPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets) { UpdateSoundEvents packet = new UpdateSoundEvents(); packet.type = UpdateType.AddOrUpdate; packet.soundEvents = new Int2ObjectOpenHashMap<>(loadedAssets.size()); @@ -54,7 +54,7 @@ public class SoundEventPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateSoundEvents packet = new UpdateSoundEvents(); packet.type = UpdateType.Remove; packet.soundEvents = new Int2ObjectOpenHashMap<>(removed.size()); diff --git a/src/com/hypixel/hytale/server/core/asset/type/soundset/SoundSetPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/soundset/SoundSetPacketGenerator.java index eae4c5a4..5df45032 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/soundset/SoundSetPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/soundset/SoundSetPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.soundset; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateSoundSets; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class SoundSetPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateSoundSets packet = new UpdateSoundSets(); packet.type = UpdateType.Init; packet.soundSets = new Int2ObjectOpenHashMap<>(assets.size()); @@ -34,7 +34,7 @@ public class SoundSetPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets) { UpdateSoundSets packet = new UpdateSoundSets(); packet.type = UpdateType.AddOrUpdate; packet.soundSets = new Int2ObjectOpenHashMap<>(loadedAssets.size()); @@ -54,7 +54,7 @@ public class SoundSetPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateSoundSets packet = new UpdateSoundSets(); packet.type = UpdateType.Remove; packet.soundSets = new Int2ObjectOpenHashMap<>(removed.size()); diff --git a/src/com/hypixel/hytale/server/core/asset/type/tagpattern/TagPatternPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/tagpattern/TagPatternPacketGenerator.java index 4054cfe4..a48a2f79 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/tagpattern/TagPatternPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/tagpattern/TagPatternPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.tagpattern; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateTagPatterns; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class TagPatternPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateTagPatterns packet = new UpdateTagPatterns(); packet.type = UpdateType.Init; packet.patterns = new Int2ObjectOpenHashMap<>(assets.size()); @@ -34,7 +34,7 @@ public class TagPatternPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets) { UpdateTagPatterns packet = new UpdateTagPatterns(); packet.type = UpdateType.AddOrUpdate; packet.patterns = new Int2ObjectOpenHashMap<>(loadedAssets.size()); @@ -54,7 +54,7 @@ public class TagPatternPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateTagPatterns packet = new UpdateTagPatterns(); packet.type = UpdateType.Remove; packet.patterns = new Int2ObjectOpenHashMap<>(removed.size()); diff --git a/src/com/hypixel/hytale/server/core/asset/type/trail/TrailPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/trail/TrailPacketGenerator.java index 16974858..7fe3e5b6 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/trail/TrailPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/trail/TrailPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.trail; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateTrails; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; public class TrailPacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { UpdateTrails packet = new UpdateTrails(); packet.type = UpdateType.Init; packet.trails = new Object2ObjectOpenHashMap<>(); @@ -29,7 +29,7 @@ public class TrailPacketGenerator extends DefaultAssetPacketGenerator loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map loadedAssets) { UpdateTrails packet = new UpdateTrails(); packet.type = UpdateType.AddOrUpdate; packet.trails = new Object2ObjectOpenHashMap<>(); @@ -43,7 +43,7 @@ public class TrailPacketGenerator extends DefaultAssetPacketGenerator removed) { + public ToClientPacket generateRemovePacket(@Nonnull Set removed) { UpdateTrails packet = new UpdateTrails(); packet.type = UpdateType.Remove; packet.trails = new Object2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/weather/WeatherPacketGenerator.java b/src/com/hypixel/hytale/server/core/asset/type/weather/WeatherPacketGenerator.java index 4d024ce9..7a033420 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/weather/WeatherPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/asset/type/weather/WeatherPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.asset.type.weather; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateWeathers; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class WeatherPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateWeathers packet = new UpdateWeathers(); packet.type = UpdateType.Init; packet.weathers = new Int2ObjectOpenHashMap<>(); @@ -34,7 +34,7 @@ public class WeatherPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets) { UpdateWeathers packet = new UpdateWeathers(); packet.type = UpdateType.AddOrUpdate; packet.weathers = new Int2ObjectOpenHashMap<>(); @@ -54,7 +54,7 @@ public class WeatherPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateWeathers packet = new UpdateWeathers(); packet.type = UpdateType.Remove; packet.weathers = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/asset/type/wordlist/WordList.java b/src/com/hypixel/hytale/server/core/asset/type/wordlist/WordList.java index b58d29ed..b740a998 100644 --- a/src/com/hypixel/hytale/server/core/asset/type/wordlist/WordList.java +++ b/src/com/hypixel/hytale/server/core/asset/type/wordlist/WordList.java @@ -43,12 +43,14 @@ public class WordList implements JsonAssetWithMap> ASSET_STORE; + @Nonnull public static final ValidatorCache VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(WordList::getAssetStore)); private static final WordList EMPTY = new WordList(); protected AssetExtraInfo.Data data; protected String id; protected String[] translationKeys; + @Nonnull public static AssetStore> getAssetStore() { if (ASSET_STORE == null) { ASSET_STORE = AssetRegistry.getAssetStore(WordList.class); diff --git a/src/com/hypixel/hytale/server/core/auth/EncryptedAuthCredentialStoreProvider.java b/src/com/hypixel/hytale/server/core/auth/EncryptedAuthCredentialStoreProvider.java index 4d6f7f1c..afbf8526 100644 --- a/src/com/hypixel/hytale/server/core/auth/EncryptedAuthCredentialStoreProvider.java +++ b/src/com/hypixel/hytale/server/core/auth/EncryptedAuthCredentialStoreProvider.java @@ -3,6 +3,7 @@ package com.hypixel.hytale.server.core.auth; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.common.util.PathUtil; import java.nio.file.Path; import javax.annotation.Nonnull; @@ -20,7 +21,12 @@ public class EncryptedAuthCredentialStoreProvider implements AuthCredentialStore @Nonnull @Override public IAuthCredentialStore createStore() { - return new EncryptedAuthCredentialStore(Path.of(this.path)); + Path resolved = Path.of(this.path); + if (!PathUtil.isInTrustedRoot(resolved)) { + throw new IllegalStateException("Auth credential store path must be within a trusted directory: " + this.path); + } else { + return new EncryptedAuthCredentialStore(resolved); + } } @Nonnull 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/AssetsCommand.java b/src/com/hypixel/hytale/server/core/command/commands/debug/AssetsCommand.java index 09d1e29f..6570e091 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/AssetsCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/AssetsCommand.java @@ -21,7 +21,7 @@ public class AssetsCommand extends AbstractCommandCollection { public static class AssetLongestAssetNameCommand extends AbstractAsyncCommand { public AssetLongestAssetNameCommand() { - super("longest", ""); + super("longest", "server.commands.assets.longest.desc"); } @Nonnull @@ -40,7 +40,10 @@ public class AssetsCommand extends AbstractCommandCollection { } context.sendMessage( - Message.raw("Longest asset name for " + e.getKey().getSimpleName() + ": " + longestName + " (" + longestName.length() + " characters)") + Message.translation("server.commands.assets.longest.result") + .param("type", e.getKey().getSimpleName()) + .param("assetName", longestName) + .param("length", longestName.length()) ); } } 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/component/hitboxcollision/HitboxCollisionAddCommand.java b/src/com/hypixel/hytale/server/core/command/commands/debug/component/hitboxcollision/HitboxCollisionAddCommand.java index 86f4595c..a179f86b 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/component/hitboxcollision/HitboxCollisionAddCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/component/hitboxcollision/HitboxCollisionAddCommand.java @@ -38,7 +38,7 @@ public class HitboxCollisionAddCommand extends AbstractCommandCollection { "hitboxCollisionConfig", "server.commands.hitboxcollision.add.hitboxCollisionConfig.desc", ArgTypes.HITBOX_COLLISION_CONFIG ); @Nonnull - private final EntityWrappedArg entityArg = this.withOptionalArg("entity", "server.commands.hitboxcollision.add.entity.desc", ArgTypes.ENTITY_ID); + private final EntityWrappedArg entityArg = this.withOptionalArg("entity", "server.commands.hitboxcollision.add.entityArg.desc", ArgTypes.ENTITY_ID); public HitboxCollisionAddEntityCommand() { super("entity", "server.commands.hitboxcollision.add.entity.desc"); diff --git a/src/com/hypixel/hytale/server/core/command/commands/debug/component/hitboxcollision/HitboxCollisionRemoveCommand.java b/src/com/hypixel/hytale/server/core/command/commands/debug/component/hitboxcollision/HitboxCollisionRemoveCommand.java index 88fe8433..f01eca40 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/component/hitboxcollision/HitboxCollisionRemoveCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/component/hitboxcollision/HitboxCollisionRemoveCommand.java @@ -26,7 +26,7 @@ public class HitboxCollisionRemoveCommand extends AbstractCommandCollection { public static class HitboxCollisionRemoveEntityCommand extends AbstractWorldCommand { @Nonnull - private final EntityWrappedArg entityArg = this.withRequiredArg("entity", "server.commands.hitboxcollision.remove.entity.desc", ArgTypes.ENTITY_ID); + private final EntityWrappedArg entityArg = this.withRequiredArg("entity", "server.commands.hitboxcollision.remove.entityArg.desc", ArgTypes.ENTITY_ID); public HitboxCollisionRemoveEntityCommand() { super("entity", "server.commands.hitboxcollision.remove.entity.desc"); diff --git a/src/com/hypixel/hytale/server/core/command/commands/debug/component/repulsion/RepulsionAddCommand.java b/src/com/hypixel/hytale/server/core/command/commands/debug/component/repulsion/RepulsionAddCommand.java index fcfde07d..e09c8d2b 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/component/repulsion/RepulsionAddCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/component/repulsion/RepulsionAddCommand.java @@ -37,7 +37,7 @@ public class RepulsionAddCommand extends AbstractCommandCollection { "repulsionConfig", "server.commands.repulsion.add.repulsionConfig.desc", ArgTypes.REPULSION_CONFIG ); @Nonnull - private final EntityWrappedArg entityArg = this.withRequiredArg("entity", "server.commands.repulsion.add.entity.desc", ArgTypes.ENTITY_ID); + private final EntityWrappedArg entityArg = this.withRequiredArg("entity", "server.commands.repulsion.add.entityArg.desc", ArgTypes.ENTITY_ID); public RepulsionAddEntityCommand() { super("entity", "server.commands.repulsion.add.entity.desc"); diff --git a/src/com/hypixel/hytale/server/core/command/commands/debug/component/repulsion/RepulsionRemoveCommand.java b/src/com/hypixel/hytale/server/core/command/commands/debug/component/repulsion/RepulsionRemoveCommand.java index e207b8ad..60b39486 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/debug/component/repulsion/RepulsionRemoveCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/debug/component/repulsion/RepulsionRemoveCommand.java @@ -30,7 +30,7 @@ public class RepulsionRemoveCommand extends AbstractCommandCollection { @Nonnull private static final Message MESSAGE_COMMANDS_REPULSION_REMOVE_SUCCESS = Message.translation("server.commands.repulsion.remove.success"); @Nonnull - private final EntityWrappedArg entityArg = this.withRequiredArg("entity", "server.commands.repulsion.remove.entity.desc", ArgTypes.ENTITY_ID); + private final EntityWrappedArg entityArg = this.withRequiredArg("entity", "server.commands.repulsion.remove.entityArg.desc", ArgTypes.ENTITY_ID); public RepulsionRemoveEntityCommand() { super("entity", "server.commands.repulsion.remove.entity.desc"); 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..5c7a7a5f 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 @@ -5,7 +5,6 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3f; import com.hypixel.hytale.protocol.Asset; import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.Direction; import com.hypixel.hytale.protocol.EntityUpdate; import com.hypixel.hytale.protocol.InstantData; @@ -14,6 +13,7 @@ import com.hypixel.hytale.protocol.MovementStates; import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.Position; import com.hypixel.hytale.protocol.TeleportAck; +import com.hypixel.hytale.protocol.TransformUpdate; import com.hypixel.hytale.protocol.io.netty.PacketDecoder; import com.hypixel.hytale.protocol.io.netty.PacketEncoder; import com.hypixel.hytale.protocol.packets.connection.ClientType; @@ -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(-1356075132, 20, "bot", ClientType.Game, uuid, this.name, null, "en", null, null)); this.logger.at(Level.INFO).log("Connected!"); } @@ -239,8 +239,8 @@ public class Bot extends SimpleChannelInboundHandler { } for (ComponentUpdate update : entry.updates) { - if (update.type == ComponentUpdateType.Transform) { - this.updateModelTransform(update.transform); + if (update instanceof TransformUpdate transformUpdate) { + this.updateModelTransform(transformUpdate.transform); break; } } 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/player/camera/CameraDemo.java b/src/com/hypixel/hytale/server/core/command/commands/player/camera/CameraDemo.java index fe98bd03..973a7a31 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/player/camera/CameraDemo.java +++ b/src/com/hypixel/hytale/server/core/command/commands/player/camera/CameraDemo.java @@ -51,7 +51,7 @@ public class CameraDemo { public void deactivate() { if (this.isActive) { - this.eventRegistry.shutdown(); + this.eventRegistry.shutdownAndCleanup(false); Universe.get().getPlayers().forEach(p -> { CameraManager cameraManager = p.getComponent(CameraManager.getComponentType()); if (cameraManager != null) { diff --git a/src/com/hypixel/hytale/server/core/command/commands/player/inventory/GiveCommand.java b/src/com/hypixel/hytale/server/core/command/commands/player/inventory/GiveCommand.java index b0eee4e0..d46d3462 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/player/inventory/GiveCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/player/inventory/GiveCommand.java @@ -66,7 +66,7 @@ public class GiveCommand extends AbstractPlayerCommand { } ItemStack stack = new ItemStack(item.getId(), quantity, metadata).withDurability(durability); - ItemStackTransaction transaction = playerComponent.getInventory().getCombinedHotbarFirst().addItemStack(stack); + ItemStackTransaction transaction = playerComponent.giveItem(stack, ref, store); ItemStack remainder = transaction.getRemainder(); Message itemNameMessage = Message.translation(item.getTranslationKey()); if (remainder != null && !remainder.isEmpty()) { @@ -132,7 +132,7 @@ public class GiveCommand extends AbstractPlayerCommand { } ItemStack stack = new ItemStack(item.getId(), quantity, metadata).withDurability(durability); - ItemStackTransaction transaction = playerComponent.getInventory().getCombinedHotbarFirst().addItemStack(stack); + ItemStackTransaction transaction = playerComponent.giveItem(stack, ref, store); ItemStack remainder = transaction.getRemainder(); Message itemNameMessage = Message.translation(item.getTranslationKey()); if (remainder != null && !remainder.isEmpty()) { diff --git a/src/com/hypixel/hytale/server/core/command/commands/server/auth/AuthStatusCommand.java b/src/com/hypixel/hytale/server/core/command/commands/server/auth/AuthStatusCommand.java index 73217f4a..72f1212f 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/server/auth/AuthStatusCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/server/auth/AuthStatusCommand.java @@ -73,7 +73,7 @@ public class AuthStatusCommand extends CommandBase { Message sessionTokenStatus = authManager.hasSessionToken() ? MESSAGE_STATUS_TOKEN_PRESENT : MESSAGE_STATUS_TOKEN_MISSING; Message identityTokenStatus = authManager.hasIdentityToken() ? MESSAGE_STATUS_TOKEN_PRESENT : MESSAGE_STATUS_TOKEN_MISSING; - String expiryStatus = ""; + Message expiryStatus = Message.empty(); Instant expiry = authManager.getTokenExpiry(); if (expiry != null) { long secondsRemaining = expiry.getEpochSecond() - Instant.now().getEpochSecond(); @@ -81,18 +81,23 @@ public class AuthStatusCommand extends CommandBase { long hours = secondsRemaining / 3600L; long minutes = secondsRemaining % 3600L / 60L; long seconds = secondsRemaining % 60L; - expiryStatus = String.format("%02d:%02d:%02d remaining", hours, minutes, seconds); + expiryStatus = Message.translation("server.commands.auth.status.remaining") + .param("hours", String.format("%02d", hours)) + .param("minutes", String.format("%02d", minutes)) + .param("seconds", String.format("%02d", seconds)); } else { - expiryStatus = "EXPIRED"; + expiryStatus = Message.translation("server.commands.auth.status.expired"); } } - String certificateStatus; + Message certificateStatus; if (authManager.getServerCertificate() != null) { String fingerprint = authManager.getServerCertificateFingerprint(); - certificateStatus = fingerprint != null ? fingerprint.substring(0, 16) + "..." : "Unknown"; + certificateStatus = fingerprint != null + ? Message.raw(fingerprint.substring(0, 16) + "...") + : Message.translation("server.commands.auth.status.certificate.unknown"); } else { - certificateStatus = "Not loaded"; + certificateStatus = Message.translation("server.commands.auth.status.certificate.notLoaded"); } context.sendMessage( diff --git a/src/com/hypixel/hytale/server/core/command/commands/utility/BackupCommand.java b/src/com/hypixel/hytale/server/core/command/commands/utility/BackupCommand.java index 6c45f64d..1db9286c 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/utility/BackupCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/utility/BackupCommand.java @@ -2,7 +2,6 @@ package com.hypixel.hytale.server.core.command.commands.utility; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.Message; -import com.hypixel.hytale.server.core.Options; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncCommand; import com.hypixel.hytale.server.core.universe.Universe; @@ -29,7 +28,7 @@ public class BackupCommand extends AbstractAsyncCommand { if (!HytaleServer.get().isBooted()) { context.sendMessage(MESSAGE_COMMANDS_ERRORS_WAIT_FOR_BOOT); return CompletableFuture.completedFuture(null); - } else if (!Options.getOptionSet().has(Options.BACKUP_DIRECTORY)) { + } else if (HytaleServer.get().getConfig().getBackupConfig().getDirectory() == null) { context.sendMessage(MESSAGE_COMMANDS_BACKUP_NOT_CONFIGURED); return CompletableFuture.completedFuture(null); } else { diff --git a/src/com/hypixel/hytale/server/core/command/commands/utility/ConvertPrefabsCommand.java b/src/com/hypixel/hytale/server/core/command/commands/utility/ConvertPrefabsCommand.java index 32693d02..2c93c756 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/utility/ConvertPrefabsCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/utility/ConvertPrefabsCommand.java @@ -1,5 +1,6 @@ package com.hypixel.hytale.server.core.command.commands.utility; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.command.system.CommandContext; @@ -84,10 +85,15 @@ public class ConvertPrefabsCommand extends AbstractAsyncCommand { String storeOption = this.storeArg.get(context); if (this.pathArg.provided(context)) { Path assetPath = Paths.get(this.pathArg.get(context)); - return this.convertPath(assetPath, blocks, filler, relative, entities, destructive, failed, skipped).thenApply(_v -> { - this.sendCompletionMessages(context, assetPath, failed, skipped); - return null; - }); + if (!PathUtil.isInTrustedRoot(assetPath)) { + context.sendMessage(Message.translation("server.commands.convertprefabs.invalidPath")); + return CompletableFuture.completedFuture(null); + } else { + return this.convertPath(assetPath, blocks, filler, relative, entities, destructive, failed, skipped).thenApply(_v -> { + this.sendCompletionMessages(context, assetPath, failed, skipped); + return null; + }); + } } else { return switch (storeOption) { case "server" -> { diff --git a/src/com/hypixel/hytale/server/core/command/commands/utility/UIGalleryCommand.java b/src/com/hypixel/hytale/server/core/command/commands/utility/UIGalleryCommand.java new file mode 100644 index 00000000..f1efb4a3 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/command/commands/utility/UIGalleryCommand.java @@ -0,0 +1,49 @@ +package com.hypixel.hytale.server.core.command.commands.utility; + +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.protocol.GameMode; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.command.system.CommandContext; +import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncCommand; +import com.hypixel.hytale.server.core.command.system.pages.UIGalleryPage; +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.storage.EntityStore; +import java.util.concurrent.CompletableFuture; +import javax.annotation.Nonnull; + +public class UIGalleryCommand extends AbstractAsyncCommand { + @Nonnull + private static final Message MESSAGE_PLAYER_NOT_IN_WORLD = Message.translation("server.commands.errors.playerNotInWorld"); + + public UIGalleryCommand() { + super("ui-gallery", "server.commands.uigallery.desc"); + this.setPermissionGroup(GameMode.Creative); + } + + @Nonnull + @Override + protected CompletableFuture executeAsync(@Nonnull CommandContext context) { + if (!context.isPlayer()) { + return CompletableFuture.completedFuture(null); + } else { + Ref playerRef = context.senderAsPlayerRef(); + if (playerRef != null && playerRef.isValid()) { + Store store = playerRef.getStore(); + World world = store.getExternalData().getWorld(); + return CompletableFuture.runAsync(() -> { + Player playerComponent = store.getComponent(playerRef, Player.getComponentType()); + PlayerRef playerRefComponent = store.getComponent(playerRef, PlayerRef.getComponentType()); + if (playerComponent != null && playerRefComponent != null) { + playerComponent.getPageManager().openCustomPage(playerRef, store, new UIGalleryPage(playerRefComponent)); + } + }, world); + } else { + context.sendMessage(MESSAGE_PLAYER_NOT_IN_WORLD); + return CompletableFuture.completedFuture(null); + } + } + } +} diff --git a/src/com/hypixel/hytale/server/core/command/commands/utility/ValidateCPBCommand.java b/src/com/hypixel/hytale/server/core/command/commands/utility/ValidateCPBCommand.java index ca7656a0..85c09d4e 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/utility/ValidateCPBCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/utility/ValidateCPBCommand.java @@ -35,8 +35,13 @@ public class ValidateCPBCommand extends AbstractAsyncCommand { @Override protected CompletableFuture executeAsync(@Nonnull CommandContext context) { if (this.pathArg.provided(context)) { - String path = this.pathArg.get(context); - return CompletableFuture.runAsync(() -> convertPrefabs(context, PathUtil.get(path))); + Path assetPath = Path.of(this.pathArg.get(context)); + if (!PathUtil.isInTrustedRoot(assetPath)) { + context.sendMessage(Message.translation("server.commands.validatecpb.invalidPath")); + return CompletableFuture.completedFuture(null); + } else { + return CompletableFuture.runAsync(() -> convertPrefabs(context, assetPath)); + } } else { return CompletableFuture.runAsync(() -> { for (AssetPack pack : AssetModule.get().getAssetPacks()) { diff --git a/src/com/hypixel/hytale/server/core/command/commands/utility/lighting/LightingSendToggleCommand.java b/src/com/hypixel/hytale/server/core/command/commands/utility/lighting/LightingSendToggleCommand.java index c667c5eb..e4aac3d7 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/utility/lighting/LightingSendToggleCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/utility/lighting/LightingSendToggleCommand.java @@ -8,7 +8,6 @@ import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; import com.hypixel.hytale.server.core.command.system.basecommands.AbstractWorldCommand; 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.message.MessageFormat; import java.util.Objects; import java.util.function.BooleanSupplier; import java.util.function.Consumer; @@ -44,6 +43,6 @@ abstract class LightingSendToggleCommand extends AbstractWorldCommand { Boolean enabled = this.enabledArg.provided(context) ? this.enabledArg.get(context) : null; Boolean newValue = Objects.requireNonNullElseGet(enabled, () -> !this.getter.getAsBoolean()); this.setter.accept(newValue); - context.sendMessage(Message.translation(this.statusTranslationKey).param("status", MessageFormat.enabled(newValue))); + context.sendMessage(Message.translation(this.statusTranslationKey).param("enabled", newValue.toString())); } } diff --git a/src/com/hypixel/hytale/server/core/command/commands/utility/net/NetworkCommand.java b/src/com/hypixel/hytale/server/core/command/commands/utility/net/NetworkCommand.java index bc0cd27e..8a003f08 100644 --- a/src/com/hypixel/hytale/server/core/command/commands/utility/net/NetworkCommand.java +++ b/src/com/hypixel/hytale/server/core/command/commands/utility/net/NetworkCommand.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.server.core.command.commands.utility.net; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg; @@ -10,12 +11,17 @@ import com.hypixel.hytale.server.core.command.system.basecommands.AbstractComman import com.hypixel.hytale.server.core.command.system.basecommands.AbstractTargetPlayerCommand; import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase; import com.hypixel.hytale.server.core.entity.knockback.KnockbackSystems; +import com.hypixel.hytale.server.core.io.PacketHandler; import com.hypixel.hytale.server.core.io.netty.LatencySimulationHandler; import com.hypixel.hytale.server.core.modules.entity.player.KnockbackPredictionSystems; 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 io.netty.channel.Channel; +import io.netty.handler.codec.quic.QuicStreamChannel; +import io.netty.handler.codec.quic.QuicStreamPriority; +import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -25,6 +31,7 @@ public class NetworkCommand extends AbstractCommandCollection { super("network", "server.commands.network.desc"); this.addAliases("net"); this.addSubCommand(new NetworkCommand.LatencySimulationCommand()); + this.addSubCommand(new NetworkCommand.StreamPriorityCommand()); this.addSubCommand(new NetworkCommand.ServerKnockbackCommand()); this.addSubCommand(new NetworkCommand.DebugKnockbackCommand()); } @@ -114,4 +121,173 @@ public class NetworkCommand extends AbstractCommandCollection { ); } } + + public static class StreamPriorityCommand extends AbstractCommandCollection { + private static final Map> PRESETS = Map.of( + "default", + PacketHandler.DEFAULT_STREAM_PRIORITIES, + "equal", + priority(0, 0, 0), + "tiered", + priority(0, 1, 2), + "maplow", + priority(0, 0, 1), + "datalow", + priority(0, 1, 1), + "chunkshi", + priority(1, 0, 2), + "maphi", + priority(1, 2, 0) + ); + + public StreamPriorityCommand() { + super("streampriority", "server.commands.network.streamPriority.desc"); + this.addAliases("sp"); + this.addSubCommand(new NetworkCommand.StreamPriorityCommand.Set()); + this.addSubCommand(new NetworkCommand.StreamPriorityCommand.Preset()); + this.addSubCommand(new NetworkCommand.StreamPriorityCommand.Reset()); + } + + private static void applyPriorities(@Nonnull PlayerRef playerRef, @Nonnull Map priorities) { + PacketHandler handler = playerRef.getPacketHandler(); + + for (Entry entry : priorities.entrySet()) { + if (handler.getChannel(entry.getKey()) instanceof QuicStreamChannel quicStreamChannel) { + quicStreamChannel.updatePriority(entry.getValue()); + } + } + } + + private static String formatPriorities(@Nonnull Map priorities) { + StringBuilder sb = new StringBuilder(); + + for (NetworkChannel channel : NetworkChannel.VALUES) { + QuicStreamPriority priority = priorities.get(channel); + if (priority != null) { + if (!sb.isEmpty()) { + sb.append(", "); + } + + sb.append(channel.name()).append('=').append(priority.urgency()); + } + } + + return sb.toString(); + } + + private static Map priority(int defaultUrgency, int chunksUrgency, int worldMapUrgency) { + return Map.of( + NetworkChannel.Default, + new QuicStreamPriority(defaultUrgency, true), + NetworkChannel.Chunks, + new QuicStreamPriority(chunksUrgency, true), + NetworkChannel.WorldMap, + new QuicStreamPriority(worldMapUrgency, true) + ); + } + + static class Preset extends AbstractTargetPlayerCommand { + @Nonnull + private final RequiredArg presetArg = this.withRequiredArg( + "preset", "server.commands.network.streamPriority.preset.name.desc", ArgTypes.STRING + ); + + Preset() { + super("preset", "server.commands.network.streamPriority.preset.desc"); + } + + @Override + protected void execute( + @Nonnull CommandContext context, + @Nullable Ref sourceRef, + @Nonnull Ref ref, + @Nonnull PlayerRef playerRef, + @Nonnull World world, + @Nonnull Store store + ) { + String name = this.presetArg.get(context).toLowerCase(); + Map priorities = NetworkCommand.StreamPriorityCommand.PRESETS.get(name); + if (priorities == null) { + context.sendMessage( + Message.translation("server.commands.network.streamPriority.preset.unknown") + .param("name", name) + .param("presets", String.join(", ", NetworkCommand.StreamPriorityCommand.PRESETS.keySet())) + ); + } else { + NetworkCommand.StreamPriorityCommand.applyPriorities(playerRef, priorities); + context.sendMessage( + Message.translation("server.commands.network.streamPriority.preset.success") + .param("name", name) + .param("priorities", NetworkCommand.StreamPriorityCommand.formatPriorities(priorities)) + ); + } + } + } + + static class Reset extends AbstractTargetPlayerCommand { + Reset() { + super("reset", "server.commands.network.streamPriority.reset.desc"); + } + + @Override + protected void execute( + @Nonnull CommandContext context, + @Nullable Ref sourceRef, + @Nonnull Ref ref, + @Nonnull PlayerRef playerRef, + @Nonnull World world, + @Nonnull Store store + ) { + NetworkCommand.StreamPriorityCommand.applyPriorities(playerRef, PacketHandler.DEFAULT_STREAM_PRIORITIES); + context.sendMessage( + Message.translation("server.commands.network.streamPriority.reset.success") + .param("priorities", NetworkCommand.StreamPriorityCommand.formatPriorities(PacketHandler.DEFAULT_STREAM_PRIORITIES)) + ); + } + } + + static class Set extends AbstractTargetPlayerCommand { + @Nonnull + private final RequiredArg channelArg = this.withRequiredArg( + "channel", + "server.commands.network.streamPriority.set.channel.desc", + ArgTypes.forEnum("server.commands.network.streamPriority.channel", NetworkChannel.class) + ); + @Nonnull + private final RequiredArg priorityArg = this.withRequiredArg( + "priority", "server.commands.network.streamPriority.set.priority.desc", ArgTypes.INTEGER + ); + + Set() { + super("set", "server.commands.network.streamPriority.set.desc"); + } + + @Override + protected void execute( + @Nonnull CommandContext context, + @Nullable Ref sourceRef, + @Nonnull Ref ref, + @Nonnull PlayerRef playerRef, + @Nonnull World world, + @Nonnull Store store + ) { + NetworkChannel networkChannel = this.channelArg.get(context); + int priority = this.priorityArg.get(context); + if (priority >= 0 && priority <= 255) { + if (playerRef.getPacketHandler().getChannel(networkChannel) instanceof QuicStreamChannel quicStreamChannel) { + quicStreamChannel.updatePriority(new QuicStreamPriority(priority, true)); + context.sendMessage( + Message.translation("server.commands.network.streamPriority.set.success") + .param("channel", networkChannel.name()) + .param("priority", priority) + ); + } else { + context.sendMessage(Message.translation("server.commands.network.streamPriority.set.notQuic").param("channel", networkChannel.name())); + } + } else { + context.sendMessage(Message.translation("server.commands.network.streamPriority.set.invalidPriority")); + } + } + } + } } 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/CommandManager.java b/src/com/hypixel/hytale/server/core/command/system/CommandManager.java index de8e480a..f8198931 100644 --- a/src/com/hypixel/hytale/server/core/command/system/CommandManager.java +++ b/src/com/hypixel/hytale/server/core/command/system/CommandManager.java @@ -48,6 +48,7 @@ import com.hypixel.hytale.server.core.command.commands.utility.ConvertPrefabsCom import com.hypixel.hytale.server.core.command.commands.utility.EventTitleCommand; import com.hypixel.hytale.server.core.command.commands.utility.NotifyCommand; import com.hypixel.hytale.server.core.command.commands.utility.StashCommand; +import com.hypixel.hytale.server.core.command.commands.utility.UIGalleryCommand; import com.hypixel.hytale.server.core.command.commands.utility.ValidateCPBCommand; import com.hypixel.hytale.server.core.command.commands.utility.git.GitCommand; import com.hypixel.hytale.server.core.command.commands.utility.help.HelpCommand; @@ -159,6 +160,7 @@ public class CommandManager implements CommandOwner { this.registerSystemCommand(new SleepCommand()); this.registerSystemCommand(new NetworkCommand()); this.registerSystemCommand(new CommandsCommand()); + this.registerSystemCommand(new UIGalleryCommand()); this.registerSystemCommand(new GitCommand()); } diff --git a/src/com/hypixel/hytale/server/core/command/system/arguments/types/ArgTypes.java b/src/com/hypixel/hytale/server/core/command/system/arguments/types/ArgTypes.java index 31ad56e5..3f447fcf 100644 --- a/src/com/hypixel/hytale/server/core/command/system/arguments/types/ArgTypes.java +++ b/src/com/hypixel/hytale/server/core/command/system/arguments/types/ArgTypes.java @@ -654,6 +654,19 @@ public final class ArgTypes { } } }; + public static final ArgumentType> LAYER_ENTRY_TYPE = new MultiArgumentType>( + "Layer Entry Type", "A thickness for a corresponding block pattern", "1 Rock_Stone", "3 50%Rock_Basalt;50%Rock_Stone" + ) { + private final WrappedArgumentType thickness = this.withParameter("thickness", "How thick the layer should be", ArgTypes.INTEGER); + private final WrappedArgumentType blockPattern = this.withParameter( + "blockPattern", "The block pattern to use for the layer. If using with percentages, separate values with a ';'", ArgTypes.STRING + ); + + @Nonnull + public Pair parse(@Nonnull MultiArgumentContext context, ParseResult parseResult) { + return Pair.of(context.get(this.thickness), context.get(this.blockPattern)); + } + }; public static final ArgumentType> WEIGHTED_BLOCK_TYPE = new MultiArgumentType>( "Weighted Block Type", "A weight corresponding to a blocktype", "5 Empty", "20 Rock_Stone", "2 Rock_Shale" ) { 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..46b9b5cb 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 arg = requiredArgs.get(i); commandBuilder.append("#RequiredArgumentsList", "Pages/ParameterItem.ui"); commandBuilder.set("#RequiredArgumentsList[" + i + "] #ParamName.TextSpans", Message.raw(arg.getName())); - commandBuilder.set("#RequiredArgumentsList[" + i + "] #ParamTag.TextSpans", Message.raw("[Required]")); + commandBuilder.set("#RequiredArgumentsList[" + i + "] #ParamTag.TextSpans", Message.translation("server.customUI.commandListPage.required")); commandBuilder.set( "#RequiredArgumentsList[" + i + "] #ParamType.TextSpans", Message.translation("server.customUI.commandListPage.paramType").param("type", arg.getArgumentType().getName()) @@ -586,7 +593,9 @@ public class CommandListPage extends InteractiveCustomUIPage") ); - commandBuilder.set("#OptionalArgumentsList[" + optIndex + "] #ParamTag.TextSpans", Message.raw("[Optional]")); + commandBuilder.set( + "#OptionalArgumentsList[" + optIndex + "] #ParamTag.TextSpans", Message.translation("server.customUI.commandListPage.optional") + ); commandBuilder.set( "#OptionalArgumentsList[" + optIndex + "] #ParamType.TextSpans", Message.translation("server.customUI.commandListPage.paramType").param("type", optArg.getArgumentType().getName()) @@ -605,12 +614,14 @@ public class CommandListPage extends InteractiveCustomUIPage") ); - commandBuilder.set("#DefaultArgumentsList[" + defIndex + "] #ParamTag.TextSpans", Message.raw("[Default]")); + commandBuilder.set( + "#DefaultArgumentsList[" + defIndex + "] #ParamTag.TextSpans", Message.translation("server.customUI.commandListPage.default") + ); commandBuilder.set( "#DefaultArgumentsList[" + defIndex + "] #ParamType.TextSpans", Message.translation("server.customUI.commandListPage.paramTypeDefault") .param("type", defArg.getArgumentType().getName()) - .param("default", defArg.getDefaultValueDescription()) + .param("default", Message.translation(defArg.getDefaultValueDescription())) ); commandBuilder.set( "#DefaultArgumentsList[" + defIndex + "] #ParamDescription.TextSpans", @@ -623,7 +634,7 @@ public class CommandListPage extends InteractiveCustomUIPage { + private static final Value CATEGORY_BUTTON_STYLE = Value.ref("Pages/UIGallery/CategoryButton.ui", "LabelStyle"); + private static final Value CATEGORY_BUTTON_SELECTED_STYLE = Value.ref("Pages/UIGallery/CategoryButton.ui", "SelectedLabelStyle"); + private UIGalleryPage.Category selectedCategory = UIGalleryPage.Category.BUTTONS; + private final IntSet expandedCodeBlocks = new IntOpenHashSet(); + + public UIGalleryPage(@Nonnull PlayerRef playerRef) { + super(playerRef, CustomPageLifetime.CanDismiss, UIGalleryPage.UIGalleryEventData.CODEC); + } + + @Override + public void build( + @Nonnull Ref ref, @Nonnull UICommandBuilder commandBuilder, @Nonnull UIEventBuilder eventBuilder, @Nonnull Store store + ) { + commandBuilder.append("Pages/UIGallery/UIGalleryPage.ui"); + this.buildCategoryList(commandBuilder, eventBuilder); + this.displayCategory(this.selectedCategory, commandBuilder, eventBuilder); + } + + public void handleDataEvent(@Nonnull Ref ref, @Nonnull Store store, @Nonnull UIGalleryPage.UIGalleryEventData data) { + UICommandBuilder commandBuilder = new UICommandBuilder(); + UIEventBuilder eventBuilder = new UIEventBuilder(); + if (data.category != null) { + UIGalleryPage.Category newCategory = UIGalleryPage.Category.fromId(data.category); + if (newCategory != this.selectedCategory) { + int oldIndex = this.selectedCategory.ordinal(); + commandBuilder.set("#CategoryList[" + oldIndex + "].Style", CATEGORY_BUTTON_STYLE); + int newIndex = newCategory.ordinal(); + commandBuilder.set("#CategoryList[" + newIndex + "].Style", CATEGORY_BUTTON_SELECTED_STYLE); + this.expandedCodeBlocks.clear(); + this.selectedCategory = newCategory; + this.displayCategory(this.selectedCategory, commandBuilder, eventBuilder); + } + + this.sendUpdate(commandBuilder, eventBuilder, false); + } else if (data.toggleCode != null) { + try { + int codeIndex = Integer.parseInt(data.toggleCode); + this.toggleCodeBlock(codeIndex, commandBuilder); + this.sendUpdate(commandBuilder, eventBuilder, false); + } catch (NumberFormatException var9) { + } + } + } + + private void buildCategoryList(@Nonnull UICommandBuilder commandBuilder, @Nonnull UIEventBuilder eventBuilder) { + commandBuilder.clear("#CategoryList"); + + for (int i = 0; i < UIGalleryPage.Category.values().length; i++) { + UIGalleryPage.Category category = UIGalleryPage.Category.values()[i]; + commandBuilder.append("#CategoryList", "Pages/UIGallery/CategoryButton.ui"); + commandBuilder.set("#CategoryList[" + i + "].TextSpans", Message.translation(category.getNameKey())); + if (category == this.selectedCategory) { + commandBuilder.set("#CategoryList[" + i + "].Style", CATEGORY_BUTTON_SELECTED_STYLE); + } + + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#CategoryList[" + i + "]", EventData.of("Category", category.getId())); + } + } + + private void displayCategory(@Nonnull UIGalleryPage.Category category, @Nonnull UICommandBuilder commandBuilder, @Nonnull UIEventBuilder eventBuilder) { + commandBuilder.set("#CategoryTitle.TextSpans", Message.translation(category.getNameKey())); + commandBuilder.set("#CategoryDescription.TextSpans", Message.translation(category.getDescriptionKey())); + commandBuilder.clear("#CategoryContent"); + commandBuilder.append("#CategoryContent", category.getContentPath()); + + for (int i = 0; i < category.getCodeBlockCount(); i++) { + String selector = "#CategoryContent #Code" + i + " #ToggleCode"; + eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, selector, EventData.of("ToggleCode", String.valueOf(i))); + } + } + + private void toggleCodeBlock(int index, @Nonnull UICommandBuilder commandBuilder) { + String containerSelector = "#CategoryContent #Code" + index + " #CodeContainer"; + String buttonSelector = "#CategoryContent #Code" + index + " #ToggleCode"; + if (this.expandedCodeBlocks.contains(index)) { + this.expandedCodeBlocks.remove(index); + commandBuilder.set(containerSelector + ".Visible", false); + commandBuilder.set(buttonSelector + ".TextSpans", Message.raw("Show Code")); + } else { + this.expandedCodeBlocks.add(index); + commandBuilder.set(containerSelector + ".Visible", true); + commandBuilder.set(buttonSelector + ".TextSpans", Message.raw("Hide Code")); + } + } + + private static enum Category { + BUTTONS( + "buttons", + "server.customUI.uiGallery.category.buttons", + "server.customUI.uiGallery.category.buttons.desc", + "Pages/UIGallery/Categories/ButtonsContent.ui", + 7 + ), + INPUTS( + "inputs", + "server.customUI.uiGallery.category.inputs", + "server.customUI.uiGallery.category.inputs.desc", + "Pages/UIGallery/Categories/InputsContent.ui", + 4 + ), + SELECTION( + "selection", + "server.customUI.uiGallery.category.selection", + "server.customUI.uiGallery.category.selection.desc", + "Pages/UIGallery/Categories/SelectionContent.ui", + 4 + ), + CONTAINERS( + "containers", + "server.customUI.uiGallery.category.containers", + "server.customUI.uiGallery.category.containers.desc", + "Pages/UIGallery/Categories/ContainersContent.ui", + 7 + ), + TEXT("text", "server.customUI.uiGallery.category.text", "server.customUI.uiGallery.category.text.desc", "Pages/UIGallery/Categories/TextContent.ui", 3), + SLIDERS( + "sliders", + "server.customUI.uiGallery.category.sliders", + "server.customUI.uiGallery.category.sliders.desc", + "Pages/UIGallery/Categories/SlidersContent.ui", + 3 + ), + PROGRESS( + "progress", + "server.customUI.uiGallery.category.progress", + "server.customUI.uiGallery.category.progress.desc", + "Pages/UIGallery/Categories/ProgressContent.ui", + 3 + ), + SCROLLBARS( + "scrollbars", + "server.customUI.uiGallery.category.scrollbars", + "server.customUI.uiGallery.category.scrollbars.desc", + "Pages/UIGallery/Categories/ScrollbarsContent.ui", + 3 + ), + NAVIGATION( + "navigation", + "server.customUI.uiGallery.category.navigation", + "server.customUI.uiGallery.category.navigation.desc", + "Pages/UIGallery/Categories/NavigationContent.ui", + 2 + ), + TOOLTIPS( + "tooltips", + "server.customUI.uiGallery.category.tooltips", + "server.customUI.uiGallery.category.tooltips.desc", + "Pages/UIGallery/Categories/TooltipsContent.ui", + 2 + ); + + private final String id; + private final String nameKey; + private final String descriptionKey; + private final String contentPath; + private final int codeBlockCount; + + private Category(String id, String nameKey, String descriptionKey, String contentPath, int codeBlockCount) { + this.id = id; + this.nameKey = nameKey; + this.descriptionKey = descriptionKey; + this.contentPath = contentPath; + this.codeBlockCount = codeBlockCount; + } + + public String getId() { + return this.id; + } + + public String getNameKey() { + return this.nameKey; + } + + public String getDescriptionKey() { + return this.descriptionKey; + } + + public String getContentPath() { + return this.contentPath; + } + + public int getCodeBlockCount() { + return this.codeBlockCount; + } + + public static UIGalleryPage.Category fromId(String id) { + for (UIGalleryPage.Category category : values()) { + if (category.id.equals(id)) { + return category; + } + } + + return BUTTONS; + } + } + + public static class UIGalleryEventData { + static final String KEY_CATEGORY = "Category"; + static final String KEY_TOGGLE_CODE = "ToggleCode"; + public static final BuilderCodec CODEC = BuilderCodec.builder( + UIGalleryPage.UIGalleryEventData.class, UIGalleryPage.UIGalleryEventData::new + ) + .addField(new KeyedCodec<>("Category", Codec.STRING), (entry, s) -> entry.category = s, entry -> entry.category) + .addField(new KeyedCodec<>("ToggleCode", Codec.STRING), (entry, s) -> entry.toggleCode = s, entry -> entry.toggleCode) + .build(); + private String category; + private String toggleCode; + } +} diff --git a/src/com/hypixel/hytale/server/core/config/BackupConfig.java b/src/com/hypixel/hytale/server/core/config/BackupConfig.java new file mode 100644 index 00000000..cea5c53a --- /dev/null +++ b/src/com/hypixel/hytale/server/core/config/BackupConfig.java @@ -0,0 +1,172 @@ +package com.hypixel.hytale.server.core.config; + +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.codec.validation.Validators; +import com.hypixel.hytale.server.core.HytaleServerConfig; +import com.hypixel.hytale.server.core.Options; +import java.nio.file.Path; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import joptsimple.OptionSet; + +public class BackupConfig { + public static final int DEFAULT_FREQUENCY_MINUTES = 30; + public static final int DEFAULT_MAX_COUNT = 5; + public static final int DEFAULT_ARCHIVE_MAX_COUNT = 5; + @Nonnull + public static final Codec CODEC = BuilderCodec.builder(BackupConfig.class, BackupConfig::new) + .append(new KeyedCodec<>("Enabled", Codec.BOOLEAN), (o, b) -> o.enabled = b, o -> o.enabled) + .documentation("Determines whether automatic backups are enabled. Can be overridden by the --backup CLI option.") + .add() + .append(new KeyedCodec<>("FrequencyMinutes", Codec.INTEGER), (o, i) -> o.frequencyMinutes = i, o -> o.frequencyMinutes) + .addValidator(Validators.greaterThan(0)) + .documentation("The backup frequency in minutes. Must be at least 1. Can be overridden by the --backup-frequency CLI option.") + .add() + .append(new KeyedCodec<>("Directory", Codec.STRING), (o, s) -> o.directory = s, o -> o.directory) + .addValidator(Validators.nonEmptyString()) + .documentation("The backup directory path. Can be overridden by the --backup-directory CLI option.") + .add() + .append(new KeyedCodec<>("MaxCount", Codec.INTEGER), (o, i) -> o.maxCount = i, o -> o.maxCount) + .addValidator(Validators.greaterThan(0)) + .documentation("The maximum number of recent backups to retain. Must be at least 1. Can be overridden by the --backup-max-count CLI option.") + .add() + .append(new KeyedCodec<>("ArchiveMaxCount", Codec.INTEGER), (o, i) -> o.archiveMaxCount = i, o -> o.archiveMaxCount) + .addValidator(Validators.greaterThan(0)) + .documentation("The maximum number of archived backups to retain. Must be at least 1. Can be overridden by the --backup-archive-max-count CLI option.") + .add() + .build(); + @Nullable + private Boolean enabled; + @Nullable + private Integer frequencyMinutes; + @Nullable + private String directory; + @Nullable + private Integer maxCount; + @Nullable + private Integer archiveMaxCount; + @Nullable + transient HytaleServerConfig hytaleServerConfig; + + public BackupConfig() { + } + + public BackupConfig(@Nonnull HytaleServerConfig hytaleServerConfig) { + this.hytaleServerConfig = hytaleServerConfig; + } + + public void setHytaleServerConfig(@Nonnull HytaleServerConfig hytaleServerConfig) { + this.hytaleServerConfig = hytaleServerConfig; + } + + public boolean isEnabled() { + if (Options.getOptionSet().has(Options.BACKUP)) { + return true; + } else { + return this.enabled != null ? this.enabled : false; + } + } + + @Nullable + public Boolean getEnabledConfig() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public int getFrequencyMinutes() { + OptionSet optionSet = Options.getOptionSet(); + if (optionSet.has(Options.BACKUP_FREQUENCY_MINUTES)) { + return Math.max(optionSet.valueOf(Options.BACKUP_FREQUENCY_MINUTES), 1); + } else { + return this.frequencyMinutes != null ? Math.max(this.frequencyMinutes, 1) : 30; + } + } + + @Nullable + public Integer getFrequencyMinutesConfig() { + return this.frequencyMinutes; + } + + public void setFrequencyMinutes(int frequencyMinutes) { + this.frequencyMinutes = frequencyMinutes; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + @Nullable + public Path getDirectory() { + OptionSet optionSet = Options.getOptionSet(); + if (optionSet.has(Options.BACKUP_DIRECTORY)) { + return optionSet.valueOf(Options.BACKUP_DIRECTORY); + } else { + return this.directory != null ? Path.of(this.directory) : null; + } + } + + @Nullable + public String getDirectoryConfig() { + return this.directory; + } + + public void setDirectory(@Nullable String directory) { + this.directory = directory; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public int getMaxCount() { + OptionSet optionSet = Options.getOptionSet(); + if (optionSet.has(Options.BACKUP_MAX_COUNT)) { + return optionSet.valueOf(Options.BACKUP_MAX_COUNT); + } else { + return this.maxCount != null ? this.maxCount : 5; + } + } + + @Nullable + public Integer getMaxCountConfig() { + return this.maxCount; + } + + public void setMaxCount(int maxCount) { + this.maxCount = maxCount; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public int getArchiveMaxCount() { + OptionSet optionSet = Options.getOptionSet(); + if (optionSet.has(Options.BACKUP_ARCHIVE_MAX_COUNT)) { + return optionSet.valueOf(Options.BACKUP_ARCHIVE_MAX_COUNT); + } else { + return this.archiveMaxCount != null ? this.archiveMaxCount : 5; + } + } + + @Nullable + public Integer getArchiveMaxCountConfig() { + return this.archiveMaxCount; + } + + public void setArchiveMaxCount(int archiveMaxCount) { + this.archiveMaxCount = archiveMaxCount; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public boolean isConfigured() { + return this.isEnabled() && this.getDirectory() != null; + } +} diff --git a/src/com/hypixel/hytale/server/core/config/ModConfig.java b/src/com/hypixel/hytale/server/core/config/ModConfig.java new file mode 100644 index 00000000..1728bab4 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/config/ModConfig.java @@ -0,0 +1,46 @@ +package com.hypixel.hytale.server.core.config; + +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.common.semver.SemverRange; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ModConfig { + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder(ModConfig.class, ModConfig::new) + .append(new KeyedCodec<>("Enabled", Codec.BOOLEAN), (modConfig, enabled) -> modConfig.enabled = enabled, modConfig -> modConfig.enabled) + .documentation("Determines whether the mod/plugin is enabled.") + .add() + .append( + new KeyedCodec<>("RequiredVersion", SemverRange.CODEC), + (modConfig, semverRange) -> modConfig.requiredVersion = semverRange, + modConfig -> modConfig.requiredVersion + ) + .documentation("The required version range for the mod/plugin.") + .add() + .build(); + @Nullable + private Boolean enabled; + @Nullable + private SemverRange requiredVersion; + + @Nullable + public Boolean getEnabled() { + return this.enabled; + } + + public void setEnabled(@Nonnull Boolean enabled) { + this.enabled = enabled; + } + + @Nullable + public SemverRange getRequiredVersion() { + return this.requiredVersion; + } + + public void setRequiredVersion(@Nonnull SemverRange requiredVersion) { + this.requiredVersion = requiredVersion; + } +} diff --git a/src/com/hypixel/hytale/server/core/config/RateLimitConfig.java b/src/com/hypixel/hytale/server/core/config/RateLimitConfig.java new file mode 100644 index 00000000..d749f597 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/config/RateLimitConfig.java @@ -0,0 +1,74 @@ +package com.hypixel.hytale.server.core.config; + +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.HytaleServerConfig; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class RateLimitConfig { + public static final int DEFAULT_PACKETS_PER_SECOND = 2000; + public static final int DEFAULT_BURST_CAPACITY = 500; + @Nonnull + public static final Codec CODEC = BuilderCodec.builder(RateLimitConfig.class, RateLimitConfig::new) + .append(new KeyedCodec<>("Enabled", Codec.BOOLEAN), (o, b) -> o.enabled = b, o -> o.enabled) + .documentation("Determines whether packet rate limiting is enabled.") + .add() + .append(new KeyedCodec<>("PacketsPerSecond", Codec.INTEGER), (o, i) -> o.packetsPerSecond = i, o -> o.packetsPerSecond) + .documentation("The number of packets allowed per second.") + .add() + .append(new KeyedCodec<>("BurstCapacity", Codec.INTEGER), (o, i) -> o.burstCapacity = i, o -> o.burstCapacity) + .documentation("The number of packets that can be sent in a burst before rate limiting is applied.") + .add() + .build(); + private Boolean enabled; + private Integer packetsPerSecond; + private Integer burstCapacity; + @Nullable + transient HytaleServerConfig hytaleServerConfig; + + public RateLimitConfig() { + } + + public RateLimitConfig(@Nonnull HytaleServerConfig hytaleServerConfig) { + this.hytaleServerConfig = hytaleServerConfig; + } + + public void setHytaleServerConfig(@Nonnull HytaleServerConfig hytaleServerConfig) { + this.hytaleServerConfig = hytaleServerConfig; + } + + public boolean isEnabled() { + return this.enabled != null ? this.enabled : true; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public int getPacketsPerSecond() { + return this.packetsPerSecond != null ? this.packetsPerSecond : 2000; + } + + public void setPacketsPerSecond(int packetsPerSecond) { + this.packetsPerSecond = packetsPerSecond; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public int getBurstCapacity() { + return this.burstCapacity != null ? this.burstCapacity : 500; + } + + public void setBurstCapacity(int burstCapacity) { + this.burstCapacity = burstCapacity; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } +} diff --git a/src/com/hypixel/hytale/server/core/config/UpdateConfig.java b/src/com/hypixel/hytale/server/core/config/UpdateConfig.java new file mode 100644 index 00000000..f1e55847 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/config/UpdateConfig.java @@ -0,0 +1,159 @@ +package com.hypixel.hytale.server.core.config; + +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.EnumCodec; +import com.hypixel.hytale.server.core.HytaleServerConfig; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class UpdateConfig { + public static final int DEFAULT_CHECK_INTERVAL_SECONDS = 3600; + @Nonnull + public static final Codec CODEC = BuilderCodec.builder(UpdateConfig.class, UpdateConfig::new) + .append(new KeyedCodec<>("Enabled", Codec.BOOLEAN), (o, b) -> o.enabled = b, o -> o.enabled) + .documentation("Determines whether to enable automatic update checks.") + .add() + .append(new KeyedCodec<>("CheckIntervalSeconds", Codec.INTEGER), (o, i) -> o.checkIntervalSeconds = i, o -> o.checkIntervalSeconds) + .documentation("The interval, in seconds, between automatic update checks.") + .add() + .append(new KeyedCodec<>("NotifyPlayersOnAvailable", Codec.BOOLEAN), (o, b) -> o.notifyPlayersOnAvailable = b, o -> o.notifyPlayersOnAvailable) + .documentation("Whether to notify players in-game when an update is available.") + .add() + .append(new KeyedCodec<>("Patchline", Codec.STRING), (o, s) -> o.patchline = s, o -> o.patchline) + .documentation("The patchline to check for updates on.") + .add() + .append(new KeyedCodec<>("RunBackupBeforeUpdate", Codec.BOOLEAN), (o, b) -> o.runBackupBeforeUpdate = b, o -> o.runBackupBeforeUpdate) + .documentation("Determines whether to run a backup before applying an update.") + .add() + .append(new KeyedCodec<>("BackupConfigBeforeUpdate", Codec.BOOLEAN), (o, b) -> o.backupConfigBeforeUpdate = b, o -> o.backupConfigBeforeUpdate) + .documentation("Determines whether to backup the server config before applying an update.") + .add() + .append( + new KeyedCodec<>("AutoApplyMode", new EnumCodec<>(UpdateConfig.AutoApplyMode.class)), (o, m) -> o.autoApplyMode = m, o -> o.autoApplyMode + ) + .documentation("The mode for automatically applying updates.") + .add() + .append(new KeyedCodec<>("AutoApplyDelayMinutes", Codec.INTEGER), (o, i) -> o.autoApplyDelayMinutes = i, o -> o.autoApplyDelayMinutes) + .documentation("The delay in minutes before auto-applying an update while using SCHEDULED mode.") + .add() + .build(); + private Boolean enabled; + private Integer checkIntervalSeconds; + private Boolean notifyPlayersOnAvailable; + private String patchline; + private Boolean runBackupBeforeUpdate; + private Boolean backupConfigBeforeUpdate; + private UpdateConfig.AutoApplyMode autoApplyMode; + private Integer autoApplyDelayMinutes; + @Nullable + transient HytaleServerConfig hytaleServerConfig; + + public UpdateConfig() { + } + + public UpdateConfig(@Nonnull HytaleServerConfig hytaleServerConfig) { + this.hytaleServerConfig = hytaleServerConfig; + } + + public void setHytaleServerConfig(@Nonnull HytaleServerConfig hytaleServerConfig) { + this.hytaleServerConfig = hytaleServerConfig; + } + + public boolean isEnabled() { + return this.enabled != null ? this.enabled : true; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public int getCheckIntervalSeconds() { + return this.checkIntervalSeconds != null ? this.checkIntervalSeconds : 3600; + } + + public void setCheckIntervalSeconds(int checkIntervalSeconds) { + this.checkIntervalSeconds = checkIntervalSeconds; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public boolean isNotifyPlayersOnAvailable() { + return this.notifyPlayersOnAvailable != null ? this.notifyPlayersOnAvailable : true; + } + + public void setNotifyPlayersOnAvailable(boolean notifyPlayersOnAvailable) { + this.notifyPlayersOnAvailable = notifyPlayersOnAvailable; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + @Nullable + public String getPatchline() { + return this.patchline; + } + + public void setPatchline(@Nullable String patchline) { + this.patchline = patchline; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public boolean isRunBackupBeforeUpdate() { + return this.runBackupBeforeUpdate != null ? this.runBackupBeforeUpdate : true; + } + + public void setRunBackupBeforeUpdate(boolean runBackupBeforeUpdate) { + this.runBackupBeforeUpdate = runBackupBeforeUpdate; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public boolean isBackupConfigBeforeUpdate() { + return this.backupConfigBeforeUpdate != null ? this.backupConfigBeforeUpdate : true; + } + + public void setBackupConfigBeforeUpdate(boolean backupConfigBeforeUpdate) { + this.backupConfigBeforeUpdate = backupConfigBeforeUpdate; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + @Nonnull + public UpdateConfig.AutoApplyMode getAutoApplyMode() { + return this.autoApplyMode != null ? this.autoApplyMode : UpdateConfig.AutoApplyMode.DISABLED; + } + + public void setAutoApplyMode(@Nonnull UpdateConfig.AutoApplyMode autoApplyMode) { + this.autoApplyMode = autoApplyMode; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public int getAutoApplyDelayMinutes() { + return this.autoApplyDelayMinutes != null ? this.autoApplyDelayMinutes : 30; + } + + public void setAutoApplyDelayMinutes(int autoApplyDelayMinutes) { + this.autoApplyDelayMinutes = autoApplyDelayMinutes; + if (this.hytaleServerConfig != null) { + this.hytaleServerConfig.markChanged(); + } + } + + public static enum AutoApplyMode { + DISABLED, + WHEN_EMPTY, + SCHEDULED; + } +} diff --git a/src/com/hypixel/hytale/server/core/console/ConsoleModule.java b/src/com/hypixel/hytale/server/core/console/ConsoleModule.java index b127708f..06e008ce 100644 --- a/src/com/hypixel/hytale/server/core/console/ConsoleModule.java +++ b/src/com/hypixel/hytale/server/core/console/ConsoleModule.java @@ -22,9 +22,10 @@ import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; public class ConsoleModule extends JavaPlugin { + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static final PluginManifest MANIFEST = PluginManifest.corePlugin(ConsoleModule.class).build(); private static ConsoleModule instance; - private Terminal terminal; + private static Terminal terminal; private ConsoleModule.ConsoleRunnable consoleRunnable; public static ConsoleModule get() { @@ -35,11 +36,7 @@ public class ConsoleModule extends JavaPlugin { super(init); } - @Override - protected void setup() { - instance = this; - this.getCommandRegistry().registerCommand(new SayCommand()); - + public static void initializeTerminal() { try { TerminalBuilder builder = TerminalBuilder.builder(); if (Constants.SINGLEPLAYER) { @@ -48,22 +45,28 @@ public class ConsoleModule extends JavaPlugin { builder.color(true); } - this.terminal = builder.build(); - HytaleConsole.INSTANCE.setTerminal(this.terminal.getType()); - LineReader lineReader = LineReaderBuilder.builder().terminal(this.terminal).build(); - this.consoleRunnable = new ConsoleModule.ConsoleRunnable(lineReader, ConsoleSender.INSTANCE); - this.getLogger().at(Level.INFO).log("Setup console with type: %s", this.terminal.getType()); - } catch (IOException var3) { - this.getLogger().at(Level.SEVERE).withCause(var3).log("Failed to start console reader"); + terminal = builder.build(); + HytaleConsole.INSTANCE.setTerminal(terminal.getType()); + } catch (IOException var1) { + LOGGER.at(Level.SEVERE).withCause(var1).log("Failed to start console reader"); } } + @Override + protected void setup() { + instance = this; + this.getCommandRegistry().registerCommand(new SayCommand()); + LineReader lineReader = LineReaderBuilder.builder().terminal(terminal).build(); + this.consoleRunnable = new ConsoleModule.ConsoleRunnable(lineReader, ConsoleSender.INSTANCE); + this.getLogger().at(Level.INFO).log("Setup console with type: %s", terminal.getType()); + } + @Override protected void shutdown() { this.getLogger().at(Level.INFO).log("Restoring terminal..."); try { - this.terminal.close(); + terminal.close(); } catch (IOException var2) { HytaleLogger.getLogger().at(Level.SEVERE).withCause(var2).log("Failed to restore terminal!"); } @@ -72,7 +75,7 @@ public class ConsoleModule extends JavaPlugin { } public Terminal getTerminal() { - return this.terminal; + return terminal; } private static class ConsoleRunnable implements Runnable { diff --git a/src/com/hypixel/hytale/server/core/entity/InteractionManager.java b/src/com/hypixel/hytale/server/core/entity/InteractionManager.java index 457be610..30f764fc 100644 --- a/src/com/hypixel/hytale/server/core/entity/InteractionManager.java +++ b/src/com/hypixel/hytale/server/core/entity/InteractionManager.java @@ -190,7 +190,7 @@ public class InteractionManager implements Component { 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); } } @@ -417,7 +417,8 @@ public class InteractionManager implements Component { long threshold = this.getOperationTimeoutThreshold(); if (waitMillisx > threshold) { - LOGGER.at(Level.SEVERE).log("Client finished chain earlier than server! %d, %s", chain.getChainId(), chain); + LOGGER.at(Level.FINE).log("Client finished chain earlier than server! %d, %s", chain.getChainId(), chain); + this.cancelChains(chain); } } @@ -674,10 +675,12 @@ public class InteractionManager implements Component { long threshold = this.getOperationTimeoutThreshold(); if (waitMillis > threshold) { - HytaleLogger.Api ctx = LOGGER.at(Level.SEVERE); + HytaleLogger.Api ctx = LOGGER.at(Level.FINE); if (ctx.isEnabled()) { ctx.log("Client finished interaction earlier than server! %d, %s", entry.getIndex(), entry); } + + this.cancelChains(chain); } } } diff --git a/src/com/hypixel/hytale/server/core/entity/ItemUtils.java b/src/com/hypixel/hytale/server/core/entity/ItemUtils.java index bec7db1f..8966ab2f 100644 --- a/src/com/hypixel/hytale/server/core/entity/ItemUtils.java +++ b/src/com/hypixel/hytale/server/core/entity/ItemUtils.java @@ -8,26 +8,25 @@ 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.server.core.asset.type.item.config.Item; -import com.hypixel.hytale.server.core.asset.type.model.config.Model; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.event.events.ecs.DropItemEvent; import com.hypixel.hytale.server.core.event.events.ecs.InteractivelyPickupItemEvent; import com.hypixel.hytale.server.core.inventory.ItemStack; -import com.hypixel.hytale.server.core.inventory.container.ItemContainer; import com.hypixel.hytale.server.core.inventory.container.SimpleItemContainer; import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction; import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; 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.modules.entity.player.PlayerSettings; 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 ItemUtils { + @Nonnull + public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + public static void interactivelyPickupItem( @Nonnull Ref ref, @Nonnull ItemStack itemStack, @Nullable Vector3d origin, @Nonnull ComponentAccessor componentAccessor ) { @@ -39,19 +38,8 @@ public class ItemUtils { } else { Player playerComponent = componentAccessor.getComponent(ref, Player.getComponentType()); if (playerComponent != null) { - TransformComponent transformComponent = componentAccessor.getComponent(ref, TransformComponent.getComponentType()); - - assert transformComponent != null; - - PlayerSettings playerSettingsComponent = componentAccessor.getComponent(ref, PlayerSettings.getComponentType()); - if (playerSettingsComponent == null) { - playerSettingsComponent = PlayerSettings.defaults(); - } - Holder pickupItemHolder = null; - Item item = itemStack.getItem(); - ItemContainer itemContainer = playerComponent.getInventory().getContainerForItemPickup(item, playerSettingsComponent); - ItemStackTransaction transaction = itemContainer.addItemStack(itemStack); + ItemStackTransaction transaction = playerComponent.giveItem(itemStack, ref, componentAccessor); ItemStack remainder = transaction.getRemainder(); if (remainder != null && !remainder.isEmpty()) { int quantity = itemStack.getQuantity() - remainder.getQuantity(); @@ -93,14 +81,11 @@ public class ItemUtils { itemStack = event.getItemStack(); if (!itemStack.isEmpty() && itemStack.isValid()) { HeadRotation headRotationComponent = componentAccessor.getComponent(ref, HeadRotation.getComponentType()); - - assert headRotationComponent != null; - - Vector3f rotation = headRotationComponent.getRotation(); + Vector3f rotation = headRotationComponent != null ? headRotationComponent.getRotation() : new Vector3f(0.0F, 0.0F, 0.0F); Vector3d direction = Transform.getDirection(rotation.getPitch(), rotation.getYaw()); return throwItem(ref, componentAccessor, itemStack, direction, throwSpeed); } else { - HytaleLogger.getLogger().at(Level.WARNING).log("Attempted to throw invalid item %s at %s by %s", itemStack, throwSpeed, ref.getIndex()); + LOGGER.at(Level.WARNING).log("Attempted to throw invalid item %s at %s by %s", itemStack, throwSpeed, ref.getIndex()); return null; } } @@ -114,35 +99,43 @@ public class ItemUtils { @Nonnull Vector3d throwDirection, float throwSpeed ) { - TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); - - assert transformComponent != null; - - ModelComponent modelComponent = store.getComponent(ref, ModelComponent.getComponentType()); - - assert modelComponent != null; - - Vector3d throwPosition = transformComponent.getPosition().clone(); - Model model = modelComponent.getModel(); - throwPosition.add(0.0, model.getEyeHeight(ref, store), 0.0).add(throwDirection); - Holder itemEntityHolder = ItemComponent.generateItemDrop( - store, - itemStack, - throwPosition, - Vector3f.ZERO, - (float)throwDirection.x * throwSpeed, - (float)throwDirection.y * throwSpeed, - (float)throwDirection.z * throwSpeed - ); - if (itemEntityHolder == null) { + if (!ref.isValid()) { + LOGGER.at(Level.WARNING).log("Attempted to throw item %s by invalid entity %s", itemStack, Integer.valueOf(ref.getIndex())); return null; } else { - ItemComponent itemComponent = itemEntityHolder.getComponent(ItemComponent.getComponentType()); - if (itemComponent != null) { - itemComponent.setPickupDelay(1.5F); - } + TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType()); + if (transformComponent == null) { + LOGGER.at(Level.WARNING).log("Attempted to throw item %s by entity %s without a TransformComponent", itemStack, Integer.valueOf(ref.getIndex())); + return null; + } else { + float eyeHeight = 0.0F; + ModelComponent modelComponent = store.getComponent(ref, ModelComponent.getComponentType()); + if (modelComponent != null) { + eyeHeight = modelComponent.getModel().getEyeHeight(ref, store); + } - return store.addEntity(itemEntityHolder, AddReason.SPAWN); + Vector3d throwPosition = transformComponent.getPosition().clone(); + throwPosition.add(0.0, eyeHeight, 0.0).add(throwDirection); + Holder itemEntityHolder = ItemComponent.generateItemDrop( + store, + itemStack, + throwPosition, + Vector3f.ZERO, + (float)throwDirection.x * throwSpeed, + (float)throwDirection.y * throwSpeed, + (float)throwDirection.z * throwSpeed + ); + if (itemEntityHolder == null) { + return null; + } else { + ItemComponent itemComponent = itemEntityHolder.getComponent(ItemComponent.getComponentType()); + if (itemComponent != null) { + itemComponent.setPickupDelay(1.5F); + } + + return store.addEntity(itemEntityHolder, AddReason.SPAWN); + } + } } } diff --git a/src/com/hypixel/hytale/server/core/entity/effect/ActiveEntityEffect.java b/src/com/hypixel/hytale/server/core/entity/effect/ActiveEntityEffect.java index e76bdfcf..897d183a 100644 --- a/src/com/hypixel/hytale/server/core/entity/effect/ActiveEntityEffect.java +++ b/src/com/hypixel/hytale/server/core/entity/effect/ActiveEntityEffect.java @@ -243,16 +243,19 @@ public class ActiveEntityEffect implements Damage.Source { @Override public Message getDeathMessage(@Nonnull Damage info, @Nonnull Ref targetRef, @Nonnull ComponentAccessor componentAccessor) { EntityEffect entityEffect = EntityEffect.getAssetMap().getAsset(this.entityEffectIndex); - Message damageCauseMessage; - if (entityEffect != null) { - String locale = entityEffect.getLocale(); - String reason = locale != null ? locale : entityEffect.getId().toLowerCase(Locale.ROOT); - damageCauseMessage = Message.translation("server.general.damageCauses." + reason); + if (entityEffect == null) { + return Message.translation("server.general.killedBy").param("damageSource", MESSAGE_GENERAL_DAMAGE_CAUSES_UNKNOWN); } else { - damageCauseMessage = MESSAGE_GENERAL_DAMAGE_CAUSES_UNKNOWN; + String deathMessageKey = entityEffect.getDeathMessageKey(); + if (deathMessageKey != null) { + return Message.translation(deathMessageKey); + } else { + String locale = entityEffect.getLocale(); + String reason = locale != null ? locale : entityEffect.getId().toLowerCase(Locale.ROOT); + Message damageCauseMessage = Message.translation("server.general.damageCauses." + reason); + return Message.translation("server.general.killedBy").param("damageSource", damageCauseMessage); + } } - - return Message.translation("server.general.killedBy").param("damageSource", damageCauseMessage); } @Nonnull diff --git a/src/com/hypixel/hytale/server/core/entity/entities/Player.java b/src/com/hypixel/hytale/server/core/entity/entities/Player.java index 5a53419e..c03d4e31 100644 --- a/src/com/hypixel/hytale/server/core/entity/entities/Player.java +++ b/src/com/hypixel/hytale/server/core/entity/entities/Player.java @@ -51,6 +51,7 @@ import com.hypixel.hytale.server.core.inventory.Inventory; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.inventory.container.ItemContainer; import com.hypixel.hytale.server.core.inventory.transaction.ItemStackSlotTransaction; +import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction; import com.hypixel.hytale.server.core.io.PacketHandler; import com.hypixel.hytale.server.core.modules.collision.CollisionModule; import com.hypixel.hytale.server.core.modules.collision.CollisionResult; @@ -206,7 +207,7 @@ public class Player extends LivingEntity implements CommandSender, PermissionHol Store store = ref.getStore(); ChunkTracker tracker = store.getComponent(ref, ChunkTracker.getComponentType()); if (tracker != null) { - tracker.clear(); + tracker.unloadAll(this.playerRef); } this.playerRef.removeFromStore(); @@ -218,7 +219,7 @@ public class Player extends LivingEntity implements CommandSender, PermissionHol Store storex = ref.getStore(); ChunkTracker trackerx = storex.getComponent(ref, ChunkTracker.getComponentType()); if (trackerx != null) { - trackerx.clear(); + trackerx.unloadAll(this.playerRef); } this.playerRef.removeFromStore(); @@ -897,6 +898,16 @@ public class Player extends LivingEntity implements CommandSender, PermissionHol } } + @Nonnull + public ItemStackTransaction giveItem(@Nonnull ItemStack stack, @Nonnull Ref ref, @Nonnull ComponentAccessor componentAccessor) { + PlayerSettings playerSettings = componentAccessor.getComponent(ref, PlayerSettings.getComponentType()); + if (playerSettings == null) { + playerSettings = PlayerSettings.defaults(); + } + + return this.getInventory().getContainerForItemPickup(stack.getItem(), playerSettings).addItemStack(stack); + } + @Override public int hashCode() { int result = super.hashCode(); diff --git a/src/com/hypixel/hytale/server/core/entity/entities/ProjectileComponent.java b/src/com/hypixel/hytale/server/core/entity/entities/ProjectileComponent.java index 4829d90d..ff953e27 100644 --- a/src/com/hypixel/hytale/server/core/entity/entities/ProjectileComponent.java +++ b/src/com/hypixel/hytale/server/core/entity/entities/ProjectileComponent.java @@ -306,8 +306,6 @@ public class ProjectileComponent implements Component { if (depthShot != 0.0) { PhysicsMath.vectorFromAngles(yaw, pitchAdjust ? pitch : 0.0F, offset); offset.setLength(depthShot); - } else { - offset.assign(0.0, 0.0, 0.0); } offset.add(horizontalCenterShot * -PhysicsMath.headingZ(yaw), -verticalCenterShot, horizontalCenterShot * PhysicsMath.headingX(yaw)); 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/PageManager.java b/src/com/hypixel/hytale/server/core/entity/entities/player/pages/PageManager.java index 26889d10..482907eb 100644 --- a/src/com/hypixel/hytale/server/core/entity/entities/player/pages/PageManager.java +++ b/src/com/hypixel/hytale/server/core/entity/entities/player/pages/PageManager.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.protocol.packets.interface_.SetPage; import com.hypixel.hytale.protocol.packets.window.OpenWindow; import com.hypixel.hytale.server.core.entity.entities.player.windows.Window; import com.hypixel.hytale.server.core.entity.entities.player.windows.WindowManager; +import com.hypixel.hytale.server.core.modules.anchoraction.AnchorActionModule; import com.hypixel.hytale.server.core.ui.builder.UICommandBuilder; import com.hypixel.hytale.server.core.ui.builder.UIEventBuilder; import com.hypixel.hytale.server.core.universe.PlayerRef; @@ -125,11 +126,15 @@ public class PageManager { this.customPage = null; break; case Data: - if (this.customPageRequiredAcknowledgments.get() != 0 || this.customPage == null) { + if (this.customPageRequiredAcknowledgments.get() != 0) { return; } - this.customPage.handleDataEvent(ref, store, event.data); + if (this.customPage != null) { + this.customPage.handleDataEvent(ref, store, event.data); + } else { + AnchorActionModule.get().tryHandle(this.playerRef, event.data); + } break; case Acknowledge: if (this.customPageRequiredAcknowledgments.decrementAndGet() < 0) { 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/entity/movement/MovementStatesSystems.java b/src/com/hypixel/hytale/server/core/entity/movement/MovementStatesSystems.java index 3538bda7..1fecec70 100644 --- a/src/com/hypixel/hytale/server/core/entity/movement/MovementStatesSystems.java +++ b/src/com/hypixel/hytale/server/core/entity/movement/MovementStatesSystems.java @@ -13,9 +13,8 @@ import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.RefSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.MovementStates; +import com.hypixel.hytale.protocol.MovementStatesUpdate; import com.hypixel.hytale.protocol.SavedMovementStates; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerWorldData; @@ -168,8 +167,7 @@ public class MovementStatesSystems { @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo, @Nonnull MovementStatesComponent movementStatesComponent ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.MovementStates; + MovementStatesUpdate update = new MovementStatesUpdate(); update.movementStates = movementStatesComponent.getMovementStates(); for (Entry, EntityTrackerSystems.EntityViewer> entry : visibleTo.entrySet()) { diff --git a/src/com/hypixel/hytale/server/core/entity/nameplate/NameplateSystems.java b/src/com/hypixel/hytale/server/core/entity/nameplate/NameplateSystems.java index 64310356..080837aa 100644 --- a/src/com/hypixel/hytale/server/core/entity/nameplate/NameplateSystems.java +++ b/src/com/hypixel/hytale/server/core/entity/nameplate/NameplateSystems.java @@ -9,8 +9,8 @@ import com.hypixel.hytale.component.SystemGroup; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.NameplateUpdate; import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.util.Map; @@ -132,10 +132,7 @@ public class NameplateSystems { private static void queueUpdatesFor( @Nonnull Ref ref, @Nonnull Nameplate nameplateComponent, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Nameplate; - update.nameplate = new com.hypixel.hytale.protocol.Nameplate(); - update.nameplate.text = nameplateComponent.getText(); + NameplateUpdate update = new NameplateUpdate(nameplateComponent.getText()); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/event/events/player/DrainPlayerFromWorldEvent.java b/src/com/hypixel/hytale/server/core/event/events/player/DrainPlayerFromWorldEvent.java index f2c47c93..5b0f2a39 100644 --- a/src/com/hypixel/hytale/server/core/event/events/player/DrainPlayerFromWorldEvent.java +++ b/src/com/hypixel/hytale/server/core/event/events/player/DrainPlayerFromWorldEvent.java @@ -6,35 +6,42 @@ import com.hypixel.hytale.math.vector.Transform; 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 DrainPlayerFromWorldEvent implements IEvent { + @Nonnull private final Holder holder; + @Nonnull private World world; + @Nullable private Transform transform; - public DrainPlayerFromWorldEvent(Holder holder, World world, Transform transform) { + public DrainPlayerFromWorldEvent(@Nonnull Holder holder, @Nonnull World world, @Nullable Transform transform) { this.holder = holder; this.world = world; this.transform = transform; } + @Nonnull public Holder getHolder() { return this.holder; } + @Nonnull public World getWorld() { return this.world; } - public void setWorld(World world) { + public void setWorld(@Nonnull World world) { this.world = world; } + @Nullable public Transform getTransform() { return this.transform; } - public void setTransform(Transform transform) { + public void setTransform(@Nullable Transform transform) { this.transform = transform; } diff --git a/src/com/hypixel/hytale/server/core/inventory/Inventory.java b/src/com/hypixel/hytale/server/core/inventory/Inventory.java index 2b7c5f9e..ad406ecb 100644 --- a/src/com/hypixel/hytale/server/core/inventory/Inventory.java +++ b/src/com/hypixel/hytale/server/core/inventory/Inventory.java @@ -111,9 +111,11 @@ public class Inventory implements NetworkSerializable { @Deprecated private ItemContainer tools = EmptyItemContainer.INSTANCE; private ItemContainer backpack = EmptyItemContainer.INSTANCE; + private CombinedItemContainer combinedHotbarStorageBackpack; private CombinedItemContainer combinedHotbarFirst; private CombinedItemContainer combinedStorageFirst; private CombinedItemContainer combinedBackpackStorageHotbar; + private CombinedItemContainer combinedBackpackHotbarStorage; private CombinedItemContainer combinedStorageHotbarBackpack; private CombinedItemContainer combinedArmorHotbarStorage; private CombinedItemContainer combinedArmorHotbarUtilityStorage; @@ -391,89 +393,110 @@ public class Inventory implements NetworkSerializable { } } - public void smartMoveItem(int fromSectionId, int fromSlotId, int quantity, @Nonnull SmartMoveType moveType) { + public void smartMoveItem(int fromSectionId, int fromSlotId, int quantity, @Nonnull SmartMoveType moveType, PlayerSettings settings) { ItemContainer targetContainer = this.getSectionById(fromSectionId); if (targetContainer != null) { - switch (moveType) { - case EquipOrMergeStack: - if (this.tryEquipArmorPart(fromSectionId, (short)fromSlotId, quantity, targetContainer, true)) { - return; - } - - if (this.entity instanceof Player) { - for (Window window : ((Player)this.entity).getWindowManager().getWindows()) { - if (window instanceof ItemContainerWindow) { - ((ItemContainerWindow)window).getItemContainer().combineItemStacksIntoSlot(targetContainer, (short)fromSlotId); - } + ItemStack itemStack = targetContainer.getItemStack((short)fromSlotId); + if (!ItemStack.isEmpty(itemStack)) { + switch (moveType) { + case EquipOrMergeStack: + if (this.tryEquipArmorPart(itemStack, fromSectionId, (short)fromSlotId, quantity, targetContainer, true)) { + return; } - } - this.combinedHotbarFirst.combineItemStacksIntoSlot(targetContainer, (short)fromSlotId); - break; - case PutInHotbarOrWindow: - if (fromSectionId >= 0) { - targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, this.combinedHotbarFirst); - return; - } - - if (this.entity instanceof Player) { - for (Window windowx : ((Player)this.entity).getWindowManager().getWindows()) { - if (windowx instanceof ItemContainerWindow) { - ItemContainer itemContainer = ((ItemContainerWindow)windowx).getItemContainer(); - MoveTransaction transaction = targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, itemContainer); - ItemStack remainder = transaction.getAddTransaction().getRemainder(); - if (ItemStack.isEmpty(remainder) || remainder.getQuantity() != quantity) { - return; + if (this.entity instanceof Player) { + for (Window window : ((Player)this.entity).getWindowManager().getWindows()) { + if (window instanceof ItemContainerWindow) { + ((ItemContainerWindow)window).getItemContainer().combineItemStacksIntoSlot(targetContainer, (short)fromSlotId); } } } - } - if (this.tryEquipArmorPart(fromSectionId, (short)fromSlotId, quantity, targetContainer, false)) { - return; - } + this.combinedEverything.combineItemStacksIntoSlot(targetContainer, (short)fromSlotId); + break; + case PutInHotbarOrWindow: + if (fromSectionId >= 0) { + this.moveItemFromCheckToInventory(itemStack, targetContainer, (short)fromSlotId, quantity, settings); + return; + } - switch (fromSectionId) { - case -2: - targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, this.hotbar); + if (this.entity instanceof Player) { + for (Window windowx : ((Player)this.entity).getWindowManager().getWindows()) { + if (windowx instanceof ItemContainerWindow) { + ItemContainer itemContainer = ((ItemContainerWindow)windowx).getItemContainer(); + MoveTransaction transaction = targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, itemContainer); + ItemStack remainder = transaction.getAddTransaction().getRemainder(); + if (ItemStack.isEmpty(remainder) || remainder.getQuantity() != quantity) { + return; + } + } + } + } + + if (this.tryEquipArmorPart(itemStack, fromSectionId, (short)fromSlotId, quantity, targetContainer, false)) { return; - case -1: - targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, this.storage); - return; - default: - targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, this.combinedHotbarFirst); - return; - } - case PutInHotbarOrBackpack: - if (fromSectionId == -9) { - targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, this.combinedHotbarFirst); - } else { - targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, this.combinedBackpackStorageHotbar); - } + } + + switch (fromSectionId) { + case -2: + targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, this.hotbar); + return; + case -1: + targetContainer.moveItemStackFromSlot((short)fromSlotId, quantity, this.storage); + return; + default: + this.moveItemFromCheckToInventory(itemStack, targetContainer, (short)fromSlotId, quantity, settings); + return; + } + case PutInHotbarOrBackpack: + if (fromSectionId == -9) { + this.moveItemFromCheckToInventory(itemStack, targetContainer, (short)fromSlotId, quantity, settings); + } else { + targetContainer.moveItemStackFromSlot( + (short)fromSlotId, quantity, this.getContainerForItemPickup(itemStack.getItem(), settings, PickupLocation.Backpack) + ); + } + } } } } - private boolean tryEquipArmorPart(int fromSectionId, short fromSlotId, int quantity, ItemContainer targetContainer, boolean forceEquip) { - ItemStack itemStack = targetContainer.getItemStack(fromSlotId); - if (ItemStack.isEmpty(itemStack)) { + private boolean tryEquipArmorPart( + @Nonnull ItemStack itemStack, int fromSectionId, short fromSlotId, int quantity, ItemContainer targetContainer, boolean forceEquip + ) { + Item item = itemStack.getItem(); + ItemArmor itemArmor = item.getArmor(); + if (itemArmor == null || fromSectionId == -3 || !forceEquip && this.armor.getItemStack((short)itemArmor.getArmorSlot().ordinal()) != null) { return false; } else { - Item item = itemStack.getItem(); - ItemArmor itemArmor = item.getArmor(); - if (itemArmor == null || fromSectionId == -3 || !forceEquip && this.armor.getItemStack((short)itemArmor.getArmorSlot().ordinal()) != null) { - return false; - } else { - targetContainer.moveItemStackFromSlotToSlot(fromSlotId, quantity, this.armor, (short)itemArmor.getArmorSlot().ordinal()); - return true; - } + targetContainer.moveItemStackFromSlotToSlot(fromSlotId, quantity, this.armor, (short)itemArmor.getArmorSlot().ordinal()); + return true; } } + private MoveTransaction moveItemFromCheckToInventory( + @Nonnull ItemStack itemStack, @Nonnull ItemContainer targetContainer, short fromSlotId, int quantity, PlayerSettings settings + ) { + return targetContainer.moveItemStackFromSlot(fromSlotId, quantity, this.getContainerForItemPickup(itemStack.getItem(), settings)); + } + @Nullable - public ListTransaction> takeAll(int inventorySectionId) { - ItemContainer sectionById = this.getSectionById(inventorySectionId); - return sectionById != null ? sectionById.moveAllItemStacksTo(this.combinedHotbarFirst) : null; + public ListTransaction> takeAll(int inventorySectionId, PlayerSettings settings) { + ItemContainer container = this.getSectionById(inventorySectionId); + return container == null ? null : this.takeAllWithPriority(container, settings); + } + + public ListTransaction> takeAllWithPriority(ItemContainer fromContainer, PlayerSettings settings) { + List> transactions = new ObjectArrayList<>(); + + for (int slot = 0; slot < fromContainer.getCapacity(); slot++) { + ItemStack stack = fromContainer.getItemStack((short)slot); + if (!ItemStack.isEmpty(stack)) { + transactions.add(this.moveItemFromCheckToInventory(stack, fromContainer, (short)slot, stack.getQuantity(), settings)); + } + } + + return new ListTransaction<>(true, transactions); } @Nullable @@ -558,8 +581,8 @@ public class Inventory implements NetworkSerializable { return this.combinedBackpackStorageHotbar; } - public CombinedItemContainer getCombinedArmorHotbarStorage() { - return this.combinedArmorHotbarStorage; + public CombinedItemContainer getCombinedBackpackStorageHotbarFirst() { + return this.combinedHotbarStorageBackpack; } public CombinedItemContainer getCombinedArmorHotbarUtilityStorage() { @@ -574,31 +597,39 @@ public class Inventory implements NetworkSerializable { return this.combinedEverything; } + private ItemContainer getItemContainerForPickupLocation(@Nonnull PickupLocation pickupLocation) { + return switch (pickupLocation) { + case Hotbar -> this.combinedHotbarStorageBackpack; + case Storage -> this.combinedStorageHotbarBackpack; + case Backpack -> this.combinedBackpackStorageHotbar; + default -> this.combinedHotbarStorageBackpack; + }; + } + @Nonnull public ItemContainer getContainerForItemPickup(@Nonnull Item item, PlayerSettings playerSettings) { - if (item.getArmor() != null) { - return playerSettings.armorItemsPreferredPickupLocation() == PickupLocation.Hotbar ? this.getCombinedHotbarFirst() : this.getCombinedStorageFirst(); + return this.getContainerForItemPickup(item, playerSettings, null); + } + + @Nonnull + public ItemContainer getContainerForItemPickup(@Nonnull Item item, PlayerSettings playerSettings, @Nullable PickupLocation overridePickupLocation) { + if (overridePickupLocation != null) { + return this.getItemContainerForPickupLocation(overridePickupLocation); + } else if (item.getArmor() != null) { + return this.getItemContainerForPickupLocation(playerSettings.armorItemsPreferredPickupLocation()); } else if (item.getWeapon() != null || item.getTool() != null) { - return playerSettings.weaponAndToolItemsPreferredPickupLocation() == PickupLocation.Hotbar - ? this.getCombinedHotbarFirst() - : this.getCombinedStorageFirst(); + return this.getItemContainerForPickupLocation(playerSettings.weaponAndToolItemsPreferredPickupLocation()); } else if (item.getUtility().isUsable()) { - return playerSettings.usableItemsItemsPreferredPickupLocation() == PickupLocation.Hotbar - ? this.getCombinedHotbarFirst() - : this.getCombinedStorageFirst(); + return this.getItemContainerForPickupLocation(playerSettings.usableItemsItemsPreferredPickupLocation()); } else { BlockType blockType = item.hasBlockType() ? BlockType.getAssetMap().getAsset(item.getBlockId()) : BlockType.EMPTY; if (blockType == null) { blockType = BlockType.EMPTY; } - if (blockType.getMaterial() == BlockMaterial.Solid) { - return playerSettings.solidBlockItemsPreferredPickupLocation() == PickupLocation.Hotbar - ? this.getCombinedHotbarFirst() - : this.getCombinedStorageFirst(); - } else { - return playerSettings.miscItemsPreferredPickupLocation() == PickupLocation.Hotbar ? this.getCombinedHotbarFirst() : this.getCombinedStorageFirst(); - } + return blockType.getMaterial() == BlockMaterial.Solid + ? this.getItemContainerForPickupLocation(playerSettings.solidBlockItemsPreferredPickupLocation()) + : this.getItemContainerForPickupLocation(playerSettings.miscItemsPreferredPickupLocation()); } } @@ -797,7 +828,9 @@ public class Inventory implements NetworkSerializable { this.combinedHotbarFirst = new CombinedItemContainer(this.hotbar, this.storage); this.combinedStorageFirst = new CombinedItemContainer(this.storage, this.hotbar); this.combinedBackpackStorageHotbar = new CombinedItemContainer(this.backpack, this.storage, this.hotbar); + this.combinedBackpackHotbarStorage = new CombinedItemContainer(this.backpack, this.hotbar, this.storage); this.combinedStorageHotbarBackpack = new CombinedItemContainer(this.storage, this.hotbar, this.backpack); + this.combinedHotbarStorageBackpack = new CombinedItemContainer(this.hotbar, this.storage, this.backpack); this.combinedArmorHotbarStorage = new CombinedItemContainer(this.armor, this.hotbar, this.storage); this.combinedArmorHotbarUtilityStorage = new CombinedItemContainer(this.armor, this.hotbar, this.utility, this.storage); this.combinedHotbarUtilityConsumableStorage = new CombinedItemContainer(this.hotbar, this.utility, this.storage); diff --git a/src/com/hypixel/hytale/server/core/io/PacketHandler.java b/src/com/hypixel/hytale/server/core/io/PacketHandler.java index 102e5cc1..b6924ee4 100644 --- a/src/com/hypixel/hytale/server/core/io/PacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/PacketHandler.java @@ -10,7 +10,9 @@ import com.hypixel.hytale.metrics.MetricsRegistry; import com.hypixel.hytale.metrics.metric.HistoricMetric; import com.hypixel.hytale.metrics.metric.Metric; import com.hypixel.hytale.protocol.CachedPacket; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.NetworkChannel; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.PacketStatsRecorder; import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.protocol.packets.connection.Disconnect; @@ -23,6 +25,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; @@ -30,6 +33,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.local.LocalAddress; import io.netty.channel.unix.DomainSocketAddress; import io.netty.handler.codec.quic.QuicStreamChannel; +import io.netty.handler.codec.quic.QuicStreamPriority; import io.netty.util.Attribute; import io.netty.util.AttributeKey; import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; @@ -42,6 +46,7 @@ import java.net.SocketAddress; import java.security.SecureRandom; import java.time.Duration; import java.time.Instant; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -55,10 +60,19 @@ import javax.annotation.Nullable; public abstract class PacketHandler implements IPacketReceiver { public static final int MAX_PACKET_ID = 512; + @Nonnull + public static final Map DEFAULT_STREAM_PRIORITIES = Map.of( + NetworkChannel.Default, + new QuicStreamPriority(0, true), + NetworkChannel.Chunks, + new QuicStreamPriority(0, true), + NetworkChannel.WorldMap, + new QuicStreamPriority(1, true) + ); private static final HytaleLogger LOGIN_TIMING_LOGGER = HytaleLogger.get("LoginTiming"); private static final AttributeKey LOGIN_START_ATTRIBUTE_KEY = AttributeKey.newInstance("LOGIN_START"); @Nonnull - protected final Channel channel; + protected final Channel[] channels = new Channel[NetworkChannel.COUNT]; @Nonnull protected final ProtocolVersion protocolVersion; @Nullable @@ -79,7 +93,7 @@ public abstract class PacketHandler implements IPacketReceiver { protected final PacketHandler.DisconnectReason disconnectReason = new PacketHandler.DisconnectReason(); public PacketHandler(@Nonnull Channel channel, @Nonnull ProtocolVersion protocolVersion) { - this.channel = channel; + this.channels[0] = channel; this.protocolVersion = protocolVersion; this.pingInfo = new PacketHandler.PingInfo[PongType.VALUES.length]; @@ -90,7 +104,7 @@ public abstract class PacketHandler implements IPacketReceiver { @Nonnull public Channel getChannel() { - return this.channel; + return this.channels[0]; } @Deprecated(forRemoval = true) @@ -128,11 +142,11 @@ public abstract class PacketHandler implements IPacketReceiver { protected void unregistered0(@Nullable PacketHandler newHandler) { } - public void handle(@Nonnull Packet packet) { + public void handle(@Nonnull ToServerPacket packet) { this.accept(packet); } - public abstract void accept(@Nonnull Packet var1); + public abstract void accept(@Nonnull ToServerPacket var1); public void logCloseMessage() { HytaleLogger.getLogger().at(Level.INFO).log("%s was closed.", this.getIdentifier()); @@ -148,64 +162,89 @@ public abstract class PacketHandler implements IPacketReceiver { public void tryFlush() { if (this.queuedPackets.getAndSet(0) > 0) { - this.channel.flush(); + for (Channel channel : this.channels) { + if (channel != null) { + channel.flush(); + } + } } } - public void write(@Nonnull Packet... packets) { - Packet[] cachedPackets = new Packet[packets.length]; - this.handleOutboundAndCachePackets(packets, cachedPackets); - if (this.queuePackets) { - this.channel.write(cachedPackets, this.channel.voidPromise()); - this.queuedPackets.getAndIncrement(); - } else { - this.channel.writeAndFlush(cachedPackets, this.channel.voidPromise()); + public void write(@Nonnull ToClientPacket... packets) { + if (packets.length != 0) { + ToClientPacket[] cachedPackets = new ToClientPacket[packets.length]; + this.handleOutboundAndCachePackets(packets, cachedPackets); + NetworkChannel networkChannel = packets[0].getChannel(); + + for (int i = 1; i < packets.length; i++) { + if (networkChannel != packets[i].getChannel()) { + throw new IllegalArgumentException("All packets must be sent on the same channel!"); + } + } + + Channel channel = this.channels[networkChannel.getValue()]; + if (this.queuePackets) { + channel.write(cachedPackets, channel.voidPromise()); + this.queuedPackets.getAndIncrement(); + } else { + channel.writeAndFlush(cachedPackets, channel.voidPromise()); + } } } - public void write(@Nonnull Packet[] packets, @Nonnull Packet finalPacket) { - Packet[] cachedPackets = new Packet[packets.length + 1]; + public void write(@Nonnull ToClientPacket[] packets, @Nonnull ToClientPacket finalPacket) { + ToClientPacket[] cachedPackets = new ToClientPacket[packets.length + 1]; this.handleOutboundAndCachePackets(packets, cachedPackets); cachedPackets[cachedPackets.length - 1] = this.handleOutboundAndCachePacket(finalPacket); + NetworkChannel networkChannel = finalPacket.getChannel(); + + for (int i = 0; i < packets.length; i++) { + if (networkChannel != packets[i].getChannel()) { + throw new IllegalArgumentException("All packets must be sent on the same channel!"); + } + } + + Channel channel = this.channels[networkChannel.getValue()]; if (this.queuePackets) { - this.channel.write(cachedPackets, this.channel.voidPromise()); + channel.write(cachedPackets, channel.voidPromise()); this.queuedPackets.getAndIncrement(); } else { - this.channel.writeAndFlush(cachedPackets, this.channel.voidPromise()); + channel.writeAndFlush(cachedPackets, channel.voidPromise()); } } @Override - public void write(@Nonnull Packet packet) { + public void write(@Nonnull ToClientPacket packet) { this.writePacket(packet, true); } @Override - public void writeNoCache(@Nonnull Packet packet) { + public void writeNoCache(@Nonnull ToClientPacket packet) { this.writePacket(packet, false); } - public void writePacket(@Nonnull Packet packet, boolean cache) { + public void writePacket(@Nonnull ToClientPacket packet, boolean cache) { if (!PacketAdapters.__handleOutbound(this, packet)) { - Packet toSend; + ToClientPacket toSend; if (cache) { toSend = this.handleOutboundAndCachePacket(packet); } else { toSend = packet; } + Channel channel = this.channels[packet.getChannel().getValue()]; if (this.queuePackets) { - this.channel.write(toSend, this.channel.voidPromise()); + channel.write(toSend, channel.voidPromise()); this.queuedPackets.getAndIncrement(); } else { - this.channel.writeAndFlush(toSend, this.channel.voidPromise()); + channel.writeAndFlush(toSend, channel.voidPromise()); } } } - private void handleOutboundAndCachePackets(@Nonnull Packet[] packets, @Nonnull Packet[] cachedPackets) { + private void handleOutboundAndCachePackets(@Nonnull ToClientPacket[] packets, @Nonnull ToClientPacket[] cachedPackets) { for (int i = 0; i < packets.length; i++) { - Packet packet = packets[i]; + ToClientPacket packet = packets[i]; if (!PacketAdapters.__handleOutbound(this, packet)) { cachedPackets[i] = this.handleOutboundAndCachePacket(packet); } @@ -213,23 +252,26 @@ public abstract class PacketHandler implements IPacketReceiver { } @Nonnull - private Packet handleOutboundAndCachePacket(@Nonnull Packet packet) { - return (Packet)(packet instanceof CachedPacket ? packet : CachedPacket.cache(packet)); + private ToClientPacket handleOutboundAndCachePacket(@Nonnull ToClientPacket packet) { + return (ToClientPacket)(packet instanceof CachedPacket ? packet : CachedPacket.cache(packet)); } 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.getChannel()), sni, message); this.disconnect0(message); } protected void disconnect0(@Nonnull String message) { - this.channel.writeAndFlush(new Disconnect(message, DisconnectType.Disconnect)).addListener(ProtocolUtil.CLOSE_ON_COMPLETE); + this.getChannel().writeAndFlush(new Disconnect(message, DisconnectType.Disconnect)).addListener(ProtocolUtil.CLOSE_ON_COMPLETE); } @Nullable public PacketStatsRecorder getPacketStatsRecorder() { - return this.channel.attr(PacketStatsRecorder.CHANNEL_KEY).get(); + return this.getChannel().attr(PacketStatsRecorder.CHANNEL_KEY).get(); } @Nonnull @@ -275,23 +317,23 @@ public abstract class PacketHandler implements IPacketReceiver { } protected void initStage(@Nonnull String stage, @Nonnull Duration timeout, @Nonnull BooleanSupplier condition) { - NettyUtil.TimeoutContext.init(this.channel, stage, this.getIdentifier()); + NettyUtil.TimeoutContext.init(this.getChannel(), stage, this.getIdentifier()); this.setStageTimeout(stage, timeout, condition); } protected void enterStage(@Nonnull String stage, @Nonnull Duration timeout, @Nonnull BooleanSupplier condition) { - NettyUtil.TimeoutContext.update(this.channel, stage, this.getIdentifier()); + NettyUtil.TimeoutContext.update(this.getChannel(), stage, this.getIdentifier()); this.updatePacketTimeout(timeout); this.setStageTimeout(stage, timeout, condition); } protected void enterStage(@Nonnull String stage, @Nonnull Duration timeout) { - NettyUtil.TimeoutContext.update(this.channel, stage, this.getIdentifier()); + NettyUtil.TimeoutContext.update(this.getChannel(), stage, this.getIdentifier()); this.updatePacketTimeout(timeout); } protected void continueStage(@Nonnull String stage, @Nonnull Duration timeout, @Nonnull BooleanSupplier condition) { - NettyUtil.TimeoutContext.update(this.channel, stage); + NettyUtil.TimeoutContext.update(this.getChannel(), stage); this.updatePacketTimeout(timeout); this.setStageTimeout(stage, timeout, condition); } @@ -302,15 +344,15 @@ public abstract class PacketHandler implements IPacketReceiver { } if (this instanceof AuthenticationPacketHandler || !(this instanceof PasswordPacketHandler) || this.auth != null) { - logConnectionTimings(this.channel, "Entering stage '" + stageId + "'", Level.FINEST); + logConnectionTimings(this.getChannel(), "Entering stage '" + stageId + "'", Level.FINEST); long timeoutMillis = timeout.toMillis(); - this.timeoutTask = this.channel + this.timeoutTask = this.getChannel() .eventLoop() .schedule( () -> { - if (this.channel.isOpen()) { + if (this.getChannel().isOpen()) { if (!meets.getAsBoolean()) { - NettyUtil.TimeoutContext context = this.channel.attr(NettyUtil.TimeoutContext.KEY).get(); + NettyUtil.TimeoutContext context = this.getChannel().attr(NettyUtil.TimeoutContext.KEY).get(); String duration = context != null ? FormatUtil.nanosToString(System.nanoTime() - context.connectionStartNs()) : "unknown"; HytaleLogger.getLogger() .at(Level.WARNING) @@ -326,7 +368,7 @@ public abstract class PacketHandler implements IPacketReceiver { } private void updatePacketTimeout(@Nonnull Duration timeout) { - this.channel.attr(ProtocolUtil.PACKET_TIMEOUT_KEY).set(timeout); + this.getChannel().attr(ProtocolUtil.PACKET_TIMEOUT_KEY).set(timeout); } protected void clearTimeout() { @@ -347,7 +389,7 @@ public abstract class PacketHandler implements IPacketReceiver { } public boolean stillActive() { - return this.channel.isActive(); + return this.getChannel().isActive(); } public int getQueuedPacketsCount() { @@ -356,10 +398,10 @@ public abstract class PacketHandler implements IPacketReceiver { public boolean isLocalConnection() { SocketAddress socketAddress; - if (this.channel instanceof QuicStreamChannel quicStreamChannel) { + if (this.getChannel() instanceof QuicStreamChannel quicStreamChannel) { socketAddress = quicStreamChannel.parent().remoteSocketAddress(); } else { - socketAddress = this.channel.remoteAddress(); + socketAddress = this.getChannel().remoteAddress(); } if (socketAddress instanceof InetSocketAddress) { @@ -372,10 +414,10 @@ public abstract class PacketHandler implements IPacketReceiver { public boolean isLANConnection() { SocketAddress socketAddress; - if (this.channel instanceof QuicStreamChannel quicStreamChannel) { + if (this.getChannel() instanceof QuicStreamChannel quicStreamChannel) { socketAddress = quicStreamChannel.parent().remoteSocketAddress(); } else { - socketAddress = this.channel.remoteAddress(); + socketAddress = this.getChannel().remoteAddress(); } if (socketAddress instanceof InetSocketAddress) { @@ -386,6 +428,11 @@ public abstract class PacketHandler implements IPacketReceiver { } } + @Nullable + public String getSniHostname() { + return this.getChannel() instanceof QuicStreamChannel quicStreamChannel ? quicStreamChannel.parent().attr(QUICTransport.SNI_HOSTNAME_ATTR).get() : null; + } + @Nonnull public PacketHandler.DisconnectReason getDisconnectReason() { return this.disconnectReason; @@ -406,6 +453,15 @@ public abstract class PacketHandler implements IPacketReceiver { return this.clientReadyForChunksFuture; } + @Nonnull + public Channel getChannel(@Nonnull NetworkChannel networkChannel) { + return this.channels[networkChannel.getValue()]; + } + + public void setChannel(@Nonnull NetworkChannel networkChannel, @Nonnull Channel channel) { + this.channels[networkChannel.getValue()] = channel; + } + public static void logConnectionTimings(@Nonnull Channel channel, @Nonnull String message, @Nonnull Level level) { Attribute loginStartAttribute = channel.attr(LOGIN_START_ATTRIBUTE_KEY); long now = System.nanoTime(); diff --git a/src/com/hypixel/hytale/server/core/io/PacketStatsRecorderImpl.java b/src/com/hypixel/hytale/server/core/io/PacketStatsRecorderImpl.java index 625005cc..0f8258c0 100644 --- a/src/com/hypixel/hytale/server/core/io/PacketStatsRecorderImpl.java +++ b/src/com/hypixel/hytale/server/core/io/PacketStatsRecorderImpl.java @@ -151,7 +151,7 @@ public class PacketStatsRecorderImpl implements PacketStatsRecorder { @Nullable @Override public String getName() { - PacketRegistry.PacketInfo info = PacketRegistry.getById(this.packetId); + PacketRegistry.PacketInfo info = PacketRegistry.all().get(this.packetId); return info != null ? info.name() : null; } 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/GenericPacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/GenericPacketHandler.java index bbdedb3b..ca478b9e 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/GenericPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/GenericPacketHandler.java @@ -1,6 +1,6 @@ package com.hypixel.hytale.server.core.io.handlers; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.server.core.io.PacketHandler; import com.hypixel.hytale.server.core.io.ProtocolVersion; import io.netty.channel.Channel; @@ -10,13 +10,13 @@ import java.util.function.Consumer; import javax.annotation.Nonnull; public abstract class GenericPacketHandler extends PacketHandler { - private static final Consumer EMPTY_CONSUMER = packet -> {}; + private static final Consumer EMPTY_CONSUMER = packet -> {}; @Nonnull protected final List packetHandlers = new ObjectArrayList<>(); - private Consumer[] handlers = newHandlerArray(0); + private Consumer[] handlers = newHandlerArray(0); @Nonnull - public static Consumer[] newHandlerArray(int size) { + public static Consumer[] newHandlerArray(int size) { return new Consumer[size]; } @@ -28,9 +28,9 @@ public abstract class GenericPacketHandler extends PacketHandler { this.packetHandlers.add(subPacketHandler); } - public void registerHandler(int packetId, @Nonnull Consumer handler) { + public void registerHandler(int packetId, @Nonnull Consumer handler) { if (packetId >= this.handlers.length) { - Consumer[] newHandlers = newHandlerArray(packetId + 1); + Consumer[] newHandlers = newHandlerArray(packetId + 1); System.arraycopy(this.handlers, 0, newHandlers, 0, this.handlers.length); this.handlers = newHandlers; } @@ -45,9 +45,9 @@ public abstract class GenericPacketHandler extends PacketHandler { } @Override - public final void accept(@Nonnull Packet packet) { + public final void accept(@Nonnull ToServerPacket packet) { int packetId = packet.getId(); - Consumer handler = this.handlers.length > packetId ? this.handlers[packetId] : null; + Consumer handler = this.handlers.length > packetId ? this.handlers[packetId] : null; if (handler != null) { try { handler.accept(packet); diff --git a/src/com/hypixel/hytale/server/core/io/handlers/IPacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/IPacketHandler.java index c8a6c3d1..4ab840b8 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/IPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/IPacketHandler.java @@ -1,12 +1,12 @@ package com.hypixel.hytale.server.core.io.handlers; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.server.core.universe.PlayerRef; import java.util.function.Consumer; import javax.annotation.Nonnull; public interface IPacketHandler { - void registerHandler(int var1, @Nonnull Consumer var2); + void registerHandler(int var1, @Nonnull Consumer var2); void registerNoOpHandlers(int... var1); diff --git a/src/com/hypixel/hytale/server/core/io/handlers/IWorldPacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/IWorldPacketHandler.java new file mode 100644 index 00000000..72b8841b --- /dev/null +++ b/src/com/hypixel/hytale/server/core/io/handlers/IWorldPacketHandler.java @@ -0,0 +1,39 @@ +package com.hypixel.hytale.server.core.io.handlers; + +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.protocol.Packet; +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 java.util.function.Predicate; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public interface IWorldPacketHandler { + void handle(@Nonnull T var1, @Nonnull PlayerRef var2, @Nonnull Ref var3, @Nonnull World var4, @Nonnull Store var5); + + static void registerHandler(@Nonnull IPacketHandler packetHandler, int packetId, @Nonnull IWorldPacketHandler handler) { + registerHandler(packetHandler, packetId, handler, null); + } + + static void registerHandler( + @Nonnull IPacketHandler packetHandler, int packetId, @Nonnull IWorldPacketHandler handler, @Nullable Predicate precondition + ) { + packetHandler.registerHandler(packetId, packet -> { + PlayerRef playerRef = packetHandler.getPlayerRef(); + Ref ref = playerRef.getReference(); + if (ref != null && ref.isValid()) { + if (precondition == null || precondition.test(playerRef)) { + Store store = ref.getStore(); + World world = store.getExternalData().getWorld(); + world.execute(() -> { + if (ref.isValid()) { + handler.handle((T)packet, playerRef, ref, world, store); + } + }); + } + } + }); + } +} 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..5df409a0 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/InitialPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/InitialPacketHandler.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.io.handlers; import com.hypixel.hytale.common.util.java.ManifestUtil; import com.hypixel.hytale.logger.HytaleLogger; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.protocol.packets.auth.ConnectAccept; import com.hypixel.hytale.protocol.packets.connection.ClientType; @@ -40,18 +40,18 @@ public class InitialPacketHandler extends PacketHandler { @Nonnull @Override public String getIdentifier() { - return "{Initial(" + NettyUtil.formatRemoteAddress(this.channel) + ")}"; + return "{Initial(" + NettyUtil.formatRemoteAddress(this.getChannel()) + ")}"; } @Override public void registered0(PacketHandler oldHandler) { HytaleServerConfig.TimeoutProfile timeouts = HytaleServer.get().getConfig().getConnectionTimeouts(); this.initStage("initial", timeouts.getInitial(), () -> !this.registered); - PacketHandler.logConnectionTimings(this.channel, "Registered", Level.FINE); + PacketHandler.logConnectionTimings(this.getChannel(), "Registered", Level.FINE); } @Override - public void accept(@Nonnull Packet packet) { + public void accept(@Nonnull ToServerPacket packet) { if (packet.getId() == 0) { this.handle((Connect)packet); } else if (packet.getId() == 1) { @@ -66,18 +66,18 @@ public class InitialPacketHandler extends PacketHandler { if (this.receivedConnect) { super.disconnect(message); } else { - HytaleLogger.getLogger().at(Level.INFO).log("Silently disconnecting %s because no Connect packet!", NettyUtil.formatRemoteAddress(this.channel)); - ProtocolUtil.closeConnection(this.channel); + HytaleLogger.getLogger().at(Level.INFO).log("Silently disconnecting %s because no Connect packet!", NettyUtil.formatRemoteAddress(this.getChannel())); + ProtocolUtil.closeConnection(this.getChannel()); } } public void handle(@Nonnull Connect packet) { this.receivedConnect = true; this.clearTimeout(); - PacketHandler.logConnectionTimings(this.channel, "Connect", Level.FINE); - if (packet.protocolCrc != 1789265863) { + PacketHandler.logConnectionTimings(this.getChannel(), "Connect", Level.FINE); + if (packet.protocolCrc != -1356075132) { int clientBuild = packet.protocolBuildNumber; - int serverBuild = 2; + int serverBuild = 20; int errorCode; if (clientBuild < serverBuild) { errorCode = 5; @@ -86,7 +86,7 @@ public class InitialPacketHandler extends PacketHandler { } String serverVersion = ManifestUtil.getImplementationVersion(); - ProtocolUtil.closeApplicationConnection(this.channel, errorCode, serverVersion != null ? serverVersion : "unknown"); + ProtocolUtil.closeApplicationConnection(this.getChannel(), errorCode, serverVersion != null ? serverVersion : "unknown"); } else if (HytaleServer.get().isShuttingDown()) { this.disconnect("Server is shutting down!"); } else if (!HytaleServer.get().isBooted()) { @@ -98,9 +98,11 @@ public class InitialPacketHandler extends PacketHandler { language = "en-US"; } - boolean isTcpConnection = !(this.channel instanceof QuicStreamChannel); + boolean isTcpConnection = !(this.getChannel() instanceof QuicStreamChannel); if (isTcpConnection) { - HytaleLogger.getLogger().at(Level.INFO).log("TCP connection from %s - only insecure auth supported", NettyUtil.formatRemoteAddress(this.channel)); + HytaleLogger.getLogger() + .at(Level.INFO) + .log("TCP connection from %s - only insecure auth supported", NettyUtil.formatRemoteAddress(this.getChannel())); } if (packet.uuid == null) { @@ -135,7 +137,7 @@ public class InitialPacketHandler extends PacketHandler { if (isTcpConnection) { HytaleLogger.getLogger() .at(Level.WARNING) - .log("Rejecting authenticated connection from %s - TCP only supports insecure auth", NettyUtil.formatRemoteAddress(this.channel)); + .log("Rejecting authenticated connection from %s - TCP only supports insecure auth", NettyUtil.formatRemoteAddress(this.getChannel())); this.disconnect("TCP connections only support insecure authentication. Use QUIC for authenticated connections."); return; } @@ -148,11 +150,11 @@ public class InitialPacketHandler extends PacketHandler { HytaleLogger.getLogger() .at(Level.INFO) - .log("Starting authenticated flow for %s (%s) from %s", packet.username, packet.uuid, NettyUtil.formatRemoteAddress(this.channel)); + .log("Starting authenticated flow for %s (%s) from %s", packet.username, packet.uuid, NettyUtil.formatRemoteAddress(this.getChannel())); NettyUtil.setChannelHandler( - this.channel, + this.getChannel(), new AuthenticationPacketHandler( - this.channel, + this.getChannel(), protocolVersion, language, supplier, @@ -170,7 +172,7 @@ public class InitialPacketHandler extends PacketHandler { .at(Level.WARNING) .log( "Rejecting development connection from %s - server requires authentication (auth-mode=%s)", - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(this.getChannel()), authMode ); this.disconnect("This server requires authentication!"); @@ -181,7 +183,7 @@ public class InitialPacketHandler extends PacketHandler { if (!Constants.SINGLEPLAYER) { HytaleLogger.getLogger() .at(Level.WARNING) - .log("Rejecting connection from %s - offline mode is only valid in singleplayer", NettyUtil.formatRemoteAddress(this.channel)); + .log("Rejecting connection from %s - offline mode is only valid in singleplayer", NettyUtil.formatRemoteAddress(this.getChannel())); this.disconnect("Offline mode is only available in singleplayer."); return; } @@ -202,16 +204,16 @@ public class InitialPacketHandler extends PacketHandler { HytaleLogger.getLogger() .at(Level.INFO) - .log("Starting development flow for %s (%s) from %s", packet.username, packet.uuid, NettyUtil.formatRemoteAddress(this.channel)); + .log("Starting development flow for %s (%s) from %s", packet.username, packet.uuid, NettyUtil.formatRemoteAddress(this.getChannel())); byte[] passwordChallenge = this.generatePasswordChallengeIfNeeded(packet.uuid); this.write(new ConnectAccept(passwordChallenge)); PasswordPacketHandler.SetupHandlerSupplier setupSupplier = isEditorClient && EDITOR_PACKET_HANDLER_SUPPLIER != null ? (ch, pv, lang, auth) -> EDITOR_PACKET_HANDLER_SUPPLIER.create(ch, pv, lang, auth) : SetupPacketHandler::new; NettyUtil.setChannelHandler( - this.channel, + this.getChannel(), new PasswordPacketHandler( - this.channel, + this.getChannel(), protocolVersion, language, packet.uuid, @@ -250,7 +252,7 @@ public class InitialPacketHandler extends PacketHandler { public void handle(@Nonnull Disconnect packet) { this.disconnectReason.setClientDisconnectType(packet.type); - HytaleLogger.getLogger().at(Level.WARNING).log("Disconnecting %s - Sent disconnect packet???", NettyUtil.formatRemoteAddress(this.channel)); - ProtocolUtil.closeApplicationConnection(this.channel); + HytaleLogger.getLogger().at(Level.WARNING).log("Disconnecting %s - Sent disconnect packet???", NettyUtil.formatRemoteAddress(this.getChannel())); + ProtocolUtil.closeApplicationConnection(this.getChannel()); } } 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..1d67535f 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/SetupPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/SetupPacketHandler.java @@ -7,7 +7,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.protocol.Asset; import com.hypixel.hytale.protocol.HostAddress; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.protocol.packets.auth.ClientReferral; import com.hypixel.hytale.protocol.packets.connection.Disconnect; @@ -91,7 +91,7 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { @Override public String getIdentifier() { return "{Setup(" - + NettyUtil.formatRemoteAddress(this.channel) + + NettyUtil.formatRemoteAddress(this.getChannel()) + "), " + this.username + ", " @@ -132,7 +132,7 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { if (otherPlayer != null) { HytaleLogger.getLogger().at(Level.INFO).log("Found match of player %s on %s", this.uuid, otherPlayer.getUsername()); Channel otherPlayerChannel = otherPlayer.getPacketHandler().getChannel(); - if (!NettyUtil.isFromSameOrigin(otherPlayerChannel, this.channel)) { + if (!NettyUtil.isFromSameOrigin(otherPlayerChannel, this.getChannel())) { this.disconnect("You are already logged in on that account!"); otherPlayer.sendMessage(Message.translation("server.io.setuppackethandler.otherLoginAttempt")); return; @@ -154,7 +154,7 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { } } - PacketHandler.logConnectionTimings(this.channel, "Load Player Config", Level.FINE); + PacketHandler.logConnectionTimings(this.getChannel(), "Load Player Config", Level.FINE); WorldSettings worldSettings = new WorldSettings(); worldSettings.worldHeight = 320; Asset[] requiredAssets = CommonAssetModule.get().getRequiredAssets(); @@ -169,7 +169,7 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { } @Override - public void accept(@Nonnull Packet packet) { + public void accept(@Nonnull ToServerPacket packet) { switch (packet.getId()) { case 1: this.handle((Disconnect)packet); @@ -215,9 +215,14 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { HytaleLogger.getLogger() .at(Level.INFO) .log( - "%s - %s at %s left with reason: %s - %s", this.uuid, this.username, NettyUtil.formatRemoteAddress(this.channel), packet.type.name(), packet.reason + "%s - %s at %s left with reason: %s - %s", + this.uuid, + this.username, + NettyUtil.formatRemoteAddress(this.getChannel()), + packet.type.name(), + packet.reason ); - ProtocolUtil.closeApplicationConnection(this.channel); + ProtocolUtil.closeApplicationConnection(this.getChannel()); if (packet.type == DisconnectType.Crash && Constants.SINGLEPLAYER && (Universe.get().getPlayerCount() == 0 || SingleplayerModule.isOwner(this.auth, this.uuid))) { @@ -230,25 +235,25 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { throw new IllegalArgumentException("Received duplicate RequestAssets!"); } else { this.receivedRequest = true; - PacketHandler.logConnectionTimings(this.channel, "Request Assets", Level.FINE); + PacketHandler.logConnectionTimings(this.getChannel(), "Request Assets", Level.FINE); CompletableFuture future = CompletableFutureUtil._catch( HytaleServer.get() .getEventBus() .dispatchForAsync(SendCommonAssetsEvent.class) .dispatch(new SendCommonAssetsEvent(this, packet.assets)) .thenAccept(event -> { - if (this.channel.isActive()) { - PacketHandler.logConnectionTimings(this.channel, "Send Common Assets", Level.FINE); + if (this.getChannel().isActive()) { + PacketHandler.logConnectionTimings(this.getChannel(), "Send Common Assets", Level.FINE); this.assets.sent(event.getRequestedAssets()); 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)); + PacketHandler.logConnectionTimings(this.getChannel(), "Send Config Assets", Level.FINE); + this.write(new WorldLoadProgress(Message.translation("client.general.worldLoad.loadingWorld").getFormattedMessage(), 0, 0)); this.write(new WorldLoadFinished()); } }) .exceptionally(throwable -> { - if (!this.channel.isActive()) { + if (!this.getChannel().isActive()) { return null; } else { this.disconnect("An exception occurred while trying to login!"); @@ -269,8 +274,8 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { if (!this.receivedRequest) { throw new IllegalArgumentException("Hasn't received RequestAssets yet!"); } else { - PacketHandler.logConnectionTimings(this.channel, "Player Options", Level.FINE); - if (this.channel.isActive()) { + PacketHandler.logConnectionTimings(this.getChannel(), "Player Options", Level.FINE); + if (this.getChannel().isActive()) { if (packet.skin != null) { try { CosmeticsModule.get().validateSkin(packet.skin); @@ -284,15 +289,17 @@ public class SetupPacketHandler extends GenericConnectionPacketHandler { CompletableFuture future = CompletableFutureUtil._catch( Universe.get() - .addPlayer(this.channel, this.language, this.protocolVersion, this.uuid, this.username, this.auth, this.clientViewRadiusChunks, packet.skin) + .addPlayer( + this.getChannel(), this.language, this.protocolVersion, this.uuid, this.username, this.auth, this.clientViewRadiusChunks, packet.skin + ) .thenAccept(player -> { - if (this.channel.isActive()) { - PacketHandler.logConnectionTimings(this.channel, "Add To Universe", Level.FINE); + if (this.getChannel().isActive()) { + PacketHandler.logConnectionTimings(this.getChannel(), "Add To Universe", Level.FINE); this.clearTimeout(); } }) .exceptionally(throwable -> { - if (!this.channel.isActive()) { + if (!this.getChannel().isActive()) { return null; } else { this.disconnect("An exception occurred when adding to the universe!"); 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 1d18f4e1..6656d802 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 @@ -13,6 +13,7 @@ import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.BlockRotation; import com.hypixel.hytale.protocol.GameMode; import com.hypixel.hytale.protocol.HostAddress; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.protocol.packets.camera.RequestFlyCameraMode; import com.hypixel.hytale.protocol.packets.camera.SetFlyCameraMode; @@ -44,6 +45,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; @@ -60,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; @@ -73,6 +74,7 @@ import com.hypixel.hytale.server.core.io.ProtocolVersion; import com.hypixel.hytale.server.core.io.ServerManager; import com.hypixel.hytale.server.core.io.handlers.GenericPacketHandler; import com.hypixel.hytale.server.core.io.handlers.IPacketHandler; +import com.hypixel.hytale.server.core.io.handlers.IWorldPacketHandler; import com.hypixel.hytale.server.core.io.handlers.SubPacketHandler; import com.hypixel.hytale.server.core.io.netty.NettyUtil; import com.hypixel.hytale.server.core.modules.entity.EntityModule; @@ -92,9 +94,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; @@ -148,7 +153,7 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa @Override public String getIdentifier() { return "{Playing(" - + NettyUtil.formatRemoteAddress(this.channel) + + NettyUtil.formatRemoteAddress(this.getChannel()) + "), " + (this.playerRef != null ? this.playerRef.getUuid() + ", " + this.playerRef.getUsername() : "null player") + "}"; @@ -167,34 +172,38 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa this.registerHandler(211, p -> this.handle((ChatMessage)p)); this.registerHandler(23, p -> this.handle((RequestAssets)p)); this.registerHandler(219, p -> this.handle((CustomPageEvent)p)); - this.registerHandler(32, p -> this.handle((ViewRadius)p)); - this.registerHandler(232, p -> this.handle((UpdateLanguage)p)); - this.registerHandler(111, p -> this.handle((MouseInteraction)p)); + IWorldPacketHandler.registerHandler(this, 32, this::handleViewRadius); + IWorldPacketHandler.registerHandler(this, 232, this::handleUpdateLanguage); + IWorldPacketHandler.registerHandler(this, 111, this::handleMouseInteraction); this.registerHandler(251, p -> this.handle((UpdateServerAccess)p)); this.registerHandler(252, p -> this.handle((SetServerAccess)p)); - this.registerHandler(204, p -> this.handle((ClientOpenWindow)p)); - this.registerHandler(203, p -> this.handle((SendWindowAction)p)); - this.registerHandler(202, p -> this.handle((CloseWindow)p)); + IWorldPacketHandler.registerHandler(this, 204, this::handleClientOpenWindow); + IWorldPacketHandler.registerHandler(this, 203, this::handleSendWindowAction); + IWorldPacketHandler.registerHandler(this, 202, this::handleCloseWindow); this.registerHandler(260, p -> this.handle((RequestMachinimaActorModel)p)); - this.registerHandler(262, p -> this.handle((UpdateMachinimaScene)p)); + IWorldPacketHandler.registerHandler(this, 262, this::handleUpdateMachinimaScene); this.registerHandler(105, p -> this.handle((ClientReady)p)); - this.registerHandler(166, p -> this.handle((MountMovement)p)); - this.registerHandler(116, p -> this.handle((SyncPlayerPreferences)p)); - this.registerHandler(117, p -> this.handle((ClientPlaceBlock)p)); - this.registerHandler(119, p -> this.handle((RemoveMapMarker)p)); - this.registerHandler(243, p -> this.handle((UpdateWorldMapVisible)p)); - this.registerHandler(244, p -> this.handle((TeleportToWorldMapMarker)p)); - this.registerHandler(245, p -> this.handle((TeleportToWorldMapPosition)p)); + IWorldPacketHandler.registerHandler(this, 166, this::handleMountMovement); + IWorldPacketHandler.registerHandler(this, 116, this::handleSyncPlayerPreferences); + IWorldPacketHandler.registerHandler(this, 117, this::handleClientPlaceBlock); + IWorldPacketHandler.registerHandler(this, 119, this::handleRemoveMapMarker); + IWorldPacketHandler.registerHandler(this, 243, this::handleUpdateWorldMapVisible); + IWorldPacketHandler.registerHandler(this, 244, this::handleTeleportToWorldMapMarker); + IWorldPacketHandler.registerHandler(this, 245, this::handleTeleportToWorldMapPosition); + IWorldPacketHandler.registerHandler(this, 246, this::handleCreateUserMarker); this.registerHandler(290, p -> this.handle((SyncInteractionChains)p)); - this.registerHandler(158, p -> this.handle((SetPaused)p)); - this.registerHandler(282, p -> this.handle((RequestFlyCameraMode)p)); + IWorldPacketHandler.registerHandler(this, 158, this::handleSetPaused); + IWorldPacketHandler.registerHandler(this, 282, this::handleRequestFlyCameraMode); this.packetHandlers.forEach(SubPacketHandler::registerHandlers); } @Override public void closed(ChannelHandlerContext ctx) { super.closed(ctx); - Universe.get().removePlayer(this.playerRef); + NetworkChannel streamChannel = ctx.channel().attr(ProtocolUtil.STREAM_CHANNEL_KEY).get(); + if (streamChannel == null || streamChannel == NetworkChannel.Default) { + Universe.get().removePlayer(this.playerRef); + } } @Override @@ -203,7 +212,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.getChannel()), + this.getSniHostname(), + message + ); this.disconnect0(message); Universe.get().removePlayer(this.playerRef); } else { @@ -219,26 +234,21 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa "%s - %s at %s left with reason: %s - %s", this.playerRef.getUuid(), this.playerRef.getUsername(), - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(this.getChannel()), packet.type.name(), packet.reason ); - ProtocolUtil.closeApplicationConnection(this.channel); + ProtocolUtil.closeApplicationConnection(this.getChannel()); } - public void handle(@Nonnull MouseInteraction packet) { - Ref ref = this.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()); + public void handleMouseInteraction( + @Nonnull MouseInteraction packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - InteractionModule.get().doMouseInteraction(ref, store, packet, playerComponent, this.playerRef); - }); - } + InteractionModule.get().doMouseInteraction(ref, store, packet, playerComponent, playerRef); } public void handle(@Nonnull ClientMovement packet) { @@ -396,224 +406,186 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa Store store = ref.getStore(); World world = store.getExternalData().getWorld(); world.execute(() -> { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (ref.isValid()) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - PageManager pageManager = playerComponent.getPageManager(); - pageManager.handleEvent(ref, store, packet); + PageManager pageManager = playerComponent.getPageManager(); + pageManager.handleEvent(ref, store, packet); + } }); } else { this.playerRef.getPacketHandler().writeNoCache(new SetPage(Page.None, true)); } } - public void handle(@Nonnull ViewRadius packet) { - Ref ref = this.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()); + public void handleViewRadius( + @Nonnull ViewRadius packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - EntityTrackerSystems.EntityViewer entityViewerComponent = store.getComponent(ref, EntityTrackerSystems.EntityViewer.getComponentType()); + EntityTrackerSystems.EntityViewer entityViewerComponent = store.getComponent(ref, EntityTrackerSystems.EntityViewer.getComponentType()); - assert entityViewerComponent != null; + assert entityViewerComponent != null; - int viewRadiusChunks = MathUtil.ceil(packet.value / 32.0F); - playerComponent.setClientViewRadius(viewRadiusChunks); - entityViewerComponent.viewRadiusBlocks = playerComponent.getViewRadius() * 32; - }); - } + int viewRadiusChunks = MathUtil.ceil(packet.value / 32.0F); + playerComponent.setClientViewRadius(viewRadiusChunks); + entityViewerComponent.viewRadiusBlocks = playerComponent.getViewRadius() * 32; } - public void handle(@Nonnull UpdateLanguage packet) { - Ref ref = this.playerRef.getReference(); - if (ref != null && ref.isValid()) { - this.playerRef.setLanguage(packet.language); - I18nModule.get().sendTranslations(this, packet.language); - } + public void handleUpdateLanguage( + @Nonnull UpdateLanguage packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + playerRef.setLanguage(packet.language); + I18nModule.get().sendTranslations(this, packet.language); } - protected void handle(@Nonnull ClientOpenWindow packet) { - Ref ref = this.playerRef.getReference(); - if (ref != null && ref.isValid()) { - Supplier supplier = Window.CLIENT_REQUESTABLE_WINDOW_TYPES.get(packet.type); - if (supplier == null) { - throw new RuntimeException("Unable to process ClientOpenWindow packet. Window type is not supported!"); - } else { - Store store = ref.getStore(); - World world = store.getExternalData().getWorld(); - world.execute(() -> { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); + protected void handleClientOpenWindow( + @Nonnull ClientOpenWindow packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Supplier supplier = Window.CLIENT_REQUESTABLE_WINDOW_TYPES.get(packet.type); + if (supplier == null) { + throw new RuntimeException("Unable to process ClientOpenWindow packet. Window type is not supported!"); + } else { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - UpdateWindow updateWindowPacket = playerComponent.getWindowManager().clientOpenWindow(ref, supplier.get(), store); - if (updateWindowPacket != null) { - this.writeNoCache(updateWindowPacket); - } - }); + UpdateWindow updateWindowPacket = playerComponent.getWindowManager().clientOpenWindow(ref, supplier.get(), store); + if (updateWindowPacket != null) { + this.writeNoCache(updateWindowPacket); } } } - public void handle(@Nonnull SendWindowAction packet) { - Ref ref = this.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()); + public void handleSendWindowAction( + @Nonnull SendWindowAction packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - Window window = playerComponent.getWindowManager().getWindow(packet.id); - if (window != null) { - if (window instanceof ValidatedWindow validatedWindow && !validatedWindow.validate(ref, store)) { - window.close(ref, store); - } else { - window.handleAction(this.playerRef.getReference(), store, packet.action); - } - } - }); + Window window = playerComponent.getWindowManager().getWindow(packet.id); + if (window != null) { + if (window instanceof ValidatedWindow validatedWindow && !validatedWindow.validate(ref, store)) { + window.close(ref, store); + } else { + window.handleAction(ref, store, packet.action); + } } } - public void handle(@Nonnull SyncPlayerPreferences packet) { - Ref ref = this.playerRef.getReference(); - if (ref != null && ref.isValid()) { - Store store = ref.getStore(); - World world = store.getExternalData().getWorld(); - world.execute( - () -> { - ComponentType componentType = EntityModule.get().getPlayerSettingsComponentType(); - store.putComponent( - ref, - componentType, - new PlayerSettings( - packet.showEntityMarkers, - packet.armorItemsPreferredPickupLocation, - packet.weaponAndToolItemsPreferredPickupLocation, - packet.usableItemsItemsPreferredPickupLocation, - packet.solidBlockItemsPreferredPickupLocation, - packet.miscItemsPreferredPickupLocation, - new PlayerCreativeSettings(packet.allowNPCDetection, packet.respondToHit), - packet.hideHelmet, - packet.hideCuirass, - packet.hideGauntlets, - packet.hidePants - ) - ); - store.getComponent(ref, Player.getComponentType()).invalidateEquipmentNetwork(); - } - ); - } + public void handleSyncPlayerPreferences( + @Nonnull SyncPlayerPreferences packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + ComponentType componentType = EntityModule.get().getPlayerSettingsComponentType(); + store.putComponent( + ref, + componentType, + new PlayerSettings( + packet.showEntityMarkers, + packet.armorItemsPreferredPickupLocation, + packet.weaponAndToolItemsPreferredPickupLocation, + packet.usableItemsItemsPreferredPickupLocation, + packet.solidBlockItemsPreferredPickupLocation, + packet.miscItemsPreferredPickupLocation, + new PlayerCreativeSettings(packet.allowNPCDetection, packet.respondToHit), + packet.hideHelmet, + packet.hideCuirass, + packet.hideGauntlets, + packet.hidePants + ) + ); + store.getComponent(ref, Player.getComponentType()).invalidateEquipmentNetwork(); } - public void handle(@Nonnull ClientPlaceBlock packet) { - Ref ref = this.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()); + public void handleClientPlaceBlock( + @Nonnull ClientPlaceBlock packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - Inventory inventory = playerComponent.getInventory(); - 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()); + Inventory inventory = playerComponent.getInventory(); + 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()); + Store chunkStore = world.getChunkStore().getStore(); + long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); + Ref chunkReference = chunkStore.getExternalData().getChunkReference(chunkIndex); + if (chunkReference != null) { + BlockChunk blockChunk = chunkStore.getComponent(chunkReference, BlockChunk.getComponentType()); + 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) > 36.0) { + if (position.distanceSquaredTo(blockCenter) > 49.0) { + section.invalidateBlock(targetBlock.x, targetBlock.y, targetBlock.z); return; } } - Store chunkStore = world.getChunkStore().getStore(); - long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z); - Ref chunkReference = chunkStore.getExternalData().getChunkReference(chunkIndex); - if (chunkReference != null) { - BlockChunk blockChunk = chunkStore.getComponent(chunkReference, BlockChunk.getComponentType()); - if (blockChunk != null) { - BlockSection section = blockChunk.getSectionAtBlockY(targetBlock.y); - if (section != null) { - ItemStack itemInHand = playerComponent.getInventory().getItemInHand(); - if (itemInHand == null) { - section.invalidateBlock(targetBlock.x, targetBlock.y, targetBlock.z); - } else { - String heldBlockKey = itemInHand.getBlockKey(); - if (heldBlockKey == null) { - section.invalidateBlock(targetBlock.x, targetBlock.y, targetBlock.z); - } else { - if (packet.placedBlockId != -1) { - String clientPlacedBlockTypeKey = BlockType.getAssetMap().getAsset(packet.placedBlockId).getId(); - BlockType heldBlockType = BlockType.getAssetMap().getAsset(heldBlockKey); - if (heldBlockType != null && BlockPlaceUtils.canPlaceBlock(heldBlockType, clientPlacedBlockTypeKey)) { - heldBlockKey = clientPlacedBlockTypeKey; - } - } - - BlockPlaceUtils.placeBlock( - ref, - itemInHand, - heldBlockKey, - inventory.getHotbar(), - Vector3i.ZERO, - targetBlock, - blockRotation, - inventory, - inventory.getActiveHotbarSlot(), - playerComponent.getGameMode() != GameMode.Creative, - chunkReference, - chunkStore, - store - ); - } + ItemStack itemInHand = playerComponent.getInventory().getItemInHand(); + if (itemInHand == null) { + section.invalidateBlock(targetBlock.x, targetBlock.y, targetBlock.z); + } else { + String heldBlockKey = itemInHand.getBlockKey(); + if (heldBlockKey == null) { + section.invalidateBlock(targetBlock.x, targetBlock.y, targetBlock.z); + } else { + if (packet.placedBlockId != -1) { + String clientPlacedBlockTypeKey = BlockType.getAssetMap().getAsset(packet.placedBlockId).getId(); + BlockType heldBlockType = BlockType.getAssetMap().getAsset(heldBlockKey); + if (heldBlockType != null && BlockPlaceUtils.canPlaceBlock(heldBlockType, clientPlacedBlockTypeKey)) { + heldBlockKey = clientPlacedBlockTypeKey; } } + + BlockPlaceUtils.placeBlock( + ref, + itemInHand, + heldBlockKey, + inventory.getHotbar(), + Vector3i.ZERO, + targetBlock, + blockRotation, + inventory, + inventory.getActiveHotbarSlot(), + playerComponent.getGameMode() != GameMode.Creative, + chunkReference, + chunkStore, + store + ); } } } - ); + } } } - public void handle(@Nonnull RemoveMapMarker packet) { - Ref ref = this.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()); - - assert playerComponent != null; - - PlayerWorldData perWorldData = playerComponent.getPlayerConfigData().getPerWorldData(world.getName()); - perWorldData.removeLastDeath(packet.markerId); - }); - } + public void handleRemoveMapMarker( + @Nonnull RemoveMapMarker packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + world.getWorldMapManager().handleUserRemoveMarker(playerRef, packet); } - public void handle(@Nonnull CloseWindow packet) { - Ref ref = this.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()); + public void handleCloseWindow( + @Nonnull CloseWindow packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - playerComponent.getWindowManager().closeWindow(ref, packet.id, store); - }); - } + playerComponent.getWindowManager().closeWindow(ref, packet.id, store); } public void handle(@Nonnull UpdateServerAccess packet) { @@ -655,7 +627,13 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa this.writeNoCache(new SetMachinimaActorModel(Model.createUnitScaleModel(modelAsset).toPacket(), packet.sceneName, packet.actorName)); } - public void handle(@Nonnull UpdateMachinimaScene packet) { + public void handleUpdateMachinimaScene( + @Nonnull UpdateMachinimaScene packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { } public void handle(@Nonnull ClientReady packet) { @@ -676,149 +654,152 @@ public class GamePacketHandler extends GenericPacketHandler implements IPacketHa Store store = ref.getStore(); World world = store.getExternalData().getWorld(); world.execute(() -> { - Player playerComponent = store.getComponent(ref, Player.getComponentType()); + if (ref.isValid()) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - playerComponent.handleClientReady(false); - }); - } - } - - public void handle(@Nonnull UpdateWorldMapVisible packet) { - Ref ref = this.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()); - - assert playerComponent != null; - - playerComponent.getWorldMapTracker().setClientHasWorldMapVisible(packet.visible); - }); - } - } - - public void handle(@Nonnull TeleportToWorldMapMarker packet) { - Ref ref = this.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()); - - assert playerComponent != null; - - WorldMapTracker worldMapTracker = playerComponent.getWorldMapTracker(); - if (!worldMapTracker.isAllowTeleportToMarkers()) { - this.disconnect("You are not allowed to use TeleportToWorldMapMarker!"); - } else { - MapMarker marker = worldMapTracker.getSentMarkers().get(packet.id); - if (marker != null) { - Transform transform = PositionUtil.toTransform(marker.transform); - Teleport teleportComponent = Teleport.createForPlayer(transform); - world.getEntityStore().getStore().addComponent(this.playerRef.getReference(), Teleport.getComponentType(), teleportComponent); - } + playerComponent.handleClientReady(false); } }); } } - public void handle(@Nonnull TeleportToWorldMapPosition packet) { - Ref ref = this.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()); + public void handleUpdateWorldMapVisible( + @Nonnull UpdateWorldMapVisible packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - WorldMapTracker worldMapTracker = playerComponent.getWorldMapTracker(); - if (!worldMapTracker.isAllowTeleportToCoordinates()) { - this.disconnect("You are not allowed to use TeleportToWorldMapMarker!"); - } else { - world.getChunkStore().getChunkReferenceAsync(ChunkUtil.indexChunkFromBlock(packet.x, packet.y)).thenAcceptAsync(chunkRef -> { - BlockChunk blockChunkComponent = world.getChunkStore().getStore().getComponent((Ref)chunkRef, BlockChunk.getComponentType()); + playerComponent.getWorldMapTracker().setClientHasWorldMapVisible(packet.visible); + } - assert blockChunkComponent != null; + public void handleTeleportToWorldMapMarker( + @Nonnull TeleportToWorldMapMarker packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - Vector3d position = new Vector3d(packet.x, blockChunkComponent.getHeight(packet.x, packet.y) + 2, packet.y); - Teleport teleportComponent = Teleport.createForPlayer(null, position, new Vector3f(0.0F, 0.0F, 0.0F)); - world.getEntityStore().getStore().addComponent(this.playerRef.getReference(), Teleport.getComponentType(), teleportComponent); - }, world); + assert playerComponent != null; + + WorldMapTracker worldMapTracker = playerComponent.getWorldMapTracker(); + if (!worldMapTracker.isAllowTeleportToMarkers()) { + this.disconnect("You are not allowed to use TeleportToWorldMapMarker!"); + } else { + 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(playerRef.getReference(), Teleport.getComponentType(), teleportComponent); + } } } + public void handleTeleportToWorldMapPosition( + @Nonnull TeleportToWorldMapPosition packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); + + assert playerComponent != null; + + WorldMapTracker worldMapTracker = playerComponent.getWorldMapTracker(); + if (!worldMapTracker.isAllowTeleportToCoordinates()) { + this.disconnect("You are not allowed to use TeleportToWorldMapMarker!"); + } else { + world.getChunkStore().getChunkReferenceAsync(ChunkUtil.indexChunkFromBlock(packet.x, packet.y)).thenAcceptAsync(chunkRef -> { + BlockChunk blockChunkComponent = world.getChunkStore().getStore().getComponent((Ref)chunkRef, BlockChunk.getComponentType()); + + assert blockChunkComponent != null; + + Vector3d position = new Vector3d(packet.x, blockChunkComponent.getHeight(packet.x, packet.y) + 2, packet.y); + Teleport teleportComponent = Teleport.createForPlayer(null, position, new Vector3f(0.0F, 0.0F, 0.0F)); + world.getEntityStore().getStore().addComponent(playerRef.getReference(), Teleport.getComponentType(), teleportComponent); + }, world); + } + } + + public void handleCreateUserMarker( + @Nonnull CreateUserMarker packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + WorldMapManager worldMapManager = world.getWorldMapManager(); + worldMapManager.handleUserCreateMarker(playerRef, packet); + } + public void handle(@Nonnull SyncInteractionChains packet) { Collections.addAll(this.interactionPacketQueue, packet.updates); } - public void handle(@Nonnull MountMovement packet) { - Ref ref = this.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()); + public void handleMountMovement( + @Nonnull MountMovement packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - Ref entityReference = world.getEntityStore().getRefFromNetworkId(playerComponent.getMountEntityId()); - if (entityReference != null && entityReference.isValid()) { - TransformComponent transformComponent = store.getComponent(entityReference, TransformComponent.getComponentType()); + Ref entityReference = world.getEntityStore().getRefFromNetworkId(playerComponent.getMountEntityId()); + if (entityReference != null && entityReference.isValid()) { + TransformComponent transformComponent = store.getComponent(entityReference, TransformComponent.getComponentType()); - assert transformComponent != null; + assert transformComponent != null; - transformComponent.setPosition(PositionUtil.toVector3d(packet.absolutePosition)); - transformComponent.setRotation(PositionUtil.toRotation(packet.bodyOrientation)); - MovementStatesComponent movementStatesComponent = store.getComponent(entityReference, MovementStatesComponent.getComponentType()); + transformComponent.setPosition(PositionUtil.toVector3d(packet.absolutePosition)); + transformComponent.setRotation(PositionUtil.toRotation(packet.bodyOrientation)); + MovementStatesComponent movementStatesComponent = store.getComponent(entityReference, MovementStatesComponent.getComponentType()); - assert movementStatesComponent != null; + assert movementStatesComponent != null; - movementStatesComponent.setMovementStates(packet.movementStates); - } - }); + movementStatesComponent.setMovementStates(packet.movementStates); } } - public void handle(@Nonnull SetPaused packet) { - Ref ref = this.playerRef.getReference(); - if (ref != null && ref.isValid()) { - Store store = ref.getStore(); - World world = store.getExternalData().getWorld(); - world.execute(() -> { - if (world.getPlayerCount() == 1 && Constants.SINGLEPLAYER) { - world.setPaused(packet.paused); - } - }); + public void handleSetPaused( + @Nonnull SetPaused packet, @Nonnull PlayerRef playerRef, @Nonnull Ref ref, @Nonnull World world, @Nonnull Store store + ) { + if (world.getPlayerCount() == 1 && Constants.SINGLEPLAYER) { + world.setPaused(packet.paused); } } - public void handle(@Nonnull RequestFlyCameraMode packet) { - Ref ref = this.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()); + public void handleRequestFlyCameraMode( + @Nonnull RequestFlyCameraMode packet, + @Nonnull PlayerRef playerRef, + @Nonnull Ref ref, + @Nonnull World world, + @Nonnull Store store + ) { + Player playerComponent = store.getComponent(ref, Player.getComponentType()); - assert playerComponent != null; + assert playerComponent != null; - if (playerComponent.hasPermission("hytale.camera.flycam")) { - this.writeNoCache(new SetFlyCameraMode(packet.entering)); - if (packet.entering) { - this.playerRef.sendMessage(Message.translation("server.general.flyCamera.enabled")); - } else { - this.playerRef.sendMessage(Message.translation("server.general.flyCamera.disabled")); - } - } else { - this.playerRef.sendMessage(Message.translation("server.general.flyCamera.noPermission")); - } - }); + if (playerComponent.hasPermission("hytale.camera.flycam")) { + this.writeNoCache(new SetFlyCameraMode(packet.entering)); + if (packet.entering) { + playerRef.sendMessage(Message.translation("server.general.flyCamera.enabled")); + } else { + playerRef.sendMessage(Message.translation("server.general.flyCamera.disabled")); + } + } else { + playerRef.sendMessage(Message.translation("server.general.flyCamera.noPermission")); } } } 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..c3c0a7ce 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; @@ -38,6 +39,7 @@ import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction import com.hypixel.hytale.server.core.io.PacketHandler; import com.hypixel.hytale.server.core.io.handlers.IPacketHandler; import com.hypixel.hytale.server.core.io.handlers.SubPacketHandler; +import com.hypixel.hytale.server.core.modules.entity.player.PlayerSettings; import com.hypixel.hytale.server.core.modules.item.ItemModule; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.SoundUtil; @@ -254,32 +256,34 @@ public class InventoryPacketHandler implements SubPacketHandler { } else { Inventory inventory = playerComponent.getInventory(); ItemStack itemStack = ItemStack.fromPacket(packet.item); - switch (packet.moveType) { - case EquipOrMergeStack: - Item item = itemStack.getItem(); - ItemArmor itemArmor = item.getArmor(); - if (itemArmor != null) { - inventory.getArmor().setItemStackForSlot((short)itemArmor.getArmorSlot().ordinal(), itemStack); - return; - } - - int quantity = itemStack.getQuantity(); - if (item.getUtility().isUsable()) { - ItemStackTransaction transaction = inventory.getUtility().addItemStack(itemStack); - ItemStack remainder = transaction.getRemainder(); - if (ItemStack.isEmpty(remainder) || remainder.getQuantity() != quantity) { - for (ItemStackSlotTransaction slotTransaction : transaction.getSlotTransactions()) { - if (slotTransaction.succeeded()) { - inventory.setActiveUtilitySlot((byte)slotTransaction.getSlot()); - } - } + if (itemStack != null) { + switch (packet.moveType) { + case EquipOrMergeStack: + Item item = itemStack.getItem(); + ItemArmor itemArmor = item.getArmor(); + if (itemArmor != null) { + inventory.getArmor().setItemStackForSlot((short)itemArmor.getArmorSlot().ordinal(), itemStack); + return; } - return; - } - break; - case PutInHotbarOrWindow: - inventory.getCombinedHotbarFirst().addItemStack(itemStack); + int quantity = itemStack.getQuantity(); + if (item.getUtility().isUsable()) { + ItemStackTransaction transaction = inventory.getUtility().addItemStack(itemStack); + ItemStack remainder = transaction.getRemainder(); + if (ItemStack.isEmpty(remainder) || remainder.getQuantity() != quantity) { + for (ItemStackSlotTransaction slotTransaction : transaction.getSlotTransactions()) { + if (slotTransaction.succeeded()) { + inventory.setActiveUtilitySlot((byte)slotTransaction.getSlot()); + } + } + } + + return; + } + break; + case PutInHotbarOrWindow: + playerComponent.giveItem(itemStack, ref, store); + } } } } @@ -374,7 +378,12 @@ public class InventoryPacketHandler implements SubPacketHandler { assert playerComponent != null; Inventory inventory = playerComponent.getInventory(); - inventory.smartMoveItem(packet.fromSectionId, packet.fromSlotId, packet.quantity, packet.moveType); + PlayerSettings settings = store.getComponent(ref, PlayerSettings.getComponentType()); + if (settings == null) { + settings = PlayerSettings.defaults(); + } + + inventory.smartMoveItem(packet.fromSectionId, packet.fromSlotId, packet.quantity, packet.moveType, settings); }); } } @@ -428,62 +437,77 @@ 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; - } + Inventory inventory = playerComponent.getInventory(); + PlayerSettings settings = store.getComponent(ref, PlayerSettings.getComponentType()); + if (settings == null) { + settings = PlayerSettings.defaults(); + } - 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); + switch (packet.inventoryActionType) { + case TakeAll: + if (packet.inventorySectionId == -9) { + inventory.takeAll(packet.inventorySectionId, settings); 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); + inventory.takeAllWithPriority(outputContainer, settings); + } + } else { + inventory.takeAll(packet.inventorySectionId, settings); + } } - } + 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/AuthenticationPacketHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/login/AuthenticationPacketHandler.java index aa08c7a5..56a9bcf2 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/login/AuthenticationPacketHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/login/AuthenticationPacketHandler.java @@ -36,7 +36,7 @@ public class AuthenticationPacketHandler extends HandshakeHandler { @Nonnull @Override public String getIdentifier() { - return "{Authenticating(" + NettyUtil.formatRemoteAddress(this.channel) + "), authHandlerSupplier=" + this.authHandlerSupplier + "}"; + return "{Authenticating(" + NettyUtil.formatRemoteAddress(this.getChannel()) + "), authHandlerSupplier=" + this.authHandlerSupplier + "}"; } @Override @@ -51,11 +51,11 @@ public class AuthenticationPacketHandler extends HandshakeHandler { @Override protected void onAuthenticated(byte[] passwordChallenge) { - PacketHandler.logConnectionTimings(this.channel, "Authenticated", Level.FINE); + PacketHandler.logConnectionTimings(this.getChannel(), "Authenticated", Level.FINE); NettyUtil.setChannelHandler( - this.channel, + this.getChannel(), new PasswordPacketHandler( - this.channel, + this.getChannel(), this.protocolVersion, this.language, this.auth.getUuid(), diff --git a/src/com/hypixel/hytale/server/core/io/handlers/login/HandshakeHandler.java b/src/com/hypixel/hytale/server/core/io/handlers/login/HandshakeHandler.java index aaa1368a..c9e366fb 100644 --- a/src/com/hypixel/hytale/server/core/io/handlers/login/HandshakeHandler.java +++ b/src/com/hypixel/hytale/server/core/io/handlers/login/HandshakeHandler.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.io.handlers.login; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.protocol.HostAddress; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.protocol.packets.auth.AuthGrant; import com.hypixel.hytale.protocol.packets.auth.AuthToken; @@ -90,7 +90,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { } @Override - public void accept(@Nonnull Packet packet) { + public void accept(@Nonnull ToServerPacket packet) { switch (packet.getId()) { case 1: this.handle((Disconnect)packet); @@ -109,7 +109,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { this.enterStage("auth", timeouts.getAuth()); JWTValidator.IdentityTokenClaims identityClaims = getJwtValidator().validateIdentityToken(this.identityToken); if (identityClaims == null) { - LOGGER.at(Level.WARNING).log("Identity token validation failed for %s from %s", this.username, NettyUtil.formatRemoteAddress(this.channel)); + LOGGER.at(Level.WARNING).log("Identity token validation failed for %s from %s", this.username, NettyUtil.formatRemoteAddress(this.getChannel())); this.disconnect("Invalid or expired identity token"); } else { UUID tokenUuid = identityClaims.getSubjectAsUUID(); @@ -120,7 +120,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { .log( "Identity token missing required scope for %s from %s (clientType: %s, required: %s, actual: %s)", this.username, - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(this.getChannel()), this.clientType, requiredScope, identityClaims.scope @@ -133,7 +133,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { this.username, this.playerUuid, identityClaims.scope, - NettyUtil.formatRemoteAddress(this.channel) + NettyUtil.formatRemoteAddress(this.getChannel()) ); this.continueStage("auth:grant", timeouts.getAuthGrant(), () -> this.authState != HandshakeHandler.AuthState.REQUESTING_AUTH_GRANT); this.requestAuthGrant(); @@ -143,7 +143,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { .log( "Identity token UUID mismatch for %s from %s (expected: %s, got: %s)", this.username, - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(this.getChannel()), this.playerUuid, tokenUuid ); @@ -155,21 +155,21 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { private void requestAuthGrant() { String serverSessionToken = ServerAuthManager.getInstance().getSessionToken(); if (serverSessionToken != null && !serverSessionToken.isEmpty()) { + Channel channel = this.getChannel(); getSessionServiceClient() .requestAuthorizationGrantAsync(this.identityToken, AuthConfig.getServerAudience(), serverSessionToken) .thenAccept( authGrant -> { - if (this.channel.isActive()) { + if (channel.isActive()) { if (authGrant == null) { - this.channel.eventLoop().execute(() -> this.disconnect("Failed to obtain authorization grant from session service")); + channel.eventLoop().execute(() -> this.disconnect("Failed to obtain authorization grant from session service")); } else { String serverIdentityToken = ServerAuthManager.getInstance().getIdentityToken(); if (serverIdentityToken != null && !serverIdentityToken.isEmpty()) { - this.channel - .eventLoop() + channel.eventLoop() .execute( () -> { - if (this.channel.isActive()) { + if (channel.isActive()) { if (this.authState != HandshakeHandler.AuthState.REQUESTING_AUTH_GRANT) { LOGGER.at(Level.WARNING).log("State changed during auth grant request, current state: %s", this.authState); } else { @@ -177,7 +177,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { LOGGER.at(Level.INFO) .log( "Sending AuthGrant to %s (with server identity: %s)", - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(channel), !serverIdentityToken.isEmpty() ); this.write(new AuthGrant(authGrant, serverIdentityToken)); @@ -192,7 +192,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { ); } else { LOGGER.at(Level.SEVERE).log("Server identity token not available - cannot complete mutual authentication"); - this.channel.eventLoop().execute(() -> this.disconnect("Server authentication unavailable - please try again later")); + channel.eventLoop().execute(() -> this.disconnect("Server authentication unavailable - please try again later")); } } } @@ -200,7 +200,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { ) .exceptionally(ex -> { LOGGER.at(Level.WARNING).withCause(ex).log("Error requesting auth grant"); - this.channel.eventLoop().execute(() -> this.disconnect("Authentication error: " + ex.getMessage())); + channel.eventLoop().execute(() -> this.disconnect("Authentication error: " + ex.getMessage())); return null; }); } else { @@ -216,19 +216,20 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { "%s (%s) at %s left with reason: %s - %s", this.playerUuid, this.username, - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(this.getChannel()), packet.type.name(), packet.reason ); - ProtocolUtil.closeApplicationConnection(this.channel); + ProtocolUtil.closeApplicationConnection(this.getChannel()); } public void handle(@Nonnull AuthToken packet) { + Channel channel = this.getChannel(); if (this.authState != HandshakeHandler.AuthState.AWAITING_AUTH_TOKEN) { - LOGGER.at(Level.WARNING).log("Received unexpected AuthToken packet in state %s from %s", this.authState, NettyUtil.formatRemoteAddress(this.channel)); + LOGGER.at(Level.WARNING).log("Received unexpected AuthToken packet in state %s from %s", this.authState, NettyUtil.formatRemoteAddress(channel)); this.disconnect("Protocol error: unexpected AuthToken packet"); } else if (this.authTokenPacketReceived) { - LOGGER.at(Level.WARNING).log("Received duplicate AuthToken packet from %s", NettyUtil.formatRemoteAddress(this.channel)); + LOGGER.at(Level.WARNING).log("Received duplicate AuthToken packet from %s", NettyUtil.formatRemoteAddress(channel)); this.disconnect("Protocol error: duplicate AuthToken packet"); } else { this.authTokenPacketReceived = true; @@ -237,31 +238,31 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { String accessToken = packet.accessToken; if (accessToken != null && !accessToken.isEmpty()) { String serverAuthGrant = packet.serverAuthorizationGrant; - X509Certificate clientCert = this.channel.attr(QUICTransport.CLIENT_CERTIFICATE_ATTR).get(); + X509Certificate clientCert = channel.attr(QUICTransport.CLIENT_CERTIFICATE_ATTR).get(); LOGGER.at(Level.INFO) .log( "Received AuthToken from %s, validating JWT (mTLS cert present: %s, server auth grant: %s)", - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(channel), clientCert != null, serverAuthGrant != null && !serverAuthGrant.isEmpty() ); JWTValidator.JWTClaims claims = getJwtValidator().validateToken(accessToken, clientCert); if (claims == null) { - LOGGER.at(Level.WARNING).log("JWT validation failed for %s", NettyUtil.formatRemoteAddress(this.channel)); + LOGGER.at(Level.WARNING).log("JWT validation failed for %s", NettyUtil.formatRemoteAddress(channel)); this.disconnect("Invalid access token"); } else { UUID tokenUuid = claims.getSubjectAsUUID(); String tokenUsername = claims.username; if (tokenUuid == null || !tokenUuid.equals(this.playerUuid)) { LOGGER.at(Level.WARNING) - .log("JWT UUID mismatch for %s (expected: %s, got: %s)", NettyUtil.formatRemoteAddress(this.channel), this.playerUuid, tokenUuid); + .log("JWT UUID mismatch for %s (expected: %s, got: %s)", NettyUtil.formatRemoteAddress(channel), this.playerUuid, tokenUuid); this.disconnect("Invalid token claims: UUID mismatch"); } else if (tokenUsername == null || tokenUsername.isEmpty()) { - LOGGER.at(Level.WARNING).log("JWT missing username for %s", NettyUtil.formatRemoteAddress(this.channel)); + LOGGER.at(Level.WARNING).log("JWT missing username for %s", NettyUtil.formatRemoteAddress(channel)); this.disconnect("Invalid token claims: missing username"); } else if (!tokenUsername.equals(this.username)) { LOGGER.at(Level.WARNING) - .log("JWT username mismatch for %s (expected: %s, got: %s)", NettyUtil.formatRemoteAddress(this.channel), this.username, tokenUsername); + .log("JWT username mismatch for %s (expected: %s, got: %s)", NettyUtil.formatRemoteAddress(channel), this.username, tokenUsername); this.disconnect("Invalid token claims: username mismatch"); } else { this.authenticatedUsername = tokenUsername; @@ -279,7 +280,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { } } } else { - LOGGER.at(Level.WARNING).log("Received AuthToken packet with empty access token from %s", NettyUtil.formatRemoteAddress(this.channel)); + LOGGER.at(Level.WARNING).log("Received AuthToken packet with empty access token from %s", NettyUtil.formatRemoteAddress(channel)); this.disconnect("Invalid access token"); } } @@ -308,16 +309,16 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { } else { LOGGER.at(Level.FINE) .log("Using session token (first 20 chars): %s...", serverSessionToken.length() > 20 ? serverSessionToken.substring(0, 20) : serverSessionToken); + Channel channel = this.getChannel(); getSessionServiceClient() .exchangeAuthGrantForTokenAsync(serverAuthGrant, serverCertFingerprint, serverSessionToken) .thenAccept( serverAccessToken -> { - if (this.channel.isActive()) { - this.channel - .eventLoop() + if (channel.isActive()) { + channel.eventLoop() .execute( () -> { - if (this.channel.isActive()) { + if (channel.isActive()) { if (this.authState != HandshakeHandler.AuthState.EXCHANGING_SERVER_TOKEN) { LOGGER.at(Level.WARNING).log("State changed during server token exchange, current state: %s", this.authState); } else if (serverAccessToken == null) { @@ -328,7 +329,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { LOGGER.at(Level.INFO) .log( "Sending ServerAuthToken to %s (with password challenge: %s)", - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(channel), passwordChallenge != null ); this.write(new ServerAuthToken(serverAccessToken, passwordChallenge)); @@ -342,7 +343,7 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { ) .exceptionally(ex -> { LOGGER.at(Level.WARNING).withCause(ex).log("Error exchanging server auth grant"); - this.channel.eventLoop().execute(() -> { + channel.eventLoop().execute(() -> { if (this.authState == HandshakeHandler.AuthState.EXCHANGING_SERVER_TOKEN) { this.disconnect("Server authentication failed - please try again later"); } @@ -384,7 +385,9 @@ public abstract class HandshakeHandler extends GenericConnectionPacketHandler { this.authState = HandshakeHandler.AuthState.AUTHENTICATED; this.clearTimeout(); LOGGER.at(Level.INFO) - .log("Mutual authentication complete for %s (%s) from %s", this.authenticatedUsername, this.playerUuid, NettyUtil.formatRemoteAddress(this.channel)); + .log( + "Mutual authentication complete for %s (%s) from %s", this.authenticatedUsername, this.playerUuid, NettyUtil.formatRemoteAddress(this.getChannel()) + ); this.onAuthenticated(passwordChallenge); } 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..f89a71b0 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 @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.io.handlers.login; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.protocol.HostAddress; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.protocol.packets.auth.PasswordAccepted; import com.hypixel.hytale.protocol.packets.auth.PasswordRejected; @@ -60,7 +60,7 @@ public class PasswordPacketHandler extends GenericConnectionPacketHandler { @Nonnull @Override public String getIdentifier() { - return "{Password(" + NettyUtil.formatRemoteAddress(this.channel) + "), " + this.username + "}"; + return "{Password(" + NettyUtil.formatRemoteAddress(this.getChannel()) + "), " + this.username + "}"; } @Override @@ -76,7 +76,7 @@ public class PasswordPacketHandler extends GenericConnectionPacketHandler { } @Override - public void accept(@Nonnull Packet packet) { + public void accept(@Nonnull ToServerPacket packet) { switch (packet.getId()) { case 1: this.handle((Disconnect)packet); @@ -96,11 +96,11 @@ public class PasswordPacketHandler extends GenericConnectionPacketHandler { "%s (%s) at %s left with reason: %s - %s", this.playerUuid, this.username, - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(this.getChannel()), packet.type.name(), packet.reason ); - ProtocolUtil.closeApplicationConnection(this.channel); + ProtocolUtil.closeApplicationConnection(this.getChannel()); } public void handle(@Nonnull PasswordResponse packet) { @@ -120,7 +120,7 @@ public class PasswordPacketHandler extends GenericConnectionPacketHandler { .log( "Invalid password from %s (%s), %d attempts remaining", this.username, - NettyUtil.formatRemoteAddress(this.channel), + NettyUtil.formatRemoteAddress(this.getChannel()), this.attemptsRemaining ); if (this.attemptsRemaining <= 0) { @@ -141,11 +141,11 @@ public class PasswordPacketHandler extends GenericConnectionPacketHandler { this.disconnect("Server configuration error"); } } else { - LOGGER.at(Level.WARNING).log("Received empty password hash from %s", NettyUtil.formatRemoteAddress(this.channel)); + LOGGER.at(Level.WARNING).log("Received empty password hash from %s", NettyUtil.formatRemoteAddress(this.getChannel())); this.disconnect("Invalid password response"); } } else { - LOGGER.at(Level.WARNING).log("Received unexpected PasswordResponse from %s - no password required", NettyUtil.formatRemoteAddress(this.channel)); + LOGGER.at(Level.WARNING).log("Received unexpected PasswordResponse from %s - no password required", NettyUtil.formatRemoteAddress(this.getChannel())); this.disconnect("Protocol error: unexpected PasswordResponse"); } } @@ -166,8 +166,8 @@ 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); - NettyUtil.setChannelHandler(this.channel, this.setupHandlerSupplier.create(this.channel, this.protocolVersion, this.language, this.auth)); + LOGGER.at(Level.INFO).log("Connection complete for %s (%s) (SNI: %s), transitioning to setup", this.username, this.playerUuid, this.getSniHostname()); + NettyUtil.setChannelHandler(this.getChannel(), this.setupHandlerSupplier.create(this.getChannel(), this.protocolVersion, this.language, this.auth)); } @Nullable diff --git a/src/com/hypixel/hytale/server/core/io/netty/HytaleChannelInitializer.java b/src/com/hypixel/hytale/server/core/io/netty/HytaleChannelInitializer.java index e07cd72e..03f4e20c 100644 --- a/src/com/hypixel/hytale/server/core/io/netty/HytaleChannelInitializer.java +++ b/src/com/hypixel/hytale/server/core/io/netty/HytaleChannelInitializer.java @@ -9,7 +9,7 @@ import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.protocol.packets.connection.Disconnect; import com.hypixel.hytale.protocol.packets.connection.DisconnectType; import com.hypixel.hytale.server.core.HytaleServer; -import com.hypixel.hytale.server.core.HytaleServerConfig; +import com.hypixel.hytale.server.core.config.RateLimitConfig; import com.hypixel.hytale.server.core.io.PacketStatsRecorderImpl; import com.hypixel.hytale.server.core.io.handlers.InitialPacketHandler; import com.hypixel.hytale.server.core.io.transport.QUICTransport; @@ -61,18 +61,30 @@ public class HytaleChannelInitializer extends ChannelInitializer { .log("Received connection from %s to %s", NettyUtil.formatRemoteAddress(channel), NettyUtil.formatLocalAddress(channel)); } - PacketStatsRecorderImpl statsRecorder = new PacketStatsRecorderImpl(); - channel.attr(PacketStatsRecorder.CHANNEL_KEY).set(statsRecorder); - Duration initialTimeout = HytaleServer.get().getConfig().getConnectionTimeouts().getInitial(); - channel.attr(ProtocolUtil.PACKET_TIMEOUT_KEY).set(initialTimeout); - channel.pipeline().addLast("packetDecoder", new PacketDecoder()); - HytaleServerConfig.RateLimitConfig rateLimitConfig = HytaleServer.get().getConfig().getRateLimitConfig(); - if (rateLimitConfig.isEnabled()) { - channel.pipeline().addLast("rateLimit", new RateLimitHandler(rateLimitConfig.getBurstCapacity(), rateLimitConfig.getPacketsPerSecond())); + boolean canRead = true; + boolean canWrite = true; + if (channel instanceof QuicStreamChannel streamChannel) { + canRead = !streamChannel.isInputShutdown(); + canWrite = !streamChannel.isOutputShutdown(); + } + + PacketStatsRecorderImpl statsRecorder = new PacketStatsRecorderImpl(); + channel.attr(PacketStatsRecorder.CHANNEL_KEY).set(statsRecorder); + if (canRead) { + Duration initialTimeout = HytaleServer.get().getConfig().getConnectionTimeouts().getInitial(); + channel.attr(ProtocolUtil.PACKET_TIMEOUT_KEY).set(initialTimeout); + channel.pipeline().addLast("packetDecoder", new PacketDecoder()); + RateLimitConfig rateLimitConfig = HytaleServer.get().getConfig().getRateLimitConfig(); + if (rateLimitConfig.isEnabled()) { + channel.pipeline().addLast("rateLimit", new RateLimitHandler(rateLimitConfig.getBurstCapacity(), rateLimitConfig.getPacketsPerSecond())); + } + } + + if (canWrite) { + channel.pipeline().addLast("packetEncoder", new PacketEncoder()); + channel.pipeline().addLast("packetArrayEncoder", NettyUtil.PACKET_ARRAY_ENCODER_INSTANCE); } - channel.pipeline().addLast("packetEncoder", new PacketEncoder()); - channel.pipeline().addLast("packetArrayEncoder", NettyUtil.PACKET_ARRAY_ENCODER_INSTANCE); if (NettyUtil.PACKET_LOGGER.getLevel() != Level.OFF) { channel.pipeline().addLast("logger", NettyUtil.LOGGER); } diff --git a/src/com/hypixel/hytale/server/core/io/netty/NettyUtil.java b/src/com/hypixel/hytale/server/core/io/netty/NettyUtil.java index 8e526220..3833d28d 100644 --- a/src/com/hypixel/hytale/server/core/io/netty/NettyUtil.java +++ b/src/com/hypixel/hytale/server/core/io/netty/NettyUtil.java @@ -2,6 +2,8 @@ package com.hypixel.hytale.server.core.io.netty; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.logger.backend.HytaleLoggerBackend; +import com.hypixel.hytale.protocol.NetworkChannel; +import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.server.core.io.PacketHandler; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.Universe; @@ -27,6 +29,8 @@ import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.quic.QuicChannel; import io.netty.handler.codec.quic.QuicStreamChannel; +import io.netty.handler.codec.quic.QuicStreamPriority; +import io.netty.handler.codec.quic.QuicStreamType; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.util.AttributeKey; @@ -37,6 +41,7 @@ import java.lang.reflect.Constructor; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Objects; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadFactory; import java.util.logging.Level; import javax.annotation.Nonnull; @@ -78,6 +83,33 @@ public class NettyUtil { packetHandler.registered(oldPlayerConnection); } + @Nonnull + public static CompletableFuture createStream( + @Nonnull QuicChannel conn, + @Nonnull QuicStreamType streamType, + @Nonnull NetworkChannel networkChannel, + @Nullable QuicStreamPriority priority, + @Nonnull PacketHandler packetHandler + ) { + CompletableFuture future = new CompletableFuture<>(); + conn.createStream(streamType, new HytaleChannelInitializer()).addListener(result -> { + if (!result.isSuccess()) { + future.completeExceptionally(result.cause()); + } else { + QuicStreamChannel channel = result.getNow(); + channel.attr(ProtocolUtil.STREAM_CHANNEL_KEY).set(networkChannel); + if (priority != null) { + channel.updatePriority(priority); + } + + setChannelHandler(channel, packetHandler); + packetHandler.setChannel(networkChannel, channel); + future.complete(null); + } + }); + return future; + } + @Nonnull public static EventLoopGroup getEventLoopGroup(String name) { return getEventLoopGroup(0, name); diff --git a/src/com/hypixel/hytale/server/core/io/netty/PlayerChannelHandler.java b/src/com/hypixel/hytale/server/core/io/netty/PlayerChannelHandler.java index 5f662f25..19ab586c 100644 --- a/src/com/hypixel/hytale/server/core/io/netty/PlayerChannelHandler.java +++ b/src/com/hypixel/hytale/server/core/io/netty/PlayerChannelHandler.java @@ -1,6 +1,6 @@ package com.hypixel.hytale.server.core.io.netty; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToServerPacket; import com.hypixel.hytale.server.core.io.PacketHandler; import com.hypixel.hytale.server.core.io.adapter.PacketAdapters; import io.netty.channel.ChannelHandlerContext; @@ -26,7 +26,7 @@ public class PlayerChannelHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { if (ctx.channel().isActive()) { - Packet packet = (Packet)msg; + ToServerPacket packet = (ToServerPacket)msg; if (!PacketAdapters.__handleInbound(this.handler, packet)) { this.handler.handle(packet); } 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..40bb2b16 100644 --- a/src/com/hypixel/hytale/server/core/io/transport/QUICTransport.java +++ b/src/com/hypixel/hytale/server/core/io/transport/QUICTransport.java @@ -20,16 +20,20 @@ import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.SocketProtocolFamily; import io.netty.channel.socket.nio.NioChannelOption; -import io.netty.handler.codec.quic.InsecureQuicTokenHandler; +import io.netty.handler.codec.quic.QLogConfiguration; import io.netty.handler.codec.quic.QuicChannel; +import io.netty.handler.codec.quic.QuicChannelOption; import io.netty.handler.codec.quic.QuicCongestionControlAlgorithm; 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 +52,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 +63,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() @@ -138,7 +156,8 @@ public class QUICTransport implements Transport { Duration playTimeout = HytaleServer.get().getConfig().getConnectionTimeouts().getPlay(); ChannelHandler quicHandler = new QuicServerCodecBuilder() .sslContext(this.sslContext) - .tokenHandler(InsecureQuicTokenHandler.INSTANCE) + .tokenHandler(null) + .activeMigration(false) .maxIdleTimeout(playTimeout.toMillis(), TimeUnit.MILLISECONDS) .ackDelayExponent(3L) .initialMaxData(524288L) @@ -149,6 +168,7 @@ public class QUICTransport implements Transport { .initialMaxStreamsBidirectional(1L) .discoverPmtu(true) .congestionControlAlgorithm(QuicCongestionControlAlgorithm.BBR) + .option(QuicChannelOption.QLOG, System.getProperty("hytale.qlog") != null ? new QLogConfiguration(".", "hytale-server-quic-qlogs", "") : null) .handler( new ChannelInboundHandlerAdapter() { @Override @@ -156,18 +176,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 +211,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/accesscontrol/commands/WhitelistStatusCommand.java b/src/com/hypixel/hytale/server/core/modules/accesscontrol/commands/WhitelistStatusCommand.java index 2080f1b9..68fb4a5e 100644 --- a/src/com/hypixel/hytale/server/core/modules/accesscontrol/commands/WhitelistStatusCommand.java +++ b/src/com/hypixel/hytale/server/core/modules/accesscontrol/commands/WhitelistStatusCommand.java @@ -4,7 +4,6 @@ import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase; import com.hypixel.hytale.server.core.modules.accesscontrol.provider.HytaleWhitelistProvider; -import com.hypixel.hytale.server.core.util.message.MessageFormat; import javax.annotation.Nonnull; public class WhitelistStatusCommand extends CommandBase { @@ -18,6 +17,6 @@ public class WhitelistStatusCommand extends CommandBase { @Override protected void executeSync(@Nonnull CommandContext context) { - context.sendMessage(Message.translation("server.modules.whitelist.status").param("status", MessageFormat.enabled(this.whitelistProvider.isEnabled()))); + context.sendMessage(Message.translation("server.modules.whitelist.status").param("enabled", this.whitelistProvider.isEnabled() ? "true" : "false")); } } diff --git a/src/com/hypixel/hytale/server/core/modules/anchoraction/AnchorActionHandler.java b/src/com/hypixel/hytale/server/core/modules/anchoraction/AnchorActionHandler.java new file mode 100644 index 00000000..fae329aa --- /dev/null +++ b/src/com/hypixel/hytale/server/core/modules/anchoraction/AnchorActionHandler.java @@ -0,0 +1,10 @@ +package com.hypixel.hytale.server.core.modules.anchoraction; + +import com.google.gson.JsonObject; +import com.hypixel.hytale.server.core.universe.PlayerRef; +import javax.annotation.Nonnull; + +@FunctionalInterface +public interface AnchorActionHandler { + void handle(@Nonnull PlayerRef var1, @Nonnull JsonObject var2); +} diff --git a/src/com/hypixel/hytale/server/core/modules/anchoraction/AnchorActionModule.java b/src/com/hypixel/hytale/server/core/modules/anchoraction/AnchorActionModule.java new file mode 100644 index 00000000..3ff5dba5 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/modules/anchoraction/AnchorActionModule.java @@ -0,0 +1,83 @@ +package com.hypixel.hytale.server.core.modules.anchoraction; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.hypixel.hytale.common.plugin.PluginManifest; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.logger.HytaleLogger; +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.EntityStore; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import javax.annotation.Nonnull; + +public class AnchorActionModule extends JavaPlugin { + public static final PluginManifest MANIFEST = PluginManifest.corePlugin(AnchorActionModule.class).build(); + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + private static AnchorActionModule instance; + private final Map handlers = new ConcurrentHashMap<>(); + + public static AnchorActionModule get() { + return instance; + } + + public AnchorActionModule(@Nonnull JavaPluginInit init) { + super(init); + instance = this; + } + + public void register(@Nonnull String action, @Nonnull AnchorActionHandler handler) { + this.handlers.put(action, handler); + } + + public void register(@Nonnull String action, @Nonnull AnchorActionModule.WorldThreadAnchorActionHandler handler) { + this.register(action, (playerRef, data) -> { + Ref ref = playerRef.getReference(); + if (ref != null) { + Store store = ref.getStore(); + World world = store.getExternalData().getWorld(); + world.execute(() -> { + if (ref.isValid()) { + handler.handle(playerRef, ref, store, data); + } + }); + } + }); + } + + public void unregister(@Nonnull String action) { + this.handlers.remove(action); + } + + public boolean tryHandle(@Nonnull PlayerRef playerRef, @Nonnull String rawData) { + String action = null; + + try { + JsonObject data = JsonParser.parseString(rawData).getAsJsonObject(); + if (!data.has("action")) { + return false; + } else { + action = data.get("action").getAsString(); + AnchorActionHandler handler = this.handlers.get(action); + if (handler == null) { + return false; + } else { + handler.handle(playerRef, data); + return true; + } + } + } catch (Exception var6) { + LOGGER.atWarning().withCause(var6).log("Failed to handle anchor action '%s' for player %s", action, playerRef.getUuid()); + return false; + } + } + + @FunctionalInterface + public interface WorldThreadAnchorActionHandler { + void handle(@Nonnull PlayerRef var1, @Nonnull Ref var2, @Nonnull Store var3, @Nonnull JsonObject var4); + } +} 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..fc0fb4ff 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,8 @@ 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.ComponentAccessor; +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 +67,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 +119,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 +214,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,8 +256,14 @@ public class BlockModule extends JavaPlugin { } public void markNeedsSaving() { - if (this.chunkRef != null && this.chunkRef.isValid()) { - BlockComponentChunk blockComponentChunk = this.chunkRef.getStore().getComponent(this.chunkRef, BlockComponentChunk.getComponentType()); + if (this.chunkRef.isValid()) { + this.markNeedsSaving(this.chunkRef.getStore()); + } + } + + public void markNeedsSaving(ComponentAccessor accessor) { + if (this.chunkRef.isValid()) { + BlockComponentChunk blockComponentChunk = accessor.getComponent(this.chunkRef, BlockComponentChunk.getComponentType()); if (blockComponentChunk != null) { blockComponentChunk.markNeedsSaving(); } @@ -297,31 +312,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 +351,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 +373,7 @@ public class BlockModule extends JavaPlugin { @Nonnull @Override public String toString() { - return "BlockStateInfoRefSystem{componentType=" + this.componentType + "}"; + return "BlockStateInfoRefSystem{componentType=" + this.blockStateInfoComponentType + "}"; } } @@ -355,13 +381,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/blockhealth/BlockHealthChunk.java b/src/com/hypixel/hytale/server/core/modules/blockhealth/BlockHealthChunk.java index 2bd3b3e4..b1da8850 100644 --- a/src/com/hypixel/hytale/server/core/modules/blockhealth/BlockHealthChunk.java +++ b/src/com/hypixel/hytale/server/core/modules/blockhealth/BlockHealthChunk.java @@ -6,7 +6,7 @@ import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.component.Component; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.BlockPosition; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.world.UpdateBlockDamage; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.World; @@ -109,7 +109,7 @@ public class BlockHealthChunk implements Component { return this.blockHealthMap.getOrDefault(block, BlockHealth.NO_DAMAGE_INSTANCE).getHealth(); } - public void createBlockDamagePackets(@Nonnull List list) { + public void createBlockDamagePackets(@Nonnull List list) { for (Entry entry : this.blockHealthMap.entrySet()) { Vector3i block = entry.getKey(); BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); diff --git a/src/com/hypixel/hytale/server/core/modules/blockhealth/BlockHealthModule.java b/src/com/hypixel/hytale/server/core/modules/blockhealth/BlockHealthModule.java index 3cdfb61d..f0ff66da 100644 --- a/src/com/hypixel/hytale/server/core/modules/blockhealth/BlockHealthModule.java +++ b/src/com/hypixel/hytale/server/core/modules/blockhealth/BlockHealthModule.java @@ -19,7 +19,7 @@ import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.BlockPosition; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.world.UpdateBlockDamage; import com.hypixel.hytale.server.core.asset.type.gameplay.WorldConfig; import com.hypixel.hytale.server.core.event.events.ecs.PlaceBlockEvent; @@ -106,7 +106,7 @@ public class BlockHealthModule extends JavaPlugin { Store store, CommandBuffer commandBuffer, PlayerRef player, - @Nonnull List results + @Nonnull List results ) { BlockHealthChunk blockHealthChunkComponent = archetypeChunk.getComponent(index, this.blockHealthCunkComponentType); 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/debug/DebugUtils.java b/src/com/hypixel/hytale/server/core/modules/debug/DebugUtils.java index 7a30ca60..070b83dc 100644 --- a/src/com/hypixel/hytale/server/core/modules/debug/DebugUtils.java +++ b/src/com/hypixel/hytale/server/core/modules/debug/DebugUtils.java @@ -16,10 +16,52 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class DebugUtils { + public static final Vector3f COLOR_BLACK = new Vector3f(0.0F, 0.0F, 0.0F); + public static final Vector3f COLOR_WHITE = new Vector3f(1.0F, 1.0F, 1.0F); + public static final Vector3f COLOR_RED = new Vector3f(1.0F, 0.0F, 0.0F); + public static final Vector3f COLOR_LIME = new Vector3f(0.0F, 1.0F, 0.0F); + public static final Vector3f COLOR_BLUE = new Vector3f(0.0F, 0.0F, 1.0F); + public static final Vector3f COLOR_YELLOW = new Vector3f(1.0F, 1.0F, 0.0F); + public static final Vector3f COLOR_CYAN = new Vector3f(0.0F, 1.0F, 1.0F); + public static final Vector3f COLOR_MAGENTA = new Vector3f(1.0F, 0.0F, 1.0F); + public static final Vector3f COLOR_SILVER = new Vector3f(0.75F, 0.75F, 0.75F); + public static final Vector3f COLOR_GRAY = new Vector3f(0.5F, 0.5F, 0.5F); + public static final Vector3f COLOR_MAROON = new Vector3f(0.5F, 0.0F, 0.0F); + public static final Vector3f COLOR_OLIVE = new Vector3f(0.5F, 0.5F, 0.0F); + public static final Vector3f COLOR_GREEN = new Vector3f(0.0F, 0.5F, 0.0F); + public static final Vector3f COLOR_PURPLE = new Vector3f(0.5F, 0.0F, 0.5F); + public static final Vector3f COLOR_TEAL = new Vector3f(0.0F, 0.5F, 0.5F); + public static final Vector3f COLOR_NAVY = new Vector3f(0.0F, 0.0F, 0.5F); + public static final Vector3f[] INDEXED_COLORS = new Vector3f[]{ + COLOR_RED, COLOR_BLUE, COLOR_LIME, COLOR_YELLOW, COLOR_CYAN, COLOR_MAGENTA, COLOR_PURPLE, COLOR_GREEN + }; + public static final String[] INDEXED_COLOR_NAMES = new String[]{"Red", "Blue", "Lime", "Yellow", "Cyan", "Magenta", "Purple", "Green"}; public static boolean DISPLAY_FORCES = false; + public static final float DEFAULT_OPACITY = 0.8F; public static void add(@Nonnull World world, @Nonnull DebugShape shape, @Nonnull Matrix4d matrix, @Nonnull Vector3f color, float time, boolean fade) { - DisplayDebug packet = new DisplayDebug(shape, matrix.asFloatData(), new com.hypixel.hytale.protocol.Vector3f(color.x, color.y, color.z), time, fade, null); + add(world, shape, matrix, color, 0.8F, time, fade, null); + } + + public static void add( + @Nonnull World world, @Nonnull DebugShape shape, @Nonnull Matrix4d matrix, @Nonnull Vector3f color, float opacity, float time, boolean fade + ) { + add(world, shape, matrix, color, opacity, time, fade, null); + } + + private static void add( + @Nonnull World world, + @Nonnull DebugShape shape, + @Nonnull Matrix4d matrix, + @Nonnull Vector3f color, + float opacity, + float time, + boolean fade, + @Nullable float[] shapeParams + ) { + DisplayDebug packet = new DisplayDebug( + shape, matrix.asFloatData(), new com.hypixel.hytale.protocol.Vector3f(color.x, color.y, color.z), time, fade, shapeParams, opacity + ); for (PlayerRef playerRef : world.getPlayerRefs()) { playerRef.getPacketHandler().write(packet); @@ -29,18 +71,7 @@ public class DebugUtils { public static void addFrustum( @Nonnull World world, @Nonnull Matrix4d matrix, @Nonnull Matrix4d frustumProjection, @Nonnull Vector3f color, float time, boolean fade ) { - DisplayDebug packet = new DisplayDebug( - DebugShape.Frustum, - matrix.asFloatData(), - new com.hypixel.hytale.protocol.Vector3f(color.x, color.y, color.z), - time, - fade, - frustumProjection.asFloatData() - ); - - for (PlayerRef playerRef : world.getPlayerRefs()) { - playerRef.getPacketHandler().write(packet); - } + add(world, DebugShape.Frustum, matrix, color, 0.8F, time, fade, frustumProjection.asFloatData()); } public static void clear(@Nonnull World world) { @@ -67,7 +98,14 @@ public class DebugUtils { } public static void addSphere(@Nonnull World world, @Nonnull Vector3d pos, @Nonnull Vector3f color, double scale, float time) { - Matrix4d matrix = makeMatrix(pos, scale); + addSphere(world, pos.x, pos.y, pos.z, color, scale, time); + } + + public static void addSphere(@Nonnull World world, double x, double y, double z, @Nonnull Vector3f color, double scale, float time) { + Matrix4d matrix = new Matrix4d(); + matrix.identity(); + matrix.translate(x, y, z); + matrix.scale(scale, scale, scale); add(world, DebugShape.Sphere, matrix, color, time, true); } @@ -77,7 +115,14 @@ public class DebugUtils { } public static void addCube(@Nonnull World world, @Nonnull Vector3d pos, @Nonnull Vector3f color, double scale, float time) { - Matrix4d matrix = makeMatrix(pos, scale); + addCube(world, pos.x, pos.y, pos.z, color, scale, time); + } + + public static void addCube(@Nonnull World world, double x, double y, double z, @Nonnull Vector3f color, double scale, float time) { + Matrix4d matrix = new Matrix4d(); + matrix.identity(); + matrix.translate(x, y, z); + matrix.scale(scale, scale, scale); add(world, DebugShape.Cube, matrix, color, time, true); } @@ -86,6 +131,180 @@ public class DebugUtils { add(world, DebugShape.Cylinder, matrix, color, time, true); } + public static void addLine( + @Nonnull World world, @Nonnull Vector3d start, @Nonnull Vector3d end, @Nonnull Vector3f color, double thickness, float time, boolean fade + ) { + addLine(world, start.x, start.y, start.z, end.x, end.y, end.z, color, thickness, time, fade); + } + + public static void addLine( + @Nonnull World world, + double startX, + double startY, + double startZ, + double endX, + double endY, + double endZ, + @Nonnull Vector3f color, + double thickness, + float time, + boolean fade + ) { + double dirX = endX - startX; + double dirY = endY - startY; + double dirZ = endZ - startZ; + double length = Math.sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); + if (!(length < 0.001)) { + Matrix4d tmp = new Matrix4d(); + Matrix4d matrix = new Matrix4d(); + matrix.identity(); + matrix.translate(startX, startY, startZ); + double angleY = Math.atan2(dirZ, dirX); + matrix.rotateAxis(angleY + (Math.PI / 2), 0.0, 1.0, 0.0, tmp); + double angleX = Math.atan2(Math.sqrt(dirX * dirX + dirZ * dirZ), dirY); + matrix.rotateAxis(angleX, 1.0, 0.0, 0.0, tmp); + matrix.translate(0.0, length / 2.0, 0.0); + matrix.scale(thickness, length, thickness); + add(world, DebugShape.Cylinder, matrix, color, time, fade); + } + } + + public static void addDisc( + @Nonnull World world, + @Nonnull Matrix4d matrix, + double outerRadius, + double innerRadius, + @Nonnull Vector3f color, + float opacity, + int segmentCount, + float time, + boolean fade + ) { + float[] shapeParams = new float[]{ + (float)outerRadius, segmentCount, (float)innerRadius, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F + }; + add(world, DebugShape.Disc, matrix, color, opacity, time, fade, shapeParams); + } + + public static void addDisc( + @Nonnull World world, @Nonnull Matrix4d matrix, double outerRadius, double innerRadius, @Nonnull Vector3f color, float opacity, float time, boolean fade + ) { + addDisc(world, matrix, outerRadius, innerRadius, color, opacity, 32, time, fade); + } + + public static void addDisc(@Nonnull World world, @Nonnull Vector3d center, double radius, @Nonnull Vector3f color, float time, boolean fade) { + addDisc(world, center.x, center.y, center.z, radius, 0.0, color, 0.8F, time, fade); + } + + public static void addDisc(@Nonnull World world, double x, double y, double z, double radius, @Nonnull Vector3f color, float time, boolean fade) { + addDisc(world, x, y, z, radius, 0.0, color, 0.8F, time, fade); + } + + public static void addDisc( + @Nonnull World world, double x, double y, double z, double radius, @Nonnull Vector3f color, float opacity, float time, boolean fade + ) { + addDisc(world, x, y, z, radius, 0.0, color, opacity, 32, time, fade); + } + + public static void addDisc( + @Nonnull World world, + double x, + double y, + double z, + double outerRadius, + double innerRadius, + @Nonnull Vector3f color, + float opacity, + float time, + boolean fade + ) { + addDisc(world, x, y, z, outerRadius, innerRadius, color, opacity, 32, time, fade); + } + + public static void addDisc( + @Nonnull World world, + double x, + double y, + double z, + double outerRadius, + double innerRadius, + @Nonnull Vector3f color, + float opacity, + int segmentCount, + float time, + boolean fade + ) { + Matrix4d matrix = new Matrix4d(); + matrix.identity(); + matrix.translate(x, y, z); + addDisc(world, matrix, outerRadius, innerRadius, color, opacity, segmentCount, time, fade); + } + + public static void addSector( + @Nonnull World world, double x, double y, double z, double heading, double radius, double angle, @Nonnull Vector3f color, float time, boolean fade + ) { + addSector(world, x, y, z, heading, radius, angle, 0.0, color, 0.8F, 16, time, fade); + } + + public static void addSector( + @Nonnull World world, + double x, + double y, + double z, + double heading, + double radius, + double angle, + @Nonnull Vector3f color, + float opacity, + float time, + boolean fade + ) { + addSector(world, x, y, z, heading, radius, angle, 0.0, color, opacity, 16, time, fade); + } + + public static void addSector( + @Nonnull World world, + double x, + double y, + double z, + double heading, + double outerRadius, + double angle, + double innerRadius, + @Nonnull Vector3f color, + float opacity, + float time, + boolean fade + ) { + addSector(world, x, y, z, heading, outerRadius, angle, innerRadius, color, opacity, 16, time, fade); + } + + public static void addSector( + @Nonnull World world, + double x, + double y, + double z, + double heading, + double outerRadius, + double angle, + double innerRadius, + @Nonnull Vector3f color, + float opacity, + int segmentCount, + float time, + boolean fade + ) { + Matrix4d tmp = new Matrix4d(); + Matrix4d matrix = new Matrix4d(); + matrix.identity(); + matrix.translate(x, y, z); + matrix.rotateAxis(heading, 0.0, 1.0, 0.0, tmp); + float[] shapeParams = new float[]{ + (float)outerRadius, (float)angle, (float)innerRadius, segmentCount, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F + }; + add(world, DebugShape.Sector, matrix, color, opacity, time, fade, shapeParams); + } + public static void addArrow(@Nonnull World world, @Nonnull Vector3d position, @Nonnull Vector3d direction, @Nonnull Vector3f color, float time, boolean fade) { Vector3d directionClone = direction.clone(); Matrix4d tmp = new Matrix4d(); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/BlockEntitySystems.java b/src/com/hypixel/hytale/server/core/modules/entity/BlockEntitySystems.java index 3412ca97..b9e3cd39 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/BlockEntitySystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/BlockEntitySystems.java @@ -16,8 +16,7 @@ import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.shape.Box; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.BlockUpdate; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.entity.entities.BlockEntity; import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox; @@ -136,15 +135,12 @@ public class BlockEntitySystems { private static void queueUpdatesFor( Ref ref, @Nonnull BlockEntity entity, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo, float entityScale ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Block; String key = entity.getBlockTypeKey(); int index = BlockType.getAssetMap().getIndex(key); if (index == Integer.MIN_VALUE) { throw new IllegalArgumentException("Unknown key! " + key); } else { - update.blockId = index; - update.entityScale = entityScale; + BlockUpdate update = new BlockUpdate(index, entityScale); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); 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..3273d7bd 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); @@ -526,7 +529,7 @@ public class EntityModule extends JavaPlugin { entityStoreRegistry.registerSystem(new ModelSystems.PlayerConnect()); entityStoreRegistry.registerSystem(new ModelSystems.ModelChange()); entityStoreRegistry.registerSystem(new ModelSystems.UpdateBoundingBox()); - entityStoreRegistry.registerSystem(new ModelSystems.UpdateCrouchingBoundingBox()); + entityStoreRegistry.registerSystem(new ModelSystems.UpdateMovementStateBoundingBox()); entityStoreRegistry.registerSystem(new ModelSystems.PlayerUpdateMovementManager()); entityStoreRegistry.registerSystem(new ModelSystems.AnimationEntityTrackerUpdate()); entityStoreRegistry.registerSystem(new EntitySystems.NewSpawnEntityTrackerUpdate()); @@ -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/component/TransformComponent.java b/src/com/hypixel/hytale/server/core/modules/entity/component/TransformComponent.java index 3d7883d2..8b881dae 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/component/TransformComponent.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/component/TransformComponent.java @@ -42,7 +42,6 @@ public class TransformComponent implements Component { @Nullable private Ref chunkRef; - @Nonnull public static ComponentType getComponentType() { return EntityModule.get().getTransformComponentType(); } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/damage/DamageModule.java b/src/com/hypixel/hytale/server/core/modules/entity/damage/DamageModule.java index 325bec08..faed3cb6 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/damage/DamageModule.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/damage/DamageModule.java @@ -97,6 +97,7 @@ public class DamageModule extends JavaPlugin { entityStoreRegistry.registerSystem(new RespawnSystems.ClearEntityEffectsRespawnSystem()); entityStoreRegistry.registerSystem(new RespawnSystems.ClearInteractionsRespawnSystem()); entityStoreRegistry.registerSystem(new RespawnSystems.CheckBrokenItemsRespawnSystem()); + entityStoreRegistry.registerSystem(new RespawnSystems.ClearRespawnUI()); entityStoreRegistry.registerSystem(new DamageCalculatorSystems.SequenceModifier()); this.getCommandRegistry().registerCommand(new DesyncDamageCommand()); } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/damage/DamageSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/damage/DamageSystems.java index 4333bc44..dc2c63bd 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/damage/DamageSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/damage/DamageSystems.java @@ -28,8 +28,6 @@ import com.hypixel.hytale.math.vector.Vector4d; import com.hypixel.hytale.protocol.AnimationSlot; import com.hypixel.hytale.protocol.BlockMaterial; import com.hypixel.hytale.protocol.CombatTextUpdate; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.InteractionType; import com.hypixel.hytale.protocol.MovementStates; import com.hypixel.hytale.protocol.SoundCategory; @@ -843,12 +841,7 @@ public class DamageSystems { private static void queueUpdateFor( @Nonnull Ref ref, float damageAmount, @Nullable Float hitAngleDeg, @Nonnull EntityTrackerSystems.EntityViewer viewer ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.CombatText; - CombatTextUpdate combatTextUpdate = new CombatTextUpdate(); - combatTextUpdate.hitAngleDeg = hitAngleDeg == null ? 0.0F : hitAngleDeg; - combatTextUpdate.text = Integer.toString((int)Math.floor(damageAmount)); - update.combatTextUpdate = combatTextUpdate; + CombatTextUpdate update = new CombatTextUpdate(hitAngleDeg == null ? 0.0F : hitAngleDeg, Integer.toString((int)Math.floor(damageAmount))); viewer.queueUpdate(ref, update); } } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/damage/DeathComponent.java b/src/com/hypixel/hytale/server/core/modules/entity/damage/DeathComponent.java index 064a1944..0312b0ca 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/damage/DeathComponent.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/damage/DeathComponent.java @@ -18,6 +18,7 @@ import com.hypixel.hytale.server.core.asset.type.gameplay.DeathConfig; import com.hypixel.hytale.server.core.asset.type.gameplay.respawn.RespawnController; import com.hypixel.hytale.server.core.entity.InteractionChain; import com.hypixel.hytale.server.core.inventory.ItemStack; +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 java.util.List; @@ -210,15 +211,17 @@ public class DeathComponent implements Component { return deathComponent.respawnFuture; } else { World world = componentAccessor.getExternalData().getWorld(); + PlayerRef playerRefComponent = componentAccessor.getComponent(ref, PlayerRef.getComponentType()); RespawnController respawnController = world.getDeathConfig().getRespawnController(); deathComponent.respawnFuture = respawnController.respawnPlayer(world, ref, componentAccessor).whenComplete((ignore, ex) -> { if (ex != null) { LOGGER.atSevere().withCause(ex).log("Failed to respawn entity"); } - Store store = world.getEntityStore().getStore(); - if (ref.isValid()) { - store.tryRemoveComponent(ref, getComponentType()); + Ref currentRef = playerRefComponent.getReference(); + if (currentRef != null && currentRef.isValid()) { + Store store = currentRef.getStore(); + store.tryRemoveComponent(currentRef, getComponentType()); } }); return deathComponent.respawnFuture; diff --git a/src/com/hypixel/hytale/server/core/modules/entity/damage/DeathSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/damage/DeathSystems.java index eb603221..be7388ac 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/damage/DeathSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/damage/DeathSystems.java @@ -260,7 +260,7 @@ public class DeathSystems { for (short i = 0; i < combinedItemContainer.getCapacity(); i++) { ItemStack itemStack = combinedItemContainer.getItemStack(i); - if (!ItemStack.isEmpty(itemStack) && !itemStack.isBroken()) { + if (!ItemStack.isEmpty(itemStack) && !itemStack.isBroken() && itemStack.getItem().getDurabilityLossOnDeath()) { double durabilityLoss = itemStack.getMaxDurability() * durabilityLossRatio; ItemStack updatedItemStack = itemStack.withIncreasedDurability(-durabilityLoss); ItemStackSlotTransaction transaction = combinedItemContainer.replaceItemStackInSlot(i, itemStack, updatedItemStack); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/damage/RespawnSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/damage/RespawnSystems.java index c4372fb8..6d0614e4 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/damage/RespawnSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/damage/RespawnSystems.java @@ -7,6 +7,7 @@ import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefChangeSystem; +import com.hypixel.hytale.protocol.packets.interface_.Page; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.entity.InteractionManager; import com.hypixel.hytale.server.core.entity.effect.EffectControllerComponent; @@ -16,6 +17,7 @@ import com.hypixel.hytale.server.core.modules.entitystats.EntityStatValue; import com.hypixel.hytale.server.core.modules.interaction.InteractionModule; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class RespawnSystems { public static class CheckBrokenItemsRespawnSystem extends RespawnSystems.OnRespawnSystem { @@ -70,6 +72,24 @@ public class RespawnSystems { } } + public static class ClearRespawnUI extends RespawnSystems.OnRespawnSystem { + public void onComponentRemoved( + @Nonnull Ref ref, @Nonnull DeathComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer + ) { + Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType()); + + assert playerComponent != null; + + playerComponent.getPageManager().setPage(ref, store, Page.None); + } + + @Nullable + @Override + public Query getQuery() { + return Player.getComponentType(); + } + } + public abstract static class OnRespawnSystem extends RefChangeSystem { @Nonnull @Override diff --git a/src/com/hypixel/hytale/server/core/modules/entity/hitboxcollision/HitboxCollisionConfigPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/entity/hitboxcollision/HitboxCollisionConfigPacketGenerator.java index 69867a00..016f76e5 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/hitboxcollision/HitboxCollisionConfigPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/hitboxcollision/HitboxCollisionConfigPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.modules.entity.hitboxcollision; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateHitboxCollisionConfig; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -16,7 +16,7 @@ import javax.annotation.Nonnull; public class HitboxCollisionConfigPacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket( + public ToClientPacket generateInitPacket( @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets ) { Int2ObjectMap hitboxCollisionConfigs = new Int2ObjectOpenHashMap<>(); @@ -29,7 +29,7 @@ public class HitboxCollisionConfigPacketGenerator } @Nonnull - public Packet generateUpdatePacket( + public ToClientPacket generateUpdatePacket( @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query @@ -44,7 +44,7 @@ public class HitboxCollisionConfigPacketGenerator } @Nonnull - public Packet generateRemovePacket( + public ToClientPacket generateRemovePacket( @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query ) { Int2ObjectMap hitboxCollisionConfigs = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/hitboxcollision/HitboxCollisionSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/hitboxcollision/HitboxCollisionSystems.java index 9280a52f..0b0ad7c1 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/hitboxcollision/HitboxCollisionSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/hitboxcollision/HitboxCollisionSystems.java @@ -13,8 +13,8 @@ import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.HitboxCollisionUpdate; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; import com.hypixel.hytale.server.core.universe.world.World; @@ -130,9 +130,7 @@ public class HitboxCollisionSystems { private static void queueUpdatesFor( Ref ref, @Nonnull HitboxCollision hitboxCollision, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.HitboxCollision; - update.hitboxCollisionConfigIndex = hitboxCollision.getHitboxCollisionConfigIndex(); + HitboxCollisionUpdate update = new HitboxCollisionUpdate(hitboxCollision.getHitboxCollisionConfigIndex()); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/item/ItemComponent.java b/src/com/hypixel/hytale/server/core/modules/entity/item/ItemComponent.java index 59734b8c..6c7e9b71 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/item/ItemComponent.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/item/ItemComponent.java @@ -25,7 +25,6 @@ import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction import com.hypixel.hytale.server.core.modules.entity.BlockMigrationExtraInfo; import com.hypixel.hytale.server.core.modules.entity.DespawnComponent; import com.hypixel.hytale.server.core.modules.entity.EntityModule; -import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; import com.hypixel.hytale.server.core.modules.entity.component.Intangible; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId; @@ -249,35 +248,40 @@ public class ItemComponent implements Component { } } - @Nonnull + @Nullable public static Holder generatePickedUpItem( @Nonnull Ref ref, @Nonnull ComponentAccessor componentAccessor, @Nonnull Ref targetRef, @Nonnull Vector3d targetPosition ) { - Holder holder = EntityStore.REGISTRY.newHolder(); - TransformComponent itemTransformComponent = componentAccessor.getComponent(ref, TransformComponent.getComponentType()); - - assert itemTransformComponent != null; - - ItemComponent itemItemComponent = componentAccessor.getComponent(ref, getComponentType()); - - assert itemItemComponent != null; - - HeadRotation itemHeadRotationComponent = componentAccessor.getComponent(ref, HeadRotation.getComponentType()); - - assert itemHeadRotationComponent != null; - - PickupItemComponent pickupItemComponent = new PickupItemComponent(targetRef, targetPosition.clone()); - holder.addComponent(PickupItemComponent.getComponentType(), pickupItemComponent); - holder.addComponent(getComponentType(), itemItemComponent.clone()); - holder.addComponent(TransformComponent.getComponentType(), itemTransformComponent.clone()); - holder.ensureComponent(PreventItemMerging.getComponentType()); - holder.ensureComponent(Intangible.getComponentType()); - holder.addComponent(NetworkId.getComponentType(), new NetworkId(ref.getStore().getExternalData().takeNextNetworkId())); - holder.ensureComponent(EntityStore.REGISTRY.getNonSerializedComponentType()); - return holder; + if (!ref.isValid()) { + LOGGER.at(Level.WARNING).log("Attempted to generate picked up item from invalid entity reference %s", Integer.valueOf(ref.getIndex())); + return null; + } else { + TransformComponent itemTransformComponent = componentAccessor.getComponent(ref, TransformComponent.getComponentType()); + if (itemTransformComponent == null) { + LOGGER.at(Level.WARNING).log("Attempted to generate picked up item from entity %s without a TransformComponent", Integer.valueOf(ref.getIndex())); + return null; + } else { + ItemComponent itemItemComponent = componentAccessor.getComponent(ref, getComponentType()); + if (itemItemComponent == null) { + LOGGER.at(Level.WARNING).log("Attempted to generate picked up item from entity %s without an ItemComponent", Integer.valueOf(ref.getIndex())); + return null; + } else { + Holder holder = EntityStore.REGISTRY.newHolder(); + PickupItemComponent pickupItemComponent = new PickupItemComponent(targetRef, targetPosition.clone()); + holder.addComponent(PickupItemComponent.getComponentType(), pickupItemComponent); + holder.addComponent(getComponentType(), itemItemComponent.clone()); + holder.addComponent(TransformComponent.getComponentType(), itemTransformComponent.clone()); + holder.ensureComponent(PreventItemMerging.getComponentType()); + holder.ensureComponent(Intangible.getComponentType()); + holder.addComponent(NetworkId.getComponentType(), new NetworkId(ref.getStore().getExternalData().takeNextNetworkId())); + holder.ensureComponent(EntityStore.REGISTRY.getNonSerializedComponentType()); + return holder; + } + } + } } @Nonnull diff --git a/src/com/hypixel/hytale/server/core/modules/entity/item/ItemSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/item/ItemSystems.java index 96d48e26..c8083ba5 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/item/ItemSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/item/ItemSystems.java @@ -14,8 +14,7 @@ import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.math.shape.Box; import com.hypixel.hytale.protocol.ColorLight; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.ItemUpdate; import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox; import com.hypixel.hytale.server.core.modules.entity.component.DynamicLight; @@ -123,11 +122,8 @@ public class ItemSystems { float entityScale, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Item; ItemStack itemStack = item.getItemStack(); - update.item = itemStack != null ? itemStack.toPacket() : null; - update.entityScale = entityScale; + ItemUpdate update = new ItemUpdate(itemStack != null ? itemStack.toPacket() : null, entityScale); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/player/ChunkTracker.java b/src/com/hypixel/hytale/server/core/modules/entity/player/ChunkTracker.java index dca842a0..34275dd3 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/player/ChunkTracker.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/player/ChunkTracker.java @@ -15,7 +15,8 @@ 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.metrics.MetricsRegistry; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.NetworkChannel; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.world.UnloadChunk; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.entity.entities.Player; @@ -141,7 +142,7 @@ public class ChunkTracker implements Component { float dt, @Nonnull CommandBuffer commandBuffer ) { - if (this.readyForChunks) { + if (this.readyForChunks && playerRefComponent.getPacketHandler().getChannel(NetworkChannel.Chunks).isWritable()) { this.transformComponent = transformComponent; int chunkViewRadius = this.chunkViewRadius = playerComponent.getViewRadius(); Vector3d position = transformComponent.getPosition(); @@ -526,7 +527,7 @@ public class ChunkTracker implements Component { Ref chunkRef = chunkComponentStore.getChunkReference(chunkIndex); if (chunkRef != null) { Store chunkStore = chunkComponentStore.getStore(); - ObjectArrayList packets = new ObjectArrayList<>(); + ObjectArrayList packets = new ObjectArrayList<>(); chunkStore.fetch(Collections.singletonList(chunkRef), ChunkStore.UNLOAD_PACKETS_DATA_QUERY_SYSTEM_TYPE, playerRef, packets); for (int i = 0; i < packets.size(); i++) { @@ -617,14 +618,14 @@ public class ChunkTracker implements Component { private CompletableFuture _loadChunkAsync( long chunkIndex, @Nonnull PlayerRef playerRefComponent, @Nonnull Ref chunkRef, @Nonnull ChunkStore chunkComponentStore ) { - List packets = new ObjectArrayList<>(); + List packets = new ObjectArrayList<>(); chunkComponentStore.getStore().fetch(Collections.singletonList(chunkRef), ChunkStore.LOAD_PACKETS_DATA_QUERY_SYSTEM_TYPE, playerRefComponent, packets); - ObjectArrayList> futurePackets = new ObjectArrayList<>(); + ObjectArrayList> futurePackets = new ObjectArrayList<>(); chunkComponentStore.getStore() .fetch(Collections.singletonList(chunkRef), ChunkStore.LOAD_FUTURE_PACKETS_DATA_QUERY_SYSTEM_TYPE, playerRefComponent, futurePackets); return CompletableFuture.allOf(futurePackets.toArray(CompletableFuture[]::new)).thenAcceptAsync(o -> { - for (CompletableFuture futurePacket : futurePackets) { - Packet packet = futurePacket.join(); + for (CompletableFuture futurePacket : futurePackets) { + ToClientPacket packet = futurePacket.join(); if (packet != null) { packets.add(packet); } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/player/PlayerItemEntityPickupSystem.java b/src/com/hypixel/hytale/server/core/modules/entity/player/PlayerItemEntityPickupSystem.java index b7b99a35..8bcda79c 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/player/PlayerItemEntityPickupSystem.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/player/PlayerItemEntityPickupSystem.java @@ -25,7 +25,6 @@ import com.hypixel.hytale.server.core.entity.InteractionContext; import com.hypixel.hytale.server.core.entity.InteractionManager; 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 com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction; import com.hypixel.hytale.server.core.modules.entity.DespawnComponent; import com.hypixel.hytale.server.core.modules.entity.component.Interactable; @@ -162,20 +161,16 @@ public class PlayerItemEntityPickupSystem extends EntityTickingSystem pickupItemHolder = ItemComponent.generatePickedUpItem(itemRef, commandBuffer, targetPlayerRef, itemEntityPosition); - commandBuffer.addEntity(pickupItemHolder, AddReason.SPAWN); + if (pickupItemHolder != null) { + commandBuffer.addEntity(pickupItemHolder, AddReason.SPAWN); + } break; } @@ -186,7 +181,10 @@ public class PlayerItemEntityPickupSystem extends EntityTickingSystem pickupItemHolder = ItemComponent.generatePickedUpItem(itemRef, commandBuffer, targetPlayerRef, itemEntityPosition); - commandBuffer.addEntity(pickupItemHolder, AddReason.SPAWN); + if (pickupItemHolder != null) { + commandBuffer.addEntity(pickupItemHolder, AddReason.SPAWN); + } + if (quantity > 0) { playerComponent.notifyPickupItem(targetPlayerRef, remainder.withQuantity(quantity), itemEntityPosition, commandBuffer); } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/player/PlayerSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/player/PlayerSystems.java index 655d65fa..90cc7cc4 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/player/PlayerSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/player/PlayerSystems.java @@ -26,11 +26,21 @@ 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.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.EntityEffectsUpdate; +import com.hypixel.hytale.protocol.EntityStatsUpdate; import com.hypixel.hytale.protocol.EntityUpdate; -import com.hypixel.hytale.protocol.Equipment; +import com.hypixel.hytale.protocol.EquipmentUpdate; +import com.hypixel.hytale.protocol.IntangibleUpdate; +import com.hypixel.hytale.protocol.InteractableUpdate; +import com.hypixel.hytale.protocol.InvulnerableUpdate; import com.hypixel.hytale.protocol.ItemArmorSlot; import com.hypixel.hytale.protocol.ModelTransform; +import com.hypixel.hytale.protocol.ModelUpdate; +import com.hypixel.hytale.protocol.NameplateUpdate; +import com.hypixel.hytale.protocol.PlayerSkinUpdate; +import com.hypixel.hytale.protocol.PredictionUpdate; +import com.hypixel.hytale.protocol.RespondToHitUpdate; +import com.hypixel.hytale.protocol.TransformUpdate; import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolsSetSoundSet; import com.hypixel.hytale.protocol.packets.entities.EntityUpdates; import com.hypixel.hytale.protocol.packets.inventory.SetActiveSlot; @@ -574,49 +584,33 @@ public class PlayerSystems { ObjectArrayList list = new ObjectArrayList<>(); Archetype viewerArchetype = store.getArchetype(viewerRef); if (viewerArchetype.contains(Interactable.getComponentType())) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Interactable; - list.add(update); + list.add(new InteractableUpdate()); } if (viewerArchetype.contains(Intangible.getComponentType())) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Intangible; - list.add(update); + list.add(new IntangibleUpdate()); } if (viewerArchetype.contains(Invulnerable.getComponentType())) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Invulnerable; - list.add(update); + list.add(new InvulnerableUpdate()); } if (viewerArchetype.contains(RespondToHit.getComponentType())) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.RespondToHit; - list.add(update); + list.add(new RespondToHitUpdate()); } Nameplate nameplateComponent = store.getComponent(viewerRef, Nameplate.getComponentType()); if (nameplateComponent != null) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Nameplate; - update.nameplate = new com.hypixel.hytale.protocol.Nameplate(); - update.nameplate.text = nameplateComponent.getText(); - list.add(update); + list.add(new NameplateUpdate(nameplateComponent.getText())); } PredictedProjectile predictionComponent = store.getComponent(viewerRef, PredictedProjectile.getComponentType()); if (predictionComponent != null) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Prediction; - update.predictionId = predictionComponent.getUuid(); - list.add(update); + list.add(new PredictionUpdate(predictionComponent.getUuid())); } ModelComponent modelComponent = store.getComponent(viewerRef, ModelComponent.getComponentType()); - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Model; + ModelUpdate update = new ModelUpdate(); update.model = modelComponent != null ? modelComponent.getModel().toPacket() : null; EntityScaleComponent entityScaleComponent = store.getComponent(viewerRef, EntityScaleComponent.getComponentType()); if (entityScaleComponent != null) { @@ -624,19 +618,14 @@ public class PlayerSystems { } list.add(update); - update = new ComponentUpdate(); - update.type = ComponentUpdateType.PlayerSkin; PlayerSkinComponent playerSkinComponent = store.getComponent(viewerRef, PlayerSkinComponent.getComponentType()); - update.skin = playerSkinComponent != null ? playerSkinComponent.getPlayerSkin() : null; - list.add(update); + list.add(new PlayerSkinUpdate(playerSkinComponent != null ? playerSkinComponent.getPlayerSkin() : null)); Inventory inventory = playerComponent.getInventory(); - ComponentUpdate updatex = new ComponentUpdate(); - updatex.type = ComponentUpdateType.Equipment; - updatex.equipment = new Equipment(); + EquipmentUpdate updatex = new EquipmentUpdate(); ItemContainer armor = inventory.getArmor(); - updatex.equipment.armorIds = new String[armor.getCapacity()]; - Arrays.fill(updatex.equipment.armorIds, ""); - armor.forEachWithMeta((slot, itemStack, armorIds) -> armorIds[slot] = itemStack.getItemId(), updatex.equipment.armorIds); + updatex.armorIds = new String[armor.getCapacity()]; + Arrays.fill(updatex.armorIds, ""); + armor.forEachWithMeta((slot, itemStack, armorIds) -> armorIds[slot] = itemStack.getItemId(), updatex.armorIds); PlayerSettings playerSettingsComponent = store.getComponent(viewerRef, PlayerSettings.getComponentType()); if (playerSettingsComponent != null) { PlayerConfig.ArmorVisibilityOption armorVisibilityOption = store.getExternalData() @@ -645,32 +634,31 @@ public class PlayerSystems { .getPlayerConfig() .getArmorVisibilityOption(); if (armorVisibilityOption.canHideHelmet() && playerSettingsComponent.hideHelmet()) { - updatex.equipment.armorIds[ItemArmorSlot.Head.ordinal()] = ""; + updatex.armorIds[ItemArmorSlot.Head.ordinal()] = ""; } if (armorVisibilityOption.canHideCuirass() && playerSettingsComponent.hideCuirass()) { - updatex.equipment.armorIds[ItemArmorSlot.Chest.ordinal()] = ""; + updatex.armorIds[ItemArmorSlot.Chest.ordinal()] = ""; } if (armorVisibilityOption.canHideGauntlets() && playerSettingsComponent.hideGauntlets()) { - updatex.equipment.armorIds[ItemArmorSlot.Hands.ordinal()] = ""; + updatex.armorIds[ItemArmorSlot.Hands.ordinal()] = ""; } if (armorVisibilityOption.canHidePants() && playerSettingsComponent.hidePants()) { - updatex.equipment.armorIds[ItemArmorSlot.Legs.ordinal()] = ""; + updatex.armorIds[ItemArmorSlot.Legs.ordinal()] = ""; } } ItemStack itemInHand = inventory.getItemInHand(); - updatex.equipment.rightHandItemId = itemInHand != null ? itemInHand.getItemId() : "Empty"; + updatex.rightHandItemId = itemInHand != null ? itemInHand.getItemId() : "Empty"; ItemStack utilityItem = inventory.getUtilityItem(); - updatex.equipment.leftHandItemId = utilityItem != null ? utilityItem.getItemId() : "Empty"; + updatex.leftHandItemId = utilityItem != null ? utilityItem.getItemId() : "Empty"; list.add(updatex); TransformComponent transformComponent = store.getComponent(viewerRef, TransformComponent.getComponentType()); HeadRotation headRotationComponent = store.getComponent(viewerRef, HeadRotation.getComponentType()); if (transformComponent != null && headRotationComponent != null) { - ComponentUpdate updatexx = new ComponentUpdate(); - updatexx.type = ComponentUpdateType.Transform; + TransformUpdate updatexx = new TransformUpdate(); updatexx.transform = new ModelTransform(); updatexx.transform.position = PositionUtil.toPositionPacket(transformComponent.getPosition()); updatexx.transform.bodyOrientation = PositionUtil.toDirectionPacket(transformComponent.getRotation()); @@ -680,18 +668,12 @@ public class PlayerSystems { EffectControllerComponent effectControllerComponent = store.getComponent(viewerRef, EffectControllerComponent.getComponentType()); if (effectControllerComponent != null) { - ComponentUpdate updatexx = new ComponentUpdate(); - updatexx.type = ComponentUpdateType.EntityEffects; - updatexx.entityEffectUpdates = effectControllerComponent.createInitUpdates(); - list.add(updatexx); + list.add(new EntityEffectsUpdate(effectControllerComponent.createInitUpdates())); } EntityStatMap statMapComponent = store.getComponent(viewerRef, EntityStatMap.getComponentType()); if (statMapComponent != null) { - ComponentUpdate updatexx = new ComponentUpdate(); - updatexx.type = ComponentUpdateType.EntityStats; - updatexx.entityStatUpdates = statMapComponent.createInitUpdate(true); - list.add(updatexx); + list.add(new EntityStatsUpdate(statMapComponent.createInitUpdate(true))); } entityUpdate.updates = list.toArray(ComponentUpdate[]::new); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/repulsion/RepulsionConfigPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/entity/repulsion/RepulsionConfigPacketGenerator.java index 564304ae..6791917c 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/repulsion/RepulsionConfigPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/repulsion/RepulsionConfigPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.modules.entity.repulsion; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateRepulsionConfig; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; public class RepulsionConfigPacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { Int2ObjectMap repulsionConfigs = new Int2ObjectOpenHashMap<>(); for (Entry entry : assets.entrySet()) { @@ -26,7 +26,7 @@ public class RepulsionConfigPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query @@ -41,7 +41,7 @@ public class RepulsionConfigPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query ) { Int2ObjectMap repulsionConfigs = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/repulsion/RepulsionSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/repulsion/RepulsionSystems.java index e5f7359d..29c33ac1 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/repulsion/RepulsionSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/repulsion/RepulsionSystems.java @@ -22,8 +22,8 @@ import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.math.vector.Vector2d; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.protocol.ChangeVelocityType; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.RepulsionUpdate; 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.modules.entity.system.PlayerSpatialSystem; @@ -140,9 +140,7 @@ public class RepulsionSystems { private static void queueUpdatesFor( Ref ref, @Nonnull Repulsion repulsion, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Repulsion; - update.repulsionConfigIndex = repulsion.getRepulsionConfigIndex(); + RepulsionUpdate update = new RepulsionUpdate(repulsion.getRepulsionConfigIndex()); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/system/AudioSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/system/AudioSystems.java index f07c17ec..095c5fd1 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/system/AudioSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/system/AudioSystems.java @@ -11,9 +11,8 @@ import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.math.random.RandomExtra; import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.protocol.AudioUpdate; import com.hypixel.hytale.protocol.BlockSoundEvent; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.SoundCategory; import com.hypixel.hytale.server.core.asset.type.blocksound.config.BlockSoundSet; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; @@ -80,9 +79,7 @@ public class AudioSystems { private static void queueUpdatesFor( @Nonnull Ref ref, @Nonnull AudioComponent audioComponent, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Audio; - update.soundEventIds = audioComponent.getSoundEventIds(); + AudioUpdate update = new AudioUpdate(audioComponent.getSoundEventIds()); for (Entry, EntityTrackerSystems.EntityViewer> entry : visibleTo.entrySet()) { entry.getValue().queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/system/EntityInteractableSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/system/EntityInteractableSystems.java index 6ecc671c..9bcdafd9 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/system/EntityInteractableSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/system/EntityInteractableSystems.java @@ -11,8 +11,8 @@ import com.hypixel.hytale.component.SystemGroup; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.InteractableUpdate; import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.Interactable; import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; @@ -122,8 +122,7 @@ public class EntityInteractableSystems { } private static void queueUpdatesFor(Ref ref, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Interactable; + InteractableUpdate update = new InteractableUpdate(); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/system/EntitySystems.java b/src/com/hypixel/hytale/server/core/modules/entity/system/EntitySystems.java index f58da529..bba831ed 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/system/EntitySystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/system/EntitySystems.java @@ -19,8 +19,9 @@ import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.RefSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.protocol.ColorLight; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.DynamicLightUpdate; +import com.hypixel.hytale.protocol.NewSpawnUpdate; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.DynamicLight; @@ -150,9 +151,7 @@ public class EntitySystems { private static void queueUpdatesFor( @Nonnull Ref ref, @Nonnull ColorLight dynamicLight, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.DynamicLight; - update.dynamicLight = dynamicLight; + DynamicLightUpdate update = new DynamicLightUpdate(dynamicLight); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); @@ -209,8 +208,7 @@ public class EntitySystems { Ref ref = archetypeChunk.getReferenceTo(index); if (!visibleComponent.newlyVisibleTo.isEmpty()) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.NewSpawn; + NewSpawnUpdate update = new NewSpawnUpdate(); for (Entry, EntityTrackerSystems.EntityViewer> entry : visibleComponent.newlyVisibleTo.entrySet()) { entry.getValue().queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/system/IntangibleSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/system/IntangibleSystems.java index ca4b739a..e105c799 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/system/IntangibleSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/system/IntangibleSystems.java @@ -11,8 +11,8 @@ import com.hypixel.hytale.component.SystemGroup; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.IntangibleUpdate; import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.Intangible; import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; @@ -122,8 +122,7 @@ public class IntangibleSystems { } private static void queueUpdatesFor(Ref ref, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Intangible; + IntangibleUpdate update = new IntangibleUpdate(); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/system/InvulnerableSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/system/InvulnerableSystems.java index 3222484c..05fad920 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/system/InvulnerableSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/system/InvulnerableSystems.java @@ -11,8 +11,8 @@ import com.hypixel.hytale.component.SystemGroup; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.InvulnerableUpdate; import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.Invulnerable; import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; @@ -122,8 +122,7 @@ public class InvulnerableSystems { } private static void queueUpdatesFor(Ref ref, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Invulnerable; + InvulnerableUpdate update = new InvulnerableUpdate(); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/system/ModelSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/system/ModelSystems.java index cb4cf944..8644615b 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/system/ModelSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/system/ModelSystems.java @@ -19,9 +19,9 @@ import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; +import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.shape.Box; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.ActiveAnimationsUpdate; import com.hypixel.hytale.protocol.MovementStates; import com.hypixel.hytale.protocol.PlayerSkin; import com.hypixel.hytale.server.core.asset.type.model.config.Model; @@ -50,9 +50,15 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ModelSystems { + @Nonnull + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + public static class AnimationEntityTrackerUpdate extends EntityTickingSystem { + @Nonnull private final ComponentType visibleComponentType = EntityTrackerSystems.Visible.getComponentType(); + @Nonnull private final ComponentType activeAnimationComponentType = ActiveAnimationComponent.getComponentType(); + @Nonnull private final Query query = Query.and(this.visibleComponentType, this.activeAnimationComponentType); @Nullable @@ -101,9 +107,7 @@ public class ModelSystems { @Nonnull ActiveAnimationComponent animationComponent, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.ActiveAnimations; - update.activeAnimations = animationComponent.getActiveAnimations(); + ActiveAnimationsUpdate update = new ActiveAnimationsUpdate(animationComponent.getActiveAnimations()); for (Entry, EntityTrackerSystems.EntityViewer> entry : visibleTo.entrySet()) { entry.getValue().queueUpdate(ref, update); @@ -112,8 +116,11 @@ public class ModelSystems { } public static class ApplyRandomSkin extends HolderSystem { + @Nonnull private final ComponentType modelComponentType = ModelComponent.getComponentType(); + @Nonnull private final ComponentType randomSkinComponent = ApplyRandomSkinPersistedComponent.getComponentType(); + @Nonnull private final Query query = Query.and(this.randomSkinComponent, this.modelComponentType); @Override @@ -134,8 +141,11 @@ public class ModelSystems { } public static class AssignNetworkIdToProps extends HolderSystem { + @Nonnull private final ComponentType propComponentType = PropComponent.getComponentType(); + @Nonnull private final ComponentType networkIdComponentType = NetworkId.getComponentType(); + @Nonnull private final Query query = Query.and(this.propComponentType, Query.not(this.networkIdComponentType)); @Override @@ -155,6 +165,7 @@ public class ModelSystems { } public static class EnsurePropsPrefabCopyable extends HolderSystem { + @Nonnull private final ComponentType propComponentType = PropComponent.getComponentType(); @Override @@ -174,7 +185,9 @@ public class ModelSystems { } public static class ModelChange extends RefChangeSystem { + @Nonnull private final ComponentType modelComponentType = ModelComponent.getComponentType(); + @Nonnull private final ComponentType persistentModelComponentType = PersistentModel.getComponentType(); @Override @@ -200,8 +213,11 @@ public class ModelSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - PersistentModel persistentModel = store.getComponent(ref, this.persistentModelComponentType); - persistentModel.setModelReference(newComponent.getModel().toReference()); + PersistentModel persistentModelComponent = store.getComponent(ref, this.persistentModelComponentType); + + assert persistentModelComponent != null; + + persistentModelComponent.setModelReference(newComponent.getModel().toReference()); } public void onComponentRemoved( @@ -212,23 +228,36 @@ public class ModelSystems { } public static class ModelSpawned extends HolderSystem { + @Nonnull private final ComponentType modelComponentType = ModelComponent.getComponentType(); + @Nonnull private final ComponentType boundingBoxComponentType = BoundingBox.getComponentType(); + @Nonnull private final Set> dependencies = Set.of(new SystemDependency<>(Order.AFTER, ModelSystems.SetRenderedModel.class)); @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - Model model = holder.getComponent(this.modelComponentType).getModel(); - Box modelBoundingBox = model.getBoundingBox(); - if (modelBoundingBox != null) { - BoundingBox boundingBox = holder.getComponent(this.boundingBoxComponentType); - if (boundingBox == null) { - boundingBox = new BoundingBox(); - holder.addComponent(this.boundingBoxComponentType, boundingBox); - } + ModelComponent modelComponent = holder.getComponent(this.modelComponentType); - boundingBox.setBoundingBox(modelBoundingBox); - boundingBox.setDetailBoxes(model.getDetailBoxes()); + assert modelComponent != null; + + Model model = modelComponent.getModel(); + if (model == null) { + ModelSystems.LOGGER.atWarning().log("Failed to set bounding box for entity as model is null"); + } else { + Box modelBoundingBox = model.getBoundingBox(); + if (modelBoundingBox == null) { + ModelSystems.LOGGER.atWarning().log("Failed to set bounding box for entity as model bounding box is null: %s", model.getModel()); + } else { + BoundingBox boundingBox = holder.getComponent(this.boundingBoxComponentType); + if (boundingBox == null) { + boundingBox = new BoundingBox(); + holder.addComponent(this.boundingBoxComponentType, boundingBox); + } + + boundingBox.setBoundingBox(modelBoundingBox); + boundingBox.setDetailBoxes(model.getDetailBoxes()); + } } } @@ -249,16 +278,23 @@ public class ModelSystems { } public static class PlayerConnect extends HolderSystem { + @Nonnull private final ComponentType playerComponentType = Player.getComponentType(); + @Nonnull private final ComponentType modelComponentType = ModelComponent.getComponentType(); + @Nonnull private final Query query = Query.and(this.playerComponentType, Query.not(this.modelComponentType)); + @Nonnull private final Set> dependencies = Set.of(new SystemDependency<>(Order.BEFORE, ModelSystems.ModelSpawned.class)); @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - Player player = holder.getComponent(this.playerComponentType); + Player playerComponent = holder.getComponent(this.playerComponentType); + + assert playerComponent != null; + DefaultAssetMap assetMap = ModelAsset.getAssetMap(); - String preset = player.getPlayerConfigData().getPreset(); + String preset = playerComponent.getPlayerConfigData().getPreset(); ModelAsset modelAsset = preset != null ? assetMap.getAsset(preset) : null; if (modelAsset != null) { Model model = Model.createUnitScaleModel(modelAsset); @@ -290,9 +326,13 @@ public class ModelSystems { } public static class PlayerUpdateMovementManager extends RefChangeSystem { + @Nonnull private final ComponentType modelComponentType = ModelComponent.getComponentType(); + @Nonnull private final ComponentType playerComponentType = Player.getComponentType(); + @Nonnull private final Query query = Query.and(this.playerComponentType, MovementManager.getComponentType()); + @Nonnull private final Set> dependencies = Set.of(new SystemDependency<>(Order.AFTER, ModelSystems.UpdateBoundingBox.class)); @Nonnull @@ -316,7 +356,7 @@ public class ModelSystems { public void onComponentAdded( @Nonnull Ref ref, @Nonnull ModelComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - this.updateMovementController(ref, commandBuffer); + updateMovementController(ref, commandBuffer); } public void onComponentSet( @@ -326,16 +366,16 @@ public class ModelSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - this.updateMovementController(ref, commandBuffer); + updateMovementController(ref, commandBuffer); } public void onComponentRemoved( @Nonnull Ref ref, @Nonnull ModelComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - this.updateMovementController(ref, commandBuffer); + updateMovementController(ref, commandBuffer); } - private void updateMovementController(@Nonnull Ref ref, @Nonnull ComponentAccessor componentAccessor) { + private static void updateMovementController(@Nonnull Ref ref, @Nonnull ComponentAccessor componentAccessor) { MovementManager movementManagerComponent = componentAccessor.getComponent(ref, MovementManager.getComponentType()); assert movementManagerComponent != null; @@ -345,14 +385,26 @@ public class ModelSystems { } public static class SetRenderedModel extends HolderSystem { + @Nonnull private final ComponentType modelComponentType = ModelComponent.getComponentType(); + @Nonnull private final ComponentType persistentModelComponentType = PersistentModel.getComponentType(); + @Nonnull private final Query query = Query.and(this.persistentModelComponentType, Query.not(this.modelComponentType)); @Override public void onEntityAdd(@Nonnull Holder holder, @Nonnull AddReason reason, @Nonnull Store store) { - PersistentModel persistentModel = holder.getComponent(this.persistentModelComponentType); - holder.putComponent(this.modelComponentType, new ModelComponent(persistentModel.getModelReference().toModel())); + PersistentModel persistentModelComponent = holder.getComponent(this.persistentModelComponentType); + + assert persistentModelComponent != null; + + Model model = persistentModelComponent.getModelReference().toModel(); + if (model != null) { + ModelComponent modelComponent = new ModelComponent(model); + holder.putComponent(this.modelComponentType, modelComponent); + } else { + ModelSystems.LOGGER.atWarning().log("Failed to load model for entity with PersistentModel: {}", persistentModelComponent.getModelReference()); + } } @Override @@ -367,8 +419,11 @@ public class ModelSystems { } public static class UpdateBoundingBox extends RefChangeSystem { + @Nonnull private final ComponentType modelComponentType = ModelComponent.getComponentType(); + @Nonnull private final ComponentType boundingBoxComponentType = BoundingBox.getComponentType(); + @Nonnull private final ComponentType movementStatesComponentType = MovementStatesComponent.getComponentType(); @Override @@ -385,9 +440,15 @@ public class ModelSystems { public void onComponentAdded( @Nonnull Ref ref, @Nonnull ModelComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - BoundingBox boundingBox = commandBuffer.getComponent(ref, this.boundingBoxComponentType); - MovementStatesComponent movementStates = commandBuffer.getComponent(ref, this.movementStatesComponentType); - updateBoundingBox(component.getModel(), boundingBox, movementStates); + BoundingBox boundingBoxComponent = commandBuffer.getComponent(ref, this.boundingBoxComponentType); + + assert boundingBoxComponent != null; + + MovementStatesComponent movementStatesComponent = commandBuffer.getComponent(ref, this.movementStatesComponentType); + + assert movementStatesComponent != null; + + updateBoundingBox(component.getModel(), boundingBoxComponent, movementStatesComponent); } public void onComponentSet( @@ -397,15 +458,25 @@ public class ModelSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - BoundingBox boundingBox = commandBuffer.getComponent(ref, this.boundingBoxComponentType); - MovementStatesComponent movementStates = commandBuffer.getComponent(ref, this.movementStatesComponentType); - updateBoundingBox(newComponent.getModel(), boundingBox, movementStates); + BoundingBox boundingBoxComponent = commandBuffer.getComponent(ref, this.boundingBoxComponentType); + + assert boundingBoxComponent != null; + + MovementStatesComponent movementStatesComponent = commandBuffer.getComponent(ref, this.movementStatesComponentType); + + assert movementStatesComponent != null; + + updateBoundingBox(newComponent.getModel(), boundingBoxComponent, movementStatesComponent); } public void onComponentRemoved( @Nonnull Ref ref, @Nonnull ModelComponent component, @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - commandBuffer.getComponent(ref, this.boundingBoxComponentType).setBoundingBox(new Box()); + BoundingBox boundingBoxComponent = commandBuffer.getComponent(ref, this.boundingBoxComponentType); + + assert boundingBoxComponent != null; + + boundingBoxComponent.setBoundingBox(new Box()); } protected static void updateBoundingBox(@Nonnull Model model, @Nonnull BoundingBox boundingBox, @Nullable MovementStatesComponent movementStatesComponent) { @@ -422,13 +493,18 @@ public class ModelSystems { } } - public static class UpdateCrouchingBoundingBox extends EntityTickingSystem { + public static class UpdateMovementStateBoundingBox extends EntityTickingSystem { + @Nonnull public static final Set> DEPENDENCIES = Collections.singleton( new SystemDependency<>(Order.BEFORE, MovementStatesSystems.TickingSystem.class) ); + @Nonnull private final ComponentType movementStatesComponentType = MovementStatesComponent.getComponentType(); + @Nonnull private final ComponentType boundingBoxComponentType = BoundingBox.getComponentType(); + @Nonnull private final ComponentType modelComponentType = ModelComponent.getComponentType(); + @Nonnull private final Query query = Query.and(this.movementStatesComponentType, this.boundingBoxComponentType, this.modelComponentType); @Override @@ -456,13 +532,28 @@ public class ModelSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - MovementStatesComponent movementStates = archetypeChunk.getComponent(index, this.movementStatesComponentType); - MovementStates newMovementStates = movementStates.getMovementStates(); - MovementStates sentMovementStates = movementStates.getSentMovementStates(); - if (newMovementStates.crouching != sentMovementStates.crouching || newMovementStates.forcedCrouching != sentMovementStates.forcedCrouching) { - Model model = archetypeChunk.getComponent(index, this.modelComponentType).getModel(); - BoundingBox boundingBox = archetypeChunk.getComponent(index, this.boundingBoxComponentType); - ModelSystems.UpdateBoundingBox.updateBoundingBox(model, boundingBox, newMovementStates); + MovementStatesComponent movementStatesComponent = archetypeChunk.getComponent(index, this.movementStatesComponentType); + + assert movementStatesComponent != null; + + MovementStates newMovementStates = movementStatesComponent.getMovementStates(); + MovementStates sentMovementStates = movementStatesComponent.getSentMovementStates(); + boolean crouchingChanged = newMovementStates.crouching != sentMovementStates.crouching + || newMovementStates.forcedCrouching != sentMovementStates.forcedCrouching; + boolean slidingChanged = newMovementStates.sliding != sentMovementStates.sliding; + boolean sittingChanged = newMovementStates.sitting != sentMovementStates.sitting; + boolean sleepingChanged = newMovementStates.sleeping != sentMovementStates.sleeping; + if (crouchingChanged || slidingChanged || sittingChanged || sleepingChanged) { + ModelComponent modelComponent = archetypeChunk.getComponent(index, this.modelComponentType); + + assert modelComponent != null; + + Model model = modelComponent.getModel(); + BoundingBox boundingBoxComponent = archetypeChunk.getComponent(index, this.boundingBoxComponentType); + + assert boundingBoxComponent != null; + + ModelSystems.UpdateBoundingBox.updateBoundingBox(model, boundingBoxComponent, newMovementStates); } } } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/system/RespondToHitSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/system/RespondToHitSystems.java index 58726545..b797fb6a 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/system/RespondToHitSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/system/RespondToHitSystems.java @@ -11,9 +11,9 @@ import com.hypixel.hytale.component.SystemGroup; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.GameMode; +import com.hypixel.hytale.protocol.RespondToHitUpdate; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.RespondToHit; @@ -125,8 +125,7 @@ public class RespondToHitSystems { } private static void queueUpdatesFor(Ref ref, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.RespondToHit; + RespondToHitUpdate update = new RespondToHitUpdate(); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entity/system/TransformSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/system/TransformSystems.java index 9b011a3c..ae0cdcad 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/system/TransformSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/system/TransformSystems.java @@ -14,11 +14,10 @@ import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3f; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.Direction; import com.hypixel.hytale.protocol.ModelTransform; import com.hypixel.hytale.protocol.Position; +import com.hypixel.hytale.protocol.TransformUpdate; import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; @@ -99,9 +98,7 @@ public class TransformSystems { @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo, boolean newlyVisible ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Transform; - update.transform = sentTransform; + TransformUpdate update = new TransformUpdate(sentTransform); for (Entry, EntityTrackerSystems.EntityViewer> entry : visibleTo.entrySet()) { if (newlyVisible || !ref.equals(entry.getKey())) { diff --git a/src/com/hypixel/hytale/server/core/modules/entity/teleport/Teleport.java b/src/com/hypixel/hytale/server/core/modules/entity/teleport/Teleport.java index b39e3ca9..25e53026 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/teleport/Teleport.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/teleport/Teleport.java @@ -8,6 +8,7 @@ import com.hypixel.hytale.math.vector.Vector3f; import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import java.util.concurrent.CompletableFuture; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -21,6 +22,7 @@ public class Teleport implements Component { @Nullable private Vector3f headRotation; private boolean resetVelocity = true; + private CompletableFuture onComplete; @Nonnull public static ComponentType getComponentType() { @@ -92,6 +94,14 @@ public class Teleport implements Component { return this; } + public void setOnComplete(@Nonnull CompletableFuture onComplete) { + this.onComplete = onComplete; + } + + public CompletableFuture getOnComplete() { + return this.onComplete; + } + @Nullable public World getWorld() { return this.world; diff --git a/src/com/hypixel/hytale/server/core/modules/entity/teleport/TeleportSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/teleport/TeleportSystems.java index a0fc0995..d2ada8d2 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/teleport/TeleportSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/teleport/TeleportSystems.java @@ -23,6 +23,7 @@ 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 com.hypixel.hytale.server.core.util.PositionUtil; +import java.util.concurrent.CompletableFuture; import javax.annotation.Nonnull; public class TeleportSystems { @@ -62,15 +63,22 @@ public class TeleportSystems { headRotationComponent.teleportRotation(teleport.getRotation()); } + CompletableFuture future = teleport.getOnComplete(); + commandBuffer.removeComponent(ref, this.teleportComponentType); World targetWorld = teleport.getWorld(); if (targetWorld != null && !targetWorld.equals(store.getExternalData().getWorld())) { commandBuffer.run(s -> { Holder holder = s.removeEntity(ref, RemoveReason.UNLOAD); - targetWorld.execute(() -> targetWorld.getEntityStore().getStore().addEntity(holder, AddReason.LOAD)); + targetWorld.execute(() -> { + targetWorld.getEntityStore().getStore().addEntity(holder, AddReason.LOAD); + if (future != null) { + future.complete(null); + } + }); }); + } else if (future != null) { + future.complete(null); } - - commandBuffer.removeComponent(ref, this.teleportComponentType); } public void onComponentRemoved( @@ -223,7 +231,21 @@ public class TeleportSystems { TeleportRecord teleportRecord = s.ensureAndGetComponent(ref, TeleportRecord.getComponentType()); teleportRecord.setLastTeleport(new TeleportRecord.Entry(origin, destination, System.nanoTime())); playerRefComponent.removeFromStore(); - targetWorld.addPlayer(playerRefComponent, new Transform(teleport.getPosition(), teleport.getRotation())); + CompletableFuture fut = targetWorld.addPlayer(playerRefComponent, new Transform(teleport.getPosition(), teleport.getRotation())); + CompletableFuture future = teleport.getOnComplete(); + if (future != null) { + if (fut != null) { + fut.whenComplete((playerRef, throwable) -> { + if (throwable != null) { + future.completeExceptionally(throwable); + } else { + future.complete(null); + } + }); + } else { + future.completeExceptionally(new RuntimeException("Failed to teleport player to world " + targetWorld.getName())); + } + } }); } @@ -270,6 +292,11 @@ public class TeleportSystems { teleport.isResetVelocity() ); playerRefComponent.getPacketHandler().write(teleportPacket); + CompletableFuture future = teleport.getOnComplete(); + if (future != null) { + future.complete(null); + } + commandBuffer.removeComponent(ref, this.teleportComponentType); } } diff --git a/src/com/hypixel/hytale/server/core/modules/entity/tracker/EntityTrackerSystems.java b/src/com/hypixel/hytale/server/core/modules/entity/tracker/EntityTrackerSystems.java index 0bff8910..0e8278d5 100644 --- a/src/com/hypixel/hytale/server/core/modules/entity/tracker/EntityTrackerSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entity/tracker/EntityTrackerSystems.java @@ -24,6 +24,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.EntityEffectsUpdate; import com.hypixel.hytale.protocol.packets.entities.EntityUpdates; import com.hypixel.hytale.server.core.entity.effect.EffectControllerComponent; import com.hypixel.hytale.server.core.modules.entity.EntityModule; @@ -54,51 +55,66 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class EntityTrackerSystems { + @Nonnull public static final SystemGroup FIND_VISIBLE_ENTITIES_GROUP = EntityStore.REGISTRY.registerSystemGroup(); + @Nonnull public static final SystemGroup QUEUE_UPDATE_GROUP = EntityStore.REGISTRY.registerSystemGroup(); public static boolean despawnAll(@Nonnull Ref viewerRef, @Nonnull Store store) { - EntityTrackerSystems.EntityViewer viewer = store.getComponent(viewerRef, EntityTrackerSystems.EntityViewer.getComponentType()); - if (viewer == null) { + if (!viewerRef.isValid()) { return false; } else { - int networkId = viewer.sent.removeInt(viewerRef); - EntityUpdates packet = new EntityUpdates(); - packet.removed = viewer.sent.values().toIntArray(); - viewer.packetReceiver.writeNoCache(packet); - clear(viewerRef, store); - viewer.sent.put(viewerRef, networkId); - return true; + EntityTrackerSystems.EntityViewer entityViewerComponent = store.getComponent(viewerRef, EntityTrackerSystems.EntityViewer.getComponentType()); + if (entityViewerComponent == null) { + return false; + } else { + int networkId = entityViewerComponent.sent.removeInt(viewerRef); + EntityUpdates packet = new EntityUpdates(); + packet.removed = entityViewerComponent.sent.values().toIntArray(); + entityViewerComponent.packetReceiver.writeNoCache(packet); + clear(viewerRef, store); + entityViewerComponent.sent.put(viewerRef, networkId); + return true; + } } } public static boolean clear(@Nonnull Ref viewerRef, @Nonnull Store store) { - EntityTrackerSystems.EntityViewer viewer = store.getComponent(viewerRef, EntityTrackerSystems.EntityViewer.getComponentType()); - if (viewer == null) { + if (!viewerRef.isValid()) { return false; } else { - for (Ref ref : viewer.sent.keySet()) { - EntityTrackerSystems.Visible visible = store.getComponent(ref, EntityTrackerSystems.Visible.getComponentType()); - if (visible != null) { - visible.visibleTo.remove(viewerRef); + EntityTrackerSystems.EntityViewer entityViewerComponent = store.getComponent(viewerRef, EntityTrackerSystems.EntityViewer.getComponentType()); + if (entityViewerComponent == null) { + return false; + } else { + for (Ref ref : entityViewerComponent.sent.keySet()) { + if (ref != null && ref.isValid()) { + EntityTrackerSystems.Visible visibleComponent = store.getComponent(ref, EntityTrackerSystems.Visible.getComponentType()); + if (visibleComponent != null) { + visibleComponent.visibleTo.remove(viewerRef); + } + } } - } - viewer.sent.clear(); - return true; + entityViewerComponent.sent.clear(); + return true; + } } } public static class AddToVisible extends EntityTickingSystem { + @Nonnull public static final Set> DEPENDENCIES = Collections.singleton( new SystemDependency<>(Order.AFTER, EntityTrackerSystems.EnsureVisibleComponent.class) ); + @Nonnull private final ComponentType entityViewerComponentType; + @Nonnull private final ComponentType visibleComponentType; public AddToVisible( - ComponentType entityViewerComponentType, - ComponentType visibleComponentType + @Nonnull ComponentType entityViewerComponentType, + @Nonnull ComponentType visibleComponentType ) { this.entityViewerComponentType = entityViewerComponentType; this.visibleComponentType = visibleComponentType; @@ -128,23 +144,32 @@ public class EntityTrackerSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - Ref viewerRef = archetypeChunk.getReferenceTo(index); - EntityTrackerSystems.EntityViewer viewer = archetypeChunk.getComponent(index, this.entityViewerComponentType); + Ref ref = archetypeChunk.getReferenceTo(index); + EntityTrackerSystems.EntityViewer entityViewerComponent = archetypeChunk.getComponent(index, this.entityViewerComponentType); - for (Ref ref : viewer.visible) { - commandBuffer.getComponent(ref, this.visibleComponentType).addViewerParallel(viewerRef, viewer); + assert entityViewerComponent != null; + + for (Ref vislbleRef : entityViewerComponent.visible) { + if (vislbleRef != null && vislbleRef.isValid()) { + EntityTrackerSystems.Visible visibleComponent = commandBuffer.getComponent(vislbleRef, this.visibleComponentType); + if (visibleComponent != null) { + visibleComponent.addViewerParallel(ref, entityViewerComponent); + } + } } } } public static class ClearEntityViewers extends EntityTickingSystem { + @Nonnull public static final Set> DEPENDENCIES = Collections.singleton( new SystemGroupDependency<>(Order.BEFORE, EntityTrackerSystems.FIND_VISIBLE_ENTITIES_GROUP) ); - private final ComponentType componentType; + @Nonnull + private final ComponentType entityViewerComponentType; - public ClearEntityViewers(ComponentType componentType) { - this.componentType = componentType; + public ClearEntityViewers(@Nonnull ComponentType entityViewerComponentType) { + this.entityViewerComponentType = entityViewerComponentType; } @Nonnull @@ -155,7 +180,7 @@ public class EntityTrackerSystems { @Override public Query getQuery() { - return this.componentType; + return this.entityViewerComponentType; } @Override @@ -171,22 +196,27 @@ public class EntityTrackerSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - EntityTrackerSystems.EntityViewer viewer = archetypeChunk.getComponent(index, this.componentType); - viewer.visible.clear(); - viewer.lodExcludedCount = 0; - viewer.hiddenCount = 0; + EntityTrackerSystems.EntityViewer entityViewerComponent = archetypeChunk.getComponent(index, this.entityViewerComponentType); + + assert entityViewerComponent != null; + + entityViewerComponent.visible.clear(); + entityViewerComponent.lodExcludedCount = 0; + entityViewerComponent.hiddenCount = 0; } } public static class ClearPreviouslyVisible extends EntityTickingSystem { + @Nonnull public static final Set> DEPENDENCIES = Set.of( new SystemDependency<>(Order.AFTER, EntityTrackerSystems.ClearEntityViewers.class), new SystemGroupDependency(Order.AFTER, EntityTrackerSystems.FIND_VISIBLE_ENTITIES_GROUP) ); - private final ComponentType componentType; + @Nonnull + private final ComponentType visibleComponentType; - public ClearPreviouslyVisible(ComponentType componentType) { - this.componentType = componentType; + public ClearPreviouslyVisible(@Nonnull ComponentType visibleComponentType) { + this.visibleComponentType = visibleComponentType; } @Nonnull @@ -197,7 +227,7 @@ public class EntityTrackerSystems { @Override public Query getQuery() { - return this.componentType; + return this.visibleComponentType; } @Override @@ -213,24 +243,29 @@ public class EntityTrackerSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - EntityTrackerSystems.Visible visible = archetypeChunk.getComponent(index, this.componentType); - Map, EntityTrackerSystems.EntityViewer> oldVisibleTo = visible.previousVisibleTo; - visible.previousVisibleTo = visible.visibleTo; - visible.visibleTo = oldVisibleTo; - visible.visibleTo.clear(); - visible.newlyVisibleTo.clear(); + EntityTrackerSystems.Visible visibleComponent = archetypeChunk.getComponent(index, this.visibleComponentType); + + assert visibleComponent != null; + + Map, EntityTrackerSystems.EntityViewer> oldVisibleTo = visibleComponent.previousVisibleTo; + visibleComponent.previousVisibleTo = visibleComponent.visibleTo; + visibleComponent.visibleTo = oldVisibleTo; + visibleComponent.visibleTo.clear(); + visibleComponent.newlyVisibleTo.clear(); } } public static class CollectVisible extends EntityTickingSystem { - private final ComponentType componentType; + @Nonnull + private final ComponentType entityViewerComponentType; + @Nonnull private final Query query; @Nonnull private final Set> dependencies; - public CollectVisible(ComponentType componentType) { - this.componentType = componentType; - this.query = Archetype.of(componentType, TransformComponent.getComponentType()); + public CollectVisible(@Nonnull ComponentType entityViewerComponentType) { + this.entityViewerComponentType = entityViewerComponentType; + this.query = Archetype.of(entityViewerComponentType, TransformComponent.getComponentType()); this.dependencies = Collections.singleton(new SystemDependency<>(Order.AFTER, NetworkSendableSpatialSystem.class)); } @@ -264,14 +299,20 @@ public class EntityTrackerSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - TransformComponent transform = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); - Vector3d position = transform.getPosition(); - EntityTrackerSystems.EntityViewer entityViewer = archetypeChunk.getComponent(index, this.componentType); + TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + + assert transformComponent != null; + + Vector3d position = transformComponent.getPosition(); + EntityTrackerSystems.EntityViewer entityViewerComponent = archetypeChunk.getComponent(index, this.entityViewerComponentType); + + assert entityViewerComponent != null; + SpatialStructure> spatialStructure = store.getResource(EntityModule.get().getNetworkSendableSpatialResourceType()) .getSpatialStructure(); ObjectList> results = SpatialResource.getThreadLocalReferenceList(); - spatialStructure.collect(position, entityViewer.viewRadiusBlocks, results); - entityViewer.visible.addAll(results); + spatialStructure.collect(position, entityViewerComponent.viewRadiusBlocks, results); + entityViewerComponent.visible.addAll(results); } } @@ -321,17 +362,17 @@ public class EntityTrackerSystems { assert visibleComponent != null; - Ref entityRef = archetypeChunk.getReferenceTo(index); EffectControllerComponent effectControllerComponent = archetypeChunk.getComponent(index, this.effectControllerComponentType); assert effectControllerComponent != null; + Ref ref = archetypeChunk.getReferenceTo(index); if (!visibleComponent.newlyVisibleTo.isEmpty()) { - queueFullUpdate(entityRef, effectControllerComponent, visibleComponent.newlyVisibleTo); + queueFullUpdate(ref, effectControllerComponent, visibleComponent.newlyVisibleTo); } if (effectControllerComponent.consumeNetworkOutdated()) { - queueUpdatesFor(entityRef, effectControllerComponent, visibleComponent.visibleTo, visibleComponent.newlyVisibleTo); + queueUpdatesFor(ref, effectControllerComponent, visibleComponent.visibleTo, visibleComponent.newlyVisibleTo); } } @@ -340,8 +381,7 @@ public class EntityTrackerSystems { @Nonnull EffectControllerComponent effectControllerComponent, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.EntityEffects; + EntityEffectsUpdate update = new EntityEffectsUpdate(); update.entityEffectUpdates = effectControllerComponent.createInitUpdates(); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { @@ -355,8 +395,7 @@ public class EntityTrackerSystems { @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo, @Nonnull Map, EntityTrackerSystems.EntityViewer> exclude ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.EntityEffects; + EntityEffectsUpdate update = new EntityEffectsUpdate(); update.entityEffectUpdates = effectControllerComponent.consumeChanges(); if (!exclude.isEmpty()) { for (Entry, EntityTrackerSystems.EntityViewer> entry : visibleTo.entrySet()) { @@ -373,15 +412,18 @@ public class EntityTrackerSystems { } public static class EnsureVisibleComponent extends EntityTickingSystem { + @Nonnull public static final Set> DEPENDENCIES = Collections.singleton( new SystemDependency<>(Order.AFTER, EntityTrackerSystems.ClearPreviouslyVisible.class) ); + @Nonnull private final ComponentType entityViewerComponentType; + @Nonnull private final ComponentType visibleComponentType; public EnsureVisibleComponent( - ComponentType entityViewerComponentType, - ComponentType visibleComponentType + @Nonnull ComponentType entityViewerComponentType, + @Nonnull ComponentType visibleComponentType ) { this.entityViewerComponentType = entityViewerComponentType; this.visibleComponentType = visibleComponentType; @@ -411,9 +453,13 @@ public class EntityTrackerSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - for (Ref ref : archetypeChunk.getComponent(index, this.entityViewerComponentType).visible) { - if (!commandBuffer.getArchetype(ref).contains(this.visibleComponentType)) { - commandBuffer.ensureComponent(ref, this.visibleComponentType); + EntityTrackerSystems.EntityViewer entityViewerComponent = archetypeChunk.getComponent(index, this.entityViewerComponentType); + + assert entityViewerComponent != null; + + for (Ref visibleRef : entityViewerComponent.visible) { + if (visibleRef != null && visibleRef.isValid() && !commandBuffer.getArchetype(visibleRef).contains(this.visibleComponentType)) { + commandBuffer.ensureComponent(visibleRef, this.visibleComponentType); } } } @@ -477,9 +523,13 @@ public class EntityTrackerSystems { public static class EntityViewer implements Component { public int viewRadiusBlocks; + @Nonnull public IPacketReceiver packetReceiver; + @Nonnull public Set> visible; + @Nonnull public Map, EntityTrackerSystems.EntityUpdate> updates; + @Nonnull public Object2IntMap> sent; public int lodExcludedCount; public int hiddenCount; @@ -488,7 +538,7 @@ public class EntityTrackerSystems { return EntityModule.get().getEntityViewerComponentType(); } - public EntityViewer(int viewRadiusBlocks, IPacketReceiver packetReceiver) { + public EntityViewer(int viewRadiusBlocks, @Nonnull IPacketReceiver packetReceiver) { this.viewRadiusBlocks = viewRadiusBlocks; this.packetReceiver = packetReceiver; this.visible = new ObjectOpenHashSet<>(); @@ -517,7 +567,7 @@ public class EntityTrackerSystems { return new EntityTrackerSystems.EntityViewer(this); } - public void queueRemove(Ref ref, ComponentUpdateType type) { + public void queueRemove(@Nonnull Ref ref, @Nonnull ComponentUpdateType type) { if (!this.visible.contains(ref)) { throw new IllegalArgumentException("Entity is not visible!"); } else { @@ -525,7 +575,7 @@ public class EntityTrackerSystems { } } - public void queueUpdate(Ref ref, ComponentUpdate update) { + public void queueUpdate(@Nonnull Ref ref, @Nonnull ComponentUpdate update) { if (!this.visible.contains(ref)) { throw new IllegalArgumentException("Entity is not visible!"); } else { @@ -535,14 +585,16 @@ public class EntityTrackerSystems { } public static class RemoveEmptyVisibleComponent extends EntityTickingSystem { + @Nonnull public static final Set> DEPENDENCIES = Set.of( new SystemDependency<>(Order.AFTER, EntityTrackerSystems.AddToVisible.class), new SystemGroupDependency(Order.BEFORE, EntityTrackerSystems.QUEUE_UPDATE_GROUP) ); - private final ComponentType componentType; + @Nonnull + private final ComponentType visibleComponentType; - public RemoveEmptyVisibleComponent(ComponentType componentType) { - this.componentType = componentType; + public RemoveEmptyVisibleComponent(@Nonnull ComponentType visibleComponentType) { + this.visibleComponentType = visibleComponentType; } @Nonnull @@ -553,7 +605,7 @@ public class EntityTrackerSystems { @Override public Query getQuery() { - return this.componentType; + return this.visibleComponentType; } @Override @@ -569,22 +621,27 @@ public class EntityTrackerSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - if (archetypeChunk.getComponent(index, this.componentType).visibleTo.isEmpty()) { - commandBuffer.removeComponent(archetypeChunk.getReferenceTo(index), this.componentType); + EntityTrackerSystems.Visible visibleComponent = archetypeChunk.getComponent(index, this.visibleComponentType); + + assert visibleComponent != null; + + if (visibleComponent.visibleTo.isEmpty()) { + commandBuffer.removeComponent(archetypeChunk.getReferenceTo(index), this.visibleComponentType); } } } public static class RemoveVisibleComponent extends HolderSystem { - private final ComponentType componentType; + @Nonnull + private final ComponentType visibleComponentType; - public RemoveVisibleComponent(ComponentType componentType) { - this.componentType = componentType; + public RemoveVisibleComponent(@Nonnull ComponentType visibleComponentType) { + this.visibleComponentType = visibleComponentType; } @Override public Query getQuery() { - return this.componentType; + return this.visibleComponentType; } @Override @@ -593,18 +650,22 @@ public class EntityTrackerSystems { @Override public void onEntityRemoved(@Nonnull Holder holder, @Nonnull RemoveReason reason, @Nonnull Store store) { - holder.removeComponent(this.componentType); + holder.removeComponent(this.visibleComponentType); } } public static class SendPackets extends EntityTickingSystem { + @Nonnull public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull public static final ThreadLocal INT_LIST_THREAD_LOCAL = ThreadLocal.withInitial(IntArrayList::new); + @Nonnull public static final Set> DEPENDENCIES = Set.of(new SystemGroupDependency<>(Order.AFTER, EntityTrackerSystems.QUEUE_UPDATE_GROUP)); - private final ComponentType componentType; + @Nonnull + private final ComponentType entityViewerComponentType; - public SendPackets(ComponentType componentType) { - this.componentType = componentType; + public SendPackets(@Nonnull ComponentType entityViewerComponentType) { + this.entityViewerComponentType = entityViewerComponentType; } @Nullable @@ -621,7 +682,7 @@ public class EntityTrackerSystems { @Override public Query getQuery() { - return this.componentType; + return this.entityViewerComponentType; } @Override @@ -637,61 +698,70 @@ public class EntityTrackerSystems { @Nonnull Store store, @Nonnull CommandBuffer commandBuffer ) { - EntityTrackerSystems.EntityViewer viewer = archetypeChunk.getComponent(index, this.componentType); + EntityTrackerSystems.EntityViewer entityViewerComponent = archetypeChunk.getComponent(index, this.entityViewerComponentType); + + assert entityViewerComponent != null; + IntList removedEntities = INT_LIST_THREAD_LOCAL.get(); removedEntities.clear(); - int before = viewer.updates.size(); - viewer.updates.entrySet().removeIf(v -> !v.getKey().isValid()); - if (before != viewer.updates.size()) { - LOGGER.atWarning().log("Removed %d invalid updates for removed entities.", before - viewer.updates.size()); + int before = entityViewerComponent.updates.size(); + entityViewerComponent.updates.entrySet().removeIf(v -> !v.getKey().isValid()); + if (before != entityViewerComponent.updates.size()) { + LOGGER.atWarning().log("Removed %d invalid updates for removed entities.", before - entityViewerComponent.updates.size()); } - ObjectIterator>> iterator = viewer.sent.object2IntEntrySet().iterator(); + ObjectIterator>> iterator = entityViewerComponent.sent + .object2IntEntrySet() + .iterator(); while (iterator.hasNext()) { it.unimi.dsi.fastutil.objects.Object2IntMap.Entry> entry = iterator.next(); Ref ref = entry.getKey(); - if (!ref.isValid() || !viewer.visible.contains(ref)) { + if (ref == null || !ref.isValid() || !entityViewerComponent.visible.contains(ref)) { removedEntities.add(entry.getIntValue()); iterator.remove(); - if (viewer.updates.remove(ref) != null) { + if (entityViewerComponent.updates.remove(ref) != null) { LOGGER.atSevere().log("Entity can't be removed and also receive an update! " + ref); } } } - if (!removedEntities.isEmpty() || !viewer.updates.isEmpty()) { - Iterator> iteratorx = viewer.updates.keySet().iterator(); + if (!removedEntities.isEmpty() || !entityViewerComponent.updates.isEmpty()) { + Iterator> iteratorx = entityViewerComponent.updates.keySet().iterator(); while (iteratorx.hasNext()) { Ref ref = iteratorx.next(); - if (!ref.isValid() || ref.getStore() != store) { + if (ref == null || !ref.isValid() || ref.getStore() != store) { iteratorx.remove(); - } else if (!viewer.sent.containsKey(ref)) { - int networkId = commandBuffer.getComponent(ref, NetworkId.getComponentType()).getId(); + } else if (!entityViewerComponent.sent.containsKey(ref)) { + NetworkId networkIdComponent = commandBuffer.getComponent(ref, NetworkId.getComponentType()); + + assert networkIdComponent != null; + + int networkId = networkIdComponent.getId(); if (networkId == -1) { throw new IllegalArgumentException("Invalid entity network id: " + ref); } - viewer.sent.put(ref, networkId); + entityViewerComponent.sent.put(ref, networkId); } } EntityUpdates packet = new EntityUpdates(); packet.removed = !removedEntities.isEmpty() ? removedEntities.toIntArray() : null; - packet.updates = new com.hypixel.hytale.protocol.EntityUpdate[viewer.updates.size()]; + packet.updates = new com.hypixel.hytale.protocol.EntityUpdate[entityViewerComponent.updates.size()]; int i = 0; - for (Entry, EntityTrackerSystems.EntityUpdate> entry : viewer.updates.entrySet()) { + for (Entry, EntityTrackerSystems.EntityUpdate> entry : entityViewerComponent.updates.entrySet()) { com.hypixel.hytale.protocol.EntityUpdate entityUpdate = packet.updates[i++] = new com.hypixel.hytale.protocol.EntityUpdate(); - entityUpdate.networkId = viewer.sent.getInt(entry.getKey()); + entityUpdate.networkId = entityViewerComponent.sent.getInt(entry.getKey()); EntityTrackerSystems.EntityUpdate update = entry.getValue(); entityUpdate.removed = update.toRemovedArray(); entityUpdate.updates = update.toUpdatesArray(); } - viewer.updates.clear(); - viewer.packetReceiver.writeNoCache(packet); + entityViewerComponent.updates.clear(); + entityViewerComponent.packetReceiver.writeNoCache(packet); } } } @@ -717,13 +787,13 @@ public class EntityTrackerSystems { return new EntityTrackerSystems.Visible(); } - public void addViewerParallel(Ref ref, EntityTrackerSystems.EntityViewer entityViewer) { + public void addViewerParallel(@Nonnull Ref ref, @Nonnull EntityTrackerSystems.EntityViewer entityViewerComponent) { long stamp = this.lock.writeLock(); try { - this.visibleTo.put(ref, entityViewer); + this.visibleTo.put(ref, entityViewerComponent); if (!this.previousVisibleTo.containsKey(ref)) { - this.newlyVisibleTo.put(ref, entityViewer); + this.newlyVisibleTo.put(ref, entityViewerComponent); } } finally { this.lock.unlockWrite(stamp); 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..57ddbaa3 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 @@ -13,10 +13,11 @@ import com.hypixel.hytale.component.dependency.SystemDependency; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.math.vector.Vector3d; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; -import com.hypixel.hytale.protocol.Equipment; +import com.hypixel.hytale.protocol.EquipmentUpdate; import com.hypixel.hytale.protocol.ItemArmorSlot; +import com.hypixel.hytale.protocol.ModelUpdate; +import com.hypixel.hytale.protocol.PlayerSkinUpdate; +import com.hypixel.hytale.protocol.PropUpdate; import com.hypixel.hytale.server.core.asset.type.gameplay.PlayerConfig; import com.hypixel.hytale.server.core.entity.Entity; import com.hypixel.hytale.server.core.entity.EntityUtils; @@ -30,6 +31,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,24 +117,35 @@ 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; - update.model = model != null ? model.getModel().toPacket() : null; - update.entityScale = entityScale; + ModelUpdate update = new ModelUpdate(model != null ? model.getModel().toPacket() : null, entityScale); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); } + + if (isProp) { + PropUpdate propUpdate = new PropUpdate(); + + for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { + viewer.queueUpdate(ref, propUpdate); + } + } } } @@ -194,8 +207,7 @@ public class LegacyEntityTrackerSystems { private static void queueUpdatesFor( Ref ref, @Nonnull PlayerSkinComponent component, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.PlayerSkin; + PlayerSkinUpdate update = new PlayerSkinUpdate(); update.skin = component.getPlayerSkin(); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { @@ -257,14 +269,12 @@ public class LegacyEntityTrackerSystems { private static void queueUpdatesFor( @Nonnull Ref ref, @Nonnull LivingEntity entity, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Equipment; - update.equipment = new Equipment(); + EquipmentUpdate update = new EquipmentUpdate(); Inventory inventory = entity.getInventory(); ItemContainer armor = inventory.getArmor(); - update.equipment.armorIds = new String[armor.getCapacity()]; - Arrays.fill(update.equipment.armorIds, ""); - armor.forEachWithMeta((slot, itemStack, armorIds) -> armorIds[slot] = itemStack.getItemId(), update.equipment.armorIds); + update.armorIds = new String[armor.getCapacity()]; + Arrays.fill(update.armorIds, ""); + armor.forEachWithMeta((slot, itemStack, armorIds) -> armorIds[slot] = itemStack.getItemId(), update.armorIds); Store store = ref.getStore(); PlayerSettings playerSettings = store.getComponent(ref, PlayerSettings.getComponentType()); if (playerSettings != null) { @@ -274,26 +284,26 @@ public class LegacyEntityTrackerSystems { .getPlayerConfig() .getArmorVisibilityOption(); if (armorVisibilityOption.canHideHelmet() && playerSettings.hideHelmet()) { - update.equipment.armorIds[ItemArmorSlot.Head.ordinal()] = ""; + update.armorIds[ItemArmorSlot.Head.ordinal()] = ""; } if (armorVisibilityOption.canHideCuirass() && playerSettings.hideCuirass()) { - update.equipment.armorIds[ItemArmorSlot.Chest.ordinal()] = ""; + update.armorIds[ItemArmorSlot.Chest.ordinal()] = ""; } if (armorVisibilityOption.canHideGauntlets() && playerSettings.hideGauntlets()) { - update.equipment.armorIds[ItemArmorSlot.Hands.ordinal()] = ""; + update.armorIds[ItemArmorSlot.Hands.ordinal()] = ""; } if (armorVisibilityOption.canHidePants() && playerSettings.hidePants()) { - update.equipment.armorIds[ItemArmorSlot.Legs.ordinal()] = ""; + update.armorIds[ItemArmorSlot.Legs.ordinal()] = ""; } } ItemStack itemInHand = inventory.getItemInHand(); - update.equipment.rightHandItemId = itemInHand != null ? itemInHand.getItemId() : "Empty"; + update.rightHandItemId = itemInHand != null ? itemInHand.getItemId() : "Empty"; ItemStack utilityItem = inventory.getUtilityItem(); - update.equipment.leftHandItemId = utilityItem != null ? utilityItem.getItemId() : "Empty"; + update.leftHandItemId = utilityItem != null ? utilityItem.getItemId() : "Empty"; for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entitystats/EntityStatMap.java b/src/com/hypixel/hytale/server/core/modules/entitystats/EntityStatMap.java index 8902ce7f..8b1bea91 100644 --- a/src/com/hypixel/hytale/server/core/modules/entitystats/EntityStatMap.java +++ b/src/com/hypixel/hytale/server/core/modules/entitystats/EntityStatMap.java @@ -505,12 +505,30 @@ public class EntityStatMap implements Component { map.update(); for (int i = 0; i < this.values.length; i++) { - map.values[i].set(this.values[i].get()); + if (this.values[i] != null) { + EntityStatValue value = this.values[i]; + map.values[i].set(value.get()); + Map modifiers = value.getModifiers(); + if (modifiers != null) { + for (java.util.Map.Entry entry : modifiers.entrySet()) { + map.values[i].putModifier(entry.getKey(), entry.getValue()); + } + } + } + } + + for (Entry> entry : this.selfUpdates.int2ObjectEntrySet()) { + map.selfUpdates.put(entry.getIntKey(), new ObjectArrayList<>(entry.getValue())); + } + + for (Entry entry : this.selfStatValues.int2ObjectEntrySet()) { + map.selfStatValues.put(entry.getIntKey(), new FloatArrayList(entry.getValue())); + } + + for (Entry> entry : this.otherUpdates.int2ObjectEntrySet()) { + map.otherUpdates.put(entry.getIntKey(), new ObjectArrayList<>(entry.getValue())); } - map.selfUpdates.putAll(this.selfUpdates); - map.selfStatValues.putAll(this.selfStatValues); - map.otherUpdates.putAll(this.otherUpdates); return map; } diff --git a/src/com/hypixel/hytale/server/core/modules/entitystats/EntityStatsSystems.java b/src/com/hypixel/hytale/server/core/modules/entitystats/EntityStatsSystems.java index 685dec47..eff8bc7a 100644 --- a/src/com/hypixel/hytale/server/core/modules/entitystats/EntityStatsSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entitystats/EntityStatsSystems.java @@ -19,9 +19,9 @@ import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.ISystem; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.EntityStatUpdate; +import com.hypixel.hytale.protocol.EntityStatsUpdate; import com.hypixel.hytale.protocol.InteractionType; import com.hypixel.hytale.server.core.asset.type.item.config.Item; import com.hypixel.hytale.server.core.entity.EntityUtils; @@ -320,17 +320,13 @@ public class EntityStatsSystems { if (statMap.consumeSelfNetworkOutdated()) { EntityTrackerSystems.EntityViewer selfEntityViewer = visible.visibleTo.get(ref); if (selfEntityViewer != null && !visible.newlyVisibleTo.containsKey(ref)) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.EntityStats; - update.entityStatUpdates = statMap.consumeSelfUpdates(); + EntityStatsUpdate update = new EntityStatsUpdate(statMap.consumeSelfUpdates()); selfEntityViewer.queueUpdate(ref, update); } } if (statMap.consumeNetworkOutdated()) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.EntityStats; - update.entityStatUpdates = statMap.consumeOtherUpdates(); + EntityStatsUpdate update = new EntityStatsUpdate(statMap.consumeOtherUpdates()); for (Entry, EntityTrackerSystems.EntityViewer> entry : visible.visibleTo.entrySet()) { Ref viewerRef = entry.getKey(); @@ -344,9 +340,7 @@ public class EntityStatsSystems { private static void queueUpdatesForNewlyVisible( @Nonnull Ref ref, @Nonnull EntityStatMap statMap, @Nonnull Map, EntityTrackerSystems.EntityViewer> newlyVisibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.EntityStats; - update.entityStatUpdates = statMap.createInitUpdate(false); + EntityStatsUpdate update = new EntityStatsUpdate(statMap.createInitUpdate(false)); for (Entry, EntityTrackerSystems.EntityViewer> entry : newlyVisibleTo.entrySet()) { if (ref.equals(entry.getKey())) { @@ -360,9 +354,7 @@ public class EntityStatsSystems { private static void queueUpdateForNewlyVisibleSelf( Ref ref, @Nonnull EntityStatMap statMap, @Nonnull EntityTrackerSystems.EntityViewer viewer ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.EntityStats; - update.entityStatUpdates = statMap.createInitUpdate(true); + EntityStatsUpdate update = new EntityStatsUpdate(statMap.createInitUpdate(true)); viewer.queueUpdate(ref, update); } } diff --git a/src/com/hypixel/hytale/server/core/modules/entitystats/asset/EntityStatType.java b/src/com/hypixel/hytale/server/core/modules/entitystats/asset/EntityStatType.java index 448a3f59..7ac317bb 100644 --- a/src/com/hypixel/hytale/server/core/modules/entitystats/asset/EntityStatType.java +++ b/src/com/hypixel/hytale/server/core/modules/entitystats/asset/EntityStatType.java @@ -92,6 +92,13 @@ public class EntityStatType (entityStatType, parent) -> entityStatType.ignoreInvulnerability = parent.ignoreInvulnerability ) .add() + .appendInherited( + new KeyedCodec<>("HideFromTooltip", Codec.BOOLEAN), + (entityStatType, aBoolean) -> entityStatType.hideFromTooltip = aBoolean, + entityStatType -> entityStatType.hideFromTooltip, + (entityStatType, parent) -> entityStatType.hideFromTooltip = parent.hideFromTooltip + ) + .add() .build(); public static final ValidatorCache VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(EntityStatType::getAssetStore)); private static AssetStore> ASSET_STORE; @@ -107,6 +114,7 @@ public class EntityStatType @Nullable protected EntityStatType.Regenerating[] regenerating; protected boolean ignoreInvulnerability; + protected boolean hideFromTooltip; protected EntityStatType.EntityStatEffects minValueEffects; protected EntityStatType.EntityStatEffects maxValueEffects; protected EntityStatResetBehavior resetBehavior = EntityStatResetBehavior.InitialValue; @@ -214,6 +222,7 @@ public class EntityStatType } packet.resetBehavior = this.resetBehavior; + packet.hideFromTooltip = this.hideFromTooltip; this.cachedPacket = new SoftReference<>(packet); return packet; } @@ -246,6 +255,8 @@ public class EntityStatType + this.resetBehavior + ", ignoreInvulnerability=" + this.ignoreInvulnerability + + ", hideFromTooltip=" + + this.hideFromTooltip + "}"; } diff --git a/src/com/hypixel/hytale/server/core/modules/entitystats/asset/EntityStatTypePacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/entitystats/asset/EntityStatTypePacketGenerator.java index b3bd114e..a50741e3 100644 --- a/src/com/hypixel/hytale/server/core/modules/entitystats/asset/EntityStatTypePacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/entitystats/asset/EntityStatTypePacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.modules.entitystats.asset; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateEntityStatTypes; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -13,7 +13,7 @@ import javax.annotation.Nonnull; public class EntityStatTypePacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateEntityStatTypes packet = new UpdateEntityStatTypes(); packet.type = UpdateType.Init; packet.types = new Int2ObjectOpenHashMap<>(); @@ -33,7 +33,9 @@ public class EntityStatTypePacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets + ) { UpdateEntityStatTypes packet = new UpdateEntityStatTypes(); packet.type = UpdateType.AddOrUpdate; packet.types = new Int2ObjectOpenHashMap<>(); @@ -53,7 +55,7 @@ public class EntityStatTypePacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateEntityStatTypes packet = new UpdateEntityStatTypes(); packet.type = UpdateType.Remove; packet.types = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/modules/entityui/UIComponentSystems.java b/src/com/hypixel/hytale/server/core/modules/entityui/UIComponentSystems.java index 2972872e..4132c1fa 100644 --- a/src/com/hypixel/hytale/server/core/modules/entityui/UIComponentSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/entityui/UIComponentSystems.java @@ -13,8 +13,8 @@ import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.UIComponentsUpdate; import com.hypixel.hytale.server.core.modules.entity.AllLegacyLivingEntityTypesQuery; import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; @@ -153,9 +153,7 @@ public class UIComponentSystems { private static void queueUpdatesFor( Ref ref, @Nonnull UIComponentList uiComponentList, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.UIComponents; - update.entityUIComponents = uiComponentList.getComponentIds(); + UIComponentsUpdate update = new UIComponentsUpdate(uiComponentList.getComponentIds()); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, update); diff --git a/src/com/hypixel/hytale/server/core/modules/entityui/asset/EntityUIComponentPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/entityui/asset/EntityUIComponentPacketGenerator.java index 5d9c9744..bb5c4eeb 100644 --- a/src/com/hypixel/hytale/server/core/modules/entityui/asset/EntityUIComponentPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/entityui/asset/EntityUIComponentPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.modules.entityui.asset; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateEntityUIComponents; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -15,7 +15,9 @@ import javax.annotation.Nonnull; public class EntityUIComponentPacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets + ) { Int2ObjectMap configs = new Int2ObjectOpenHashMap<>(); for (Entry entry : assets.entrySet()) { @@ -26,7 +28,7 @@ public class EntityUIComponentPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query @@ -41,7 +43,7 @@ public class EntityUIComponentPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query ) { Int2ObjectMap configs = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/InteractionPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/InteractionPacketGenerator.java index f27a3124..b0bbdf09 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/InteractionPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/InteractionPacketGenerator.java @@ -2,8 +2,8 @@ package com.hypixel.hytale.server.core.modules.interaction.interaction; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.SimpleInteraction; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateInteractions; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -17,7 +17,7 @@ import javax.annotation.Nonnull; public class InteractionPacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { Int2ObjectMap interactions = new Int2ObjectOpenHashMap<>(); for (Entry entry : assets.entrySet()) { @@ -28,7 +28,7 @@ public class InteractionPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query ) { Int2ObjectMap interactions = new Int2ObjectOpenHashMap<>(); @@ -41,7 +41,7 @@ public class InteractionPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query ) { Int2ObjectMap interactions = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/RootInteractionPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/RootInteractionPacketGenerator.java index b99b401b..bf348407 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/RootInteractionPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/RootInteractionPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.modules.interaction.interaction; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateRootInteractions; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -16,7 +16,7 @@ import javax.annotation.Nonnull; public class RootInteractionPacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { Int2ObjectMap interactions = new Int2ObjectOpenHashMap<>(); for (Entry entry : assets.entrySet()) { @@ -27,7 +27,7 @@ public class RootInteractionPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query @@ -42,7 +42,7 @@ public class RootInteractionPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query ) { Int2ObjectMap interactions = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/UnarmedInteractionsPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/UnarmedInteractionsPacketGenerator.java index c5e253ad..1ae7aae4 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/UnarmedInteractionsPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/UnarmedInteractionsPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.modules.interaction.interaction; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; import com.hypixel.hytale.protocol.InteractionType; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateUnarmedInteractions; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -16,7 +16,7 @@ import javax.annotation.Nonnull; public class UnarmedInteractionsPacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(@Nonnull DefaultAssetMap assetMap, Map assets) { + public ToClientPacket generateInitPacket(@Nonnull DefaultAssetMap assetMap, Map assets) { UpdateUnarmedInteractions packet = new UpdateUnarmedInteractions(); packet.type = UpdateType.Init; UnarmedInteractions unarmedInteraction = assetMap.getAsset("Empty"); @@ -32,7 +32,7 @@ public class UnarmedInteractionsPacketGenerator extends DefaultAssetPacketGenera @Nonnull @Override - public Packet generateUpdatePacket(@Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map loadedAssets) { UpdateUnarmedInteractions packet = new UpdateUnarmedInteractions(); packet.type = UpdateType.AddOrUpdate; UnarmedInteractions unarmedInteraction = loadedAssets.get("Empty"); @@ -48,7 +48,7 @@ public class UnarmedInteractionsPacketGenerator extends DefaultAssetPacketGenera @Nonnull @Override - public Packet generateRemovePacket(Set removed) { + public ToClientPacket generateRemovePacket(Set removed) { UpdateUnarmedInteractions packet = new UpdateUnarmedInteractions(); packet.type = UpdateType.Remove; return packet; 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/client/PlaceFluidInteraction.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/client/PlaceFluidInteraction.java index 25879f1c..4dd9a4e5 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/client/PlaceFluidInteraction.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/client/PlaceFluidInteraction.java @@ -79,7 +79,8 @@ public class PlaceFluidInteraction extends SimpleBlockInteraction { Fluid fluid = Fluid.getAssetMap().getAsset(fluidIndex); Vector3i target = targetBlock; BlockType targetBlockType = world.getBlockType(targetBlock); - if (FluidTicker.isSolid(targetBlockType)) { + FluidTicker ticker = fluid.getTicker(); + if (!ticker.canOccupySolidBlocks() && FluidTicker.isSolid(targetBlockType)) { target = targetBlock.clone(); BlockFace face = BlockFace.fromProtocolFace(context.getClientState().blockFace); target.add(face.getDirection()); 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/ModifyInventoryInteraction.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/ModifyInventoryInteraction.java index b582645d..ee60cbd9 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/ModifyInventoryInteraction.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/ModifyInventoryInteraction.java @@ -121,7 +121,7 @@ public class ModifyInventoryInteraction extends SimpleInstantInteraction { } else { boolean hasRequiredGameMode = this.requiredGameMode == null || playerComponent.getGameMode() == this.requiredGameMode; if (hasRequiredGameMode) { - CombinedItemContainer combinedHotbarFirst = playerComponent.getInventory().getCombinedHotbarFirst(); + CombinedItemContainer combinedHotbarFirst = playerComponent.getInventory().getCombinedBackpackStorageHotbarFirst(); if (this.itemToRemove != null) { ItemStackTransaction removeItemStack = combinedHotbarFirst.removeItemStack(this.itemToRemove, true, true); if (!removeItemStack.succeeded()) { 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/interaction/interaction/config/server/SpawnPrefabInteraction.java b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/SpawnPrefabInteraction.java index 11f08702..282ab664 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/SpawnPrefabInteraction.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/interaction/config/server/SpawnPrefabInteraction.java @@ -63,46 +63,48 @@ public class SpawnPrefabInteraction extends SimpleInstantInteraction { @Override protected void firstRun(@Nonnull InteractionType type, @Nonnull InteractionContext context, @Nonnull CooldownHandler cooldownHandler) { - Path prefabRoot = PrefabStore.get().getAssetPrefabsPath(); - IPrefabBuffer prefab = PrefabBufferUtil.getCached(prefabRoot.resolve(this.prefabPath)); - if (prefab != null) { - CommandBuffer commandBuffer = context.getCommandBuffer(); - World world = commandBuffer.getExternalData().getWorld(); - Ref ref = context.getEntity(); - TransformComponent transformComponent = commandBuffer.getComponent(ref, TransformComponent.getComponentType()); + Path resolvedPath = PrefabStore.get().findAssetPrefabPath(this.prefabPath); + if (resolvedPath != null) { + IPrefabBuffer prefab = PrefabBufferUtil.getCached(resolvedPath); + if (prefab != null) { + CommandBuffer commandBuffer = context.getCommandBuffer(); + World world = commandBuffer.getExternalData().getWorld(); + Ref ref = context.getEntity(); + TransformComponent transformComponent = commandBuffer.getComponent(ref, TransformComponent.getComponentType()); - assert transformComponent != null; + assert transformComponent != null; - Vector3d entityPosition = transformComponent.getPosition(); - Rotation yaw = this.rotationYaw; - Vector3i target; - switch (this.originSource) { - case ENTITY: - target = entityPosition.toVector3i(); - target.add(this.offset); - break; - case BLOCK: - BlockPosition targetBlock = context.getTargetBlock(); - if (targetBlock == null) { - return; - } + Vector3d entityPosition = transformComponent.getPosition(); + Rotation yaw = this.rotationYaw; + Vector3i target; + switch (this.originSource) { + case ENTITY: + target = entityPosition.toVector3i(); + target.add(this.offset); + break; + case BLOCK: + BlockPosition targetBlock = context.getTargetBlock(); + if (targetBlock == null) { + return; + } - WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z)); - if (chunk == null) { - return; - } + WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z)); + if (chunk == null) { + return; + } - Rotation blockYaw = chunk.getRotation(targetBlock.x, targetBlock.y, targetBlock.z).yaw(); - target = new Vector3i(); - blockYaw.rotateYaw(this.offset, target); - yaw = yaw.add(blockYaw); - target.add(targetBlock.x, targetBlock.y, targetBlock.z); - break; - default: - throw new IllegalArgumentException("Unhandled origin source"); + Rotation blockYaw = chunk.getRotation(targetBlock.x, targetBlock.y, targetBlock.z).yaw(); + target = new Vector3i(); + blockYaw.rotateYaw(this.offset, target); + yaw = yaw.add(blockYaw); + target.add(targetBlock.x, targetBlock.y, targetBlock.z); + break; + default: + throw new IllegalArgumentException("Unhandled origin source"); + } + + PrefabUtil.paste(prefab, world, target, yaw, this.force, new FastRandom(), commandBuffer); } - - PrefabUtil.paste(prefab, world, target, yaw, this.force, new FastRandom(), commandBuffer); } } diff --git a/src/com/hypixel/hytale/server/core/modules/interaction/system/InteractionSystems.java b/src/com/hypixel/hytale/server/core/modules/interaction/system/InteractionSystems.java index d0e62bd4..68c2756e 100644 --- a/src/com/hypixel/hytale/server/core/modules/interaction/system/InteractionSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/interaction/system/InteractionSystems.java @@ -15,9 +15,9 @@ import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.component.system.RefSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.logger.HytaleLogger; -import com.hypixel.hytale.protocol.ComponentUpdate; import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.InteractionType; +import com.hypixel.hytale.protocol.InteractionsUpdate; import com.hypixel.hytale.protocol.packets.interaction.SyncInteractionChain; import com.hypixel.hytale.protocol.packets.interaction.SyncInteractionChains; import com.hypixel.hytale.server.core.entity.InteractionManager; @@ -241,16 +241,13 @@ public class InteractionSystems { private static void queueUpdatesFor( @Nonnull Ref ref, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo, @Nonnull Interactions component ) { - ComponentUpdate componentUpdate = new ComponentUpdate(); - componentUpdate.type = ComponentUpdateType.Interactions; Object2IntOpenHashMap interactions = new Object2IntOpenHashMap<>(); for (Entry entry : component.getInteractions().entrySet()) { interactions.put(entry.getKey(), RootInteraction.getRootInteractionIdOrUnknown(entry.getValue())); } - componentUpdate.interactions = interactions; - componentUpdate.interactionHint = component.getInteractionHint(); + InteractionsUpdate componentUpdate = new InteractionsUpdate(interactions, component.getInteractionHint()); for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) { viewer.queueUpdate(ref, componentUpdate); diff --git a/src/com/hypixel/hytale/server/core/modules/item/CraftingRecipePacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/item/CraftingRecipePacketGenerator.java index 8521e2c5..0825ae83 100644 --- a/src/com/hypixel/hytale/server/core/modules/item/CraftingRecipePacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/item/CraftingRecipePacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.modules.item; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateRecipes; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; public class CraftingRecipePacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { UpdateRecipes packet = new UpdateRecipes(); packet.type = UpdateType.Init; packet.recipes = new Object2ObjectOpenHashMap<>(); @@ -28,7 +28,7 @@ public class CraftingRecipePacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query ) { UpdateRecipes packet = new UpdateRecipes(); @@ -43,7 +43,7 @@ public class CraftingRecipePacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query) { + public ToClientPacket generateRemovePacket(DefaultAssetMap assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query) { UpdateRecipes packet = new UpdateRecipes(); packet.type = UpdateType.Remove; packet.removedRecipes = removed.toArray(String[]::new); diff --git a/src/com/hypixel/hytale/server/core/modules/item/ItemPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/item/ItemPacketGenerator.java index f3ff26de..07405044 100644 --- a/src/com/hypixel/hytale/server/core/modules/item/ItemPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/item/ItemPacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.modules.item; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateItems; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; public class ItemPacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { UpdateItems packet = new UpdateItems(); packet.type = UpdateType.Init; packet.items = new Object2ObjectOpenHashMap<>(); @@ -30,7 +30,7 @@ public class ItemPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query) { + public ToClientPacket generateUpdatePacket(DefaultAssetMap assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query) { UpdateItems packet = new UpdateItems(); packet.type = UpdateType.AddOrUpdate; packet.items = new Object2ObjectOpenHashMap<>(); @@ -46,7 +46,7 @@ public class ItemPacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query) { + public ToClientPacket generateRemovePacket(DefaultAssetMap assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query) { UpdateItems packet = new UpdateItems(); packet.type = UpdateType.Remove; packet.removedItems = removed.toArray(String[]::new); diff --git a/src/com/hypixel/hytale/server/core/modules/item/ItemQualityPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/item/ItemQualityPacketGenerator.java index f9d6ad79..767e4069 100644 --- a/src/com/hypixel/hytale/server/core/modules/item/ItemQualityPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/item/ItemQualityPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.modules.item; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateItemQualities; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -14,7 +14,7 @@ import javax.annotation.Nonnull; public class ItemQualityPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { UpdateItemQualities packet = new UpdateItemQualities(); packet.type = UpdateType.Init; packet.itemQualities = new Int2ObjectOpenHashMap<>(); @@ -34,7 +34,9 @@ public class ItemQualityPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Map loadedAssets) { + protected ToClientPacket generateUpdatePacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets + ) { UpdateItemQualities packet = new UpdateItemQualities(); packet.type = UpdateType.AddOrUpdate; packet.itemQualities = new Int2ObjectOpenHashMap<>(); @@ -54,7 +56,7 @@ public class ItemQualityPacketGenerator extends SimpleAssetPacketGenerator assetMap, @Nonnull Set removed) { + protected ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateItemQualities packet = new UpdateItemQualities(); packet.type = UpdateType.Remove; packet.itemQualities = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/modules/item/ItemReticleConfigPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/item/ItemReticleConfigPacketGenerator.java index a105b638..c8477f8d 100644 --- a/src/com/hypixel/hytale/server/core/modules/item/ItemReticleConfigPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/item/ItemReticleConfigPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.modules.item; import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateItemReticles; import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator; @@ -15,7 +15,9 @@ import javax.annotation.Nonnull; public class ItemReticleConfigPacketGenerator extends SimpleAssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket( + @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map assets + ) { UpdateItemReticles packet = new UpdateItemReticles(); packet.type = UpdateType.Init; packet.itemReticleConfigs = new Int2ObjectOpenHashMap<>(); @@ -35,7 +37,7 @@ public class ItemReticleConfigPacketGenerator } @Nonnull - public Packet generateUpdatePacket( + public ToClientPacket generateUpdatePacket( @Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Map loadedAssets ) { UpdateItemReticles packet = new UpdateItemReticles(); @@ -57,7 +59,7 @@ public class ItemReticleConfigPacketGenerator } @Nonnull - public Packet generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull IndexedLookupTableAssetMap assetMap, @Nonnull Set removed) { UpdateItemReticles packet = new UpdateItemReticles(); packet.type = UpdateType.Remove; packet.itemReticleConfigs = new Int2ObjectOpenHashMap<>(); diff --git a/src/com/hypixel/hytale/server/core/modules/item/RecipePacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/item/RecipePacketGenerator.java index 9fc4cf7e..b46966e9 100644 --- a/src/com/hypixel/hytale/server/core/modules/item/RecipePacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/item/RecipePacketGenerator.java @@ -2,7 +2,7 @@ package com.hypixel.hytale.server.core.modules.item; import com.hypixel.hytale.assetstore.AssetUpdateQuery; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateRecipes; import com.hypixel.hytale.server.core.asset.packet.AssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; public class RecipePacketGenerator extends AssetPacketGenerator> { @Nonnull - public Packet generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { + public ToClientPacket generateInitPacket(DefaultAssetMap assetMap, @Nonnull Map assets) { UpdateRecipes packet = new UpdateRecipes(); packet.type = UpdateType.Init; packet.recipes = new Object2ObjectOpenHashMap<>(); @@ -28,7 +28,7 @@ public class RecipePacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Map loadedAssets, @Nonnull AssetUpdateQuery query ) { UpdateRecipes packet = new UpdateRecipes(); @@ -43,7 +43,7 @@ public class RecipePacketGenerator extends AssetPacketGenerator assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query) { + public ToClientPacket generateRemovePacket(DefaultAssetMap assetMap, @Nonnull Set removed, @Nonnull AssetUpdateQuery query) { UpdateRecipes packet = new UpdateRecipes(); packet.type = UpdateType.Remove; packet.recipes = new Object2ObjectOpenHashMap<>(); 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/projectile/config/BallisticData.java b/src/com/hypixel/hytale/server/core/modules/projectile/config/BallisticData.java index 6c330ebd..b36b8a30 100644 --- a/src/com/hypixel/hytale/server/core/modules/projectile/config/BallisticData.java +++ b/src/com/hypixel/hytale/server/core/modules/projectile/config/BallisticData.java @@ -7,6 +7,8 @@ public interface BallisticData { double getVerticalCenterShot(); + double getHorizontalCenterShot(); + double getDepthShot(); boolean isPitchAdjustShot(); diff --git a/src/com/hypixel/hytale/server/core/modules/projectile/config/ProjectileConfig.java b/src/com/hypixel/hytale/server/core/modules/projectile/config/ProjectileConfig.java index 6fd2506a..1f555f9b 100644 --- a/src/com/hypixel/hytale/server/core/modules/projectile/config/ProjectileConfig.java +++ b/src/com/hypixel/hytale/server/core/modules/projectile/config/ProjectileConfig.java @@ -201,6 +201,11 @@ public class ProjectileConfig return this.spawnOffset.y; } + @Override + public double getHorizontalCenterShot() { + return this.spawnOffset.x; + } + @Override public double getDepthShot() { return this.spawnOffset.z; diff --git a/src/com/hypixel/hytale/server/core/modules/projectile/config/ProjectileConfigPacketGenerator.java b/src/com/hypixel/hytale/server/core/modules/projectile/config/ProjectileConfigPacketGenerator.java index afc33acc..cbc2862b 100644 --- a/src/com/hypixel/hytale/server/core/modules/projectile/config/ProjectileConfigPacketGenerator.java +++ b/src/com/hypixel/hytale/server/core/modules/projectile/config/ProjectileConfigPacketGenerator.java @@ -1,7 +1,7 @@ package com.hypixel.hytale.server.core.modules.projectile.config; import com.hypixel.hytale.assetstore.map.DefaultAssetMap; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.UpdateType; import com.hypixel.hytale.protocol.packets.assets.UpdateProjectileConfigs; import com.hypixel.hytale.server.core.asset.packet.DefaultAssetPacketGenerator; @@ -15,7 +15,7 @@ import javax.annotation.Nullable; public class ProjectileConfigPacketGenerator extends DefaultAssetPacketGenerator { @Nonnull @Override - public Packet generateInitPacket(@Nonnull DefaultAssetMap assetMap, Map assets) { + public ToClientPacket generateInitPacket(@Nonnull DefaultAssetMap assetMap, Map assets) { UpdateProjectileConfigs packet = new UpdateProjectileConfigs(); packet.type = UpdateType.Init; Map map = new Object2ObjectOpenHashMap<>(); @@ -32,7 +32,7 @@ public class ProjectileConfigPacketGenerator extends DefaultAssetPacketGenerator @Nonnull @Override - public Packet generateUpdatePacket(@Nonnull Map loadedAssets) { + public ToClientPacket generateUpdatePacket(@Nonnull Map loadedAssets) { UpdateProjectileConfigs packet = new UpdateProjectileConfigs(); packet.type = UpdateType.AddOrUpdate; Map map = new Object2ObjectOpenHashMap<>(); @@ -49,7 +49,7 @@ public class ProjectileConfigPacketGenerator extends DefaultAssetPacketGenerator @Nullable @Override - public Packet generateRemovePacket(@Nonnull Set removed) { + public ToClientPacket generateRemovePacket(@Nonnull Set removed) { UpdateProjectileConfigs packet = new UpdateProjectileConfigs(); packet.type = UpdateType.Remove; packet.removedConfigs = removed.toArray(String[]::new); diff --git a/src/com/hypixel/hytale/server/core/modules/projectile/system/PredictedProjectileSystems.java b/src/com/hypixel/hytale/server/core/modules/projectile/system/PredictedProjectileSystems.java index b40b7755..e15b9002 100644 --- a/src/com/hypixel/hytale/server/core/modules/projectile/system/PredictedProjectileSystems.java +++ b/src/com/hypixel/hytale/server/core/modules/projectile/system/PredictedProjectileSystems.java @@ -8,8 +8,7 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.SystemGroup; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; -import com.hypixel.hytale.protocol.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; +import com.hypixel.hytale.protocol.PredictionUpdate; import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems; import com.hypixel.hytale.server.core.modules.projectile.component.PredictedProjectile; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; @@ -70,9 +69,7 @@ public class PredictedProjectileSystems { @Nonnull PredictedProjectile predictedProjectile, @Nonnull Map, EntityTrackerSystems.EntityViewer> visibleTo ) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Prediction; - update.predictionId = predictedProjectile.getUuid(); + PredictionUpdate update = new PredictionUpdate(predictedProjectile.getUuid()); for (Entry, EntityTrackerSystems.EntityViewer> entry : visibleTo.entrySet()) { entry.getValue().queueUpdate(ref, update); 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..ecfc07c4 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 @@ -3,12 +3,12 @@ package com.hypixel.hytale.server.core.modules.singleplayer.commands; import com.hypixel.hytale.protocol.packets.serveraccess.Access; import com.hypixel.hytale.server.core.Constants; import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.Options; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg; import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase; import com.hypixel.hytale.server.core.modules.singleplayer.SingleplayerModule; -import com.hypixel.hytale.server.core.util.message.MessageFormat; import javax.annotation.Nonnull; public abstract class PlayCommandBase extends CommandBase { @@ -27,32 +27,102 @@ 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())); + if (Options.getOptionSet().valueOf(Options.AUTH_MODE) == Options.AuthMode.OFFLINE) { + context.sendMessage(Message.translation("server.commands.play.offlineMode")); + } else if (!Constants.SINGLEPLAYER) { + 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); + 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", enabled.toString())); + break; + case LAN: + context.sendMessage(Message.translation("server.commands.play.accessAlreadyToggledLan").param("enabled", enabled.toString())); + break; + case Friend: + context.sendMessage(Message.translation("server.commands.play.accessAlreadyToggledFriend").param("enabled", enabled.toString())); + break; + case Open: + context.sendMessage(Message.translation("server.commands.play.accessAlreadyToggledOpen").param("enabled", enabled.toString())); + } } } } diff --git a/src/com/hypixel/hytale/server/core/permissions/HytalePermissions.java b/src/com/hypixel/hytale/server/core/permissions/HytalePermissions.java index 87837372..ef1688b2 100644 --- a/src/com/hypixel/hytale/server/core/permissions/HytalePermissions.java +++ b/src/com/hypixel/hytale/server/core/permissions/HytalePermissions.java @@ -22,6 +22,7 @@ public class HytalePermissions { public static final String WORLD_MAP_COORDINATE_TELEPORT = "hytale.world_map.teleport.coordinate"; public static final String WORLD_MAP_MARKER_TELEPORT = "hytale.world_map.teleport.marker"; public static final String UPDATE_NOTIFY = "hytale.system.update.notify"; + public static final String MODS_OUTDATED_NOTIFY = "hytale.mods.outdated.notify"; @Nonnull public static String fromCommand(@Nonnull String name) { 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/JavaPlugin.java b/src/com/hypixel/hytale/server/core/plugin/JavaPlugin.java index 46422ee3..0638d888 100644 --- a/src/com/hypixel/hytale/server/core/plugin/JavaPlugin.java +++ b/src/com/hypixel/hytale/server/core/plugin/JavaPlugin.java @@ -1,10 +1,8 @@ package com.hypixel.hytale.server.core.plugin; -import com.hypixel.hytale.assetstore.AssetPack; import com.hypixel.hytale.common.plugin.PluginIdentifier; import com.hypixel.hytale.server.core.asset.AssetModule; import java.nio.file.Path; -import java.util.logging.Level; import javax.annotation.Nonnull; public abstract class JavaPlugin extends PluginBase { @@ -26,18 +24,12 @@ public abstract class JavaPlugin extends PluginBase { } @Override - protected void start0() { - super.start0(); + protected void setup0() { + super.setup0(); if (this.getManifest().includesAssetPack()) { AssetModule assetModule = AssetModule.get(); String id = new PluginIdentifier(this.getManifest()).toString(); - AssetPack existing = assetModule.getAssetPack(id); - if (existing != null) { - this.getLogger().at(Level.WARNING).log("Asset pack %s already exists, skipping embedded pack", id); - return; - } - - assetModule.registerPack(id, this.file, this.getManifest()); + assetModule.registerPack(id, this.file, this.getManifest(), true); } } diff --git a/src/com/hypixel/hytale/server/core/plugin/PluginBase.java b/src/com/hypixel/hytale/server/core/plugin/PluginBase.java index c61b3698..0b25e750 100644 --- a/src/com/hypixel/hytale/server/core/plugin/PluginBase.java +++ b/src/com/hypixel/hytale/server/core/plugin/PluginBase.java @@ -87,6 +87,7 @@ public abstract class PluginBase implements CommandOwner { private final Map, IRegistry> codecMapRegistries = new ConcurrentHashMap<>(); @Nonnull private final String basePermission; + private Throwable failureCause; public PluginBase(@Nonnull PluginInit init) { PluginManifest pluginManifest = init.getPluginManifest(); @@ -234,7 +235,7 @@ public abstract class PluginBase implements CommandOwner { } public boolean isDisabled() { - return this.state == PluginState.NONE || this.state == PluginState.DISABLED || this.state == PluginState.SHUTDOWN; + return this.state == PluginState.NONE || this.state == PluginState.DISABLED || this.state == PluginState.SHUTDOWN || this.state == PluginState.FAILED; } public boolean isEnabled() { @@ -251,7 +252,8 @@ public abstract class PluginBase implements CommandOwner { this.setup(); } catch (Throwable var2) { this.logger.at(Level.SEVERE).withCause(var2).log("Failed to setup plugin %s", this.identifier); - this.state = PluginState.DISABLED; + this.state = PluginState.FAILED; + this.failureCause = var2; } } } @@ -270,7 +272,8 @@ public abstract class PluginBase implements CommandOwner { this.state = PluginState.ENABLED; } catch (Throwable var2) { this.logger.at(Level.SEVERE).withCause(var2).log("Failed to start %s", this.identifier); - this.state = PluginState.DISABLED; + this.state = PluginState.FAILED; + this.failureCause = var2; } } } @@ -283,9 +286,13 @@ public abstract class PluginBase implements CommandOwner { try { this.shutdown(); - this.state = PluginState.DISABLED; + this.state = this.failureCause == null ? PluginState.DISABLED : PluginState.FAILED; } catch (Throwable var3) { this.logger.at(Level.SEVERE).withCause(var3).log("Failed to shutdown %s", this.identifier); + this.state = PluginState.FAILED; + if (this.failureCause == null) { + this.failureCause = var3; + } } this.cleanup(shutdown); @@ -310,6 +317,14 @@ public abstract class PluginBase implements CommandOwner { } } + Throwable getFailureCause() { + return this.failureCause; + } + + void setFailureCause(Throwable t) { + this.failureCause = t; + } + @Nonnull public abstract PluginType getType(); } diff --git a/src/com/hypixel/hytale/server/core/plugin/PluginClassLoader.java b/src/com/hypixel/hytale/server/core/plugin/PluginClassLoader.java index 5bbc3a2f..2595dc01 100644 --- a/src/com/hypixel/hytale/server/core/plugin/PluginClassLoader.java +++ b/src/com/hypixel/hytale/server/core/plugin/PluginClassLoader.java @@ -1,5 +1,6 @@ package com.hypixel.hytale.server.core.plugin; +import com.hypixel.hytale.common.plugin.PluginIdentifier; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.io.IOException; import java.net.URL; @@ -10,15 +11,14 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class PluginClassLoader extends URLClassLoader { - public static final String THIRD_PARTY_LOADER_NAME = "ThirdPartyPlugin"; @Nonnull private final PluginManager pluginManager; private final boolean inServerClassPath; @Nullable private JavaPlugin plugin; - public PluginClassLoader(@Nonnull PluginManager pluginManager, boolean inServerClassPath, @Nonnull URL... urls) { - super(inServerClassPath ? "BuiltinPlugin" : "ThirdPartyPlugin", urls, null); + public PluginClassLoader(@Nonnull PluginManager pluginManager, @Nullable PluginIdentifier identifier, boolean inServerClassPath, @Nonnull URL... urls) { + super((inServerClassPath ? "BuiltinPlugin" : "ThirdParty") + (identifier != null ? "(" + identifier + ")" : ""), urls, null); this.inServerClassPath = inServerClassPath; this.pluginManager = pluginManager; } @@ -157,7 +157,7 @@ public class PluginClassLoader extends URLClassLoader { public static boolean isFromThirdPartyPlugin(@Nullable Throwable throwable) { while (throwable != null) { for (StackTraceElement element : throwable.getStackTrace()) { - if ("ThirdPartyPlugin".equals(element.getClassLoaderName())) { + if ("ThirdParty".equals(element.getClassLoaderName())) { return true; } } diff --git a/src/com/hypixel/hytale/server/core/plugin/PluginManager.java b/src/com/hypixel/hytale/server/core/plugin/PluginManager.java index 2a78a065..1ce2d175 100644 --- a/src/com/hypixel/hytale/server/core/plugin/PluginManager.java +++ b/src/com/hypixel/hytale/server/core/plugin/PluginManager.java @@ -7,27 +7,33 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec; import com.hypixel.hytale.codec.util.RawJsonReader; import com.hypixel.hytale.common.plugin.PluginIdentifier; import com.hypixel.hytale.common.plugin.PluginManifest; -import com.hypixel.hytale.common.semver.Semver; import com.hypixel.hytale.common.semver.SemverRange; import com.hypixel.hytale.common.util.java.ManifestUtil; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.event.IEventDispatcher; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.metrics.MetricsRegistry; +import com.hypixel.hytale.server.core.Constants; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.HytaleServerConfig; +import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.Options; import com.hypixel.hytale.server.core.ShutdownReason; import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.command.system.CommandManager; +import com.hypixel.hytale.server.core.config.ModConfig; +import com.hypixel.hytale.server.core.entity.entities.Player; +import com.hypixel.hytale.server.core.event.events.player.AddPlayerToWorldEvent; import com.hypixel.hytale.server.core.plugin.commands.PluginCommand; import com.hypixel.hytale.server.core.plugin.event.PluginSetupEvent; import com.hypixel.hytale.server.core.plugin.pending.PendingLoadJavaPlugin; import com.hypixel.hytale.server.core.plugin.pending.PendingLoadPlugin; +import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.awt.Color; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -40,9 +46,12 @@ import java.net.URLClassLoader; import java.net.URLConnection; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.Duration; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -70,13 +79,14 @@ public class PluginManager { ); private static PluginManager instance; @Nonnull - private final PluginClassLoader corePluginClassLoader = new PluginClassLoader(this, true); + private final PluginClassLoader corePluginClassLoader = new PluginClassLoader(this, null, true); @Nonnull private final List corePlugins = new ObjectArrayList<>(); private final PluginManager.PluginBridgeClassLoader bridgeClassLoader = new PluginManager.PluginBridgeClassLoader(this, PluginManager.class.getClassLoader()); private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private final Map plugins = new Object2ObjectLinkedOpenHashMap<>(); private final Map classLoaders = new ConcurrentHashMap<>(); + private boolean hasOutdatedPlugins = false; private final boolean loadExternalPlugins = true; @Nonnull private PluginState state = PluginState.NONE; @@ -102,14 +112,16 @@ public class PluginManager { this.corePlugins.add(new PendingLoadJavaPlugin(null, builder, this.corePluginClassLoader)); } - private boolean canLoadOnBoot(@Nonnull PluginManifest manifest) { - PluginIdentifier identifier = new PluginIdentifier(manifest); - HytaleServerConfig.ModConfig modConfig = HytaleServer.get().getConfig().getModConfig().get(identifier); + private boolean canLoadOnBoot(@Nonnull PendingLoadPlugin plugin) { + PluginIdentifier identifier = plugin.getIdentifier(); + PluginManifest manifest = plugin.getManifest(); + 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 +147,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()); @@ -145,8 +157,8 @@ public class PluginManager { Path self; try { self = Paths.get(PluginManager.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - } catch (URISyntaxException var18) { - throw new RuntimeException(var18); + } catch (URISyntaxException var30) { + throw new RuntimeException(var30); } this.loadPluginsFromDirectory(pending, self.getParent().resolve("builtin"), false, this.availablePlugins); @@ -171,8 +183,8 @@ public class PluginManager { try { this.validatePluginDeps(pendingLoadPlugin, pending); - } catch (MissingPluginDependencyException var17) { - LOGGER.at(Level.SEVERE).log(var17.getMessage()); + } catch (MissingPluginDependencyException var29) { + LOGGER.at(Level.SEVERE).log(var29.getMessage()); iterator.remove(); } } @@ -180,10 +192,34 @@ public class PluginManager { this.lock.readLock().unlock(); } + if (this.hasOutdatedPlugins && System.getProperty("hytale.allow_outdated_mods") == null) { + LOGGER.at(Level.SEVERE) + .log("One or more plugins are targeting a different server version. It is recommended to update these plugins to ensure compatibility."); + + try { + if (!Constants.SINGLEPLAYER) { + Thread.sleep(Duration.ofSeconds(2L)); + } + } catch (InterruptedException var32) { + throw new RuntimeException(var32); + } + + HytaleServer.get().getEventBus().registerGlobal(AddPlayerToWorldEvent.class, event -> { + PlayerRef playerRef = event.getHolder().getComponent(PlayerRef.getComponentType()); + Player player = event.getHolder().getComponent(Player.getComponentType()); + if (playerRef != null && player != null) { + if (player.hasPermission("hytale.mods.outdated.notify")) { + playerRef.sendMessage(Message.translation("server.pluginManager.outOfDatePlugins").color(Color.RED)); + } + } + }); + } + this.loadOrder = PendingLoadPlugin.calculateLoadOrder(pending); this.loading = new Object2ObjectOpenHashMap<>(); pending.forEach((identifier, pendingLoad) -> this.availablePlugins.put(identifier, pendingLoad.getManifest())); - ObjectArrayList var24 = new ObjectArrayList(); + ObjectArrayList> preLoadFutures = new ObjectArrayList<>(); + ObjectArrayList failedBootPlugins = new ObjectArrayList<>(); this.lock.writeLock().lock(); try { @@ -191,26 +227,55 @@ public class PluginManager { for (PendingLoadPlugin pendingLoadPlugin : this.loadOrder) { LOGGER.at(Level.FINE).log("- %s", pendingLoadPlugin.getIdentifier()); - PluginBase plugin = pendingLoadPlugin.load(); - if (plugin != null) { + + try { + PluginBase plugin = pendingLoadPlugin.load(); this.plugins.put(plugin.getIdentifier(), plugin); this.loading.put(plugin.getIdentifier(), plugin); CompletableFuture future = plugin.preLoad(); if (future != null) { - var24.add(future); + preLoadFutures.add(future); } + } catch (ClassNotFoundException var26) { + LOGGER.at(Level.SEVERE).withCause(var26).log("Failed to load plugin %s. Failed to find main class!", pendingLoadPlugin.getPath()); + failedBootPlugins.add(pendingLoadPlugin.getIdentifier()); + } catch (NoSuchMethodException var27) { + LOGGER.at(Level.SEVERE).withCause(var27).log("Failed to load plugin %s. Requires default constructor!", pendingLoadPlugin.getPath()); + failedBootPlugins.add(pendingLoadPlugin.getIdentifier()); + } catch (Throwable var28) { + LOGGER.at(Level.SEVERE).withCause(var28).log("Failed to load plugin %s", pendingLoadPlugin.getPath()); + failedBootPlugins.add(pendingLoadPlugin.getIdentifier()); } } } finally { this.lock.writeLock().unlock(); } - CompletableFuture.allOf(var24.toArray(CompletableFuture[]::new)).join(); + if (!failedBootPlugins.isEmpty() && !Constants.shouldSkipModValidation()) { + StringBuilder sb = new StringBuilder("Failed to boot the following plugins:\n"); - for (PendingLoadPlugin pendingPlugin : this.loadOrder) { - PluginBase plugin = this.loading.get(pendingPlugin.getIdentifier()); - if (plugin != null && !this.setup(plugin)) { - this.loading.remove(pendingPlugin.getIdentifier()); + for (PluginIdentifier failed : failedBootPlugins) { + sb.append(" - ").append(failed).append('\n'); + } + + HytaleServer.get().shutdownServer(ShutdownReason.MOD_ERROR.withMessage(sb.toString().trim())); + } else { + CompletableFuture.allOf(preLoadFutures.toArray(CompletableFuture[]::new)).join(); + boolean hasFailed = false; + + for (PendingLoadPlugin pendingPlugin : this.loadOrder) { + PluginBase plugin = this.loading.get(pendingPlugin.getIdentifier()); + if (plugin != null && !this.setup(plugin)) { + hasFailed = true; + } + } + + if (!Constants.shouldSkipModValidation() && hasFailed) { + StringBuilder sb = new StringBuilder("Failed to setup the following plugins:\n"); + this.collectFailedPlugins(sb); + HytaleServer.get().shutdownServer(ShutdownReason.MOD_ERROR.withMessage(sb.toString().trim())); + } else { + this.loading.values().removeIf(v -> v.getState().isInactive()); } } } @@ -221,25 +286,23 @@ public class PluginManager { throw new IllegalStateException("Expected PluginState.SETUP but found " + this.state); } else { this.state = PluginState.START; + boolean hasFailed = false; for (PendingLoadPlugin pendingPlugin : this.loadOrder) { PluginBase plugin = this.loading.get(pendingPlugin.getIdentifier()); if (plugin != null && !this.start(plugin)) { - this.loading.remove(pendingPlugin.getIdentifier()); + hasFailed = true; } } - this.loadOrder = null; - this.loading = null; StringBuilder sb = new StringBuilder(); - for (Entry entry : HytaleServer.get().getConfig().getModConfig().entrySet()) { + for (Entry entry : HytaleServer.get().getConfig().getModConfig().entrySet()) { PluginIdentifier identifier = entry.getKey(); - HytaleServerConfig.ModConfig modConfig = entry.getValue(); + ModConfig modConfig = entry.getValue(); SemverRange requiredVersion = modConfig.getRequiredVersion(); if (requiredVersion != null && !this.hasPlugin(identifier, requiredVersion)) { sb.append(String.format("%s, Version: %s\n", identifier, modConfig)); - return; } } @@ -247,6 +310,25 @@ public class PluginManager { String msg = "Failed to start server! Missing Mods:\n" + sb; LOGGER.at(Level.SEVERE).log(msg); HytaleServer.get().shutdownServer(ShutdownReason.MISSING_REQUIRED_PLUGIN.withMessage(msg)); + } else if (hasFailed && !Constants.shouldSkipModValidation()) { + sb = new StringBuilder("Failed to start the following plugins:\n"); + this.collectFailedPlugins(sb); + HytaleServer.get().shutdownServer(ShutdownReason.MOD_ERROR.withMessage(sb.toString().trim())); + } else { + this.loadOrder = null; + this.loading = null; + } + } + } + + private void collectFailedPlugins(StringBuilder sb) { + if (this.loading != null) { + for (Entry failed : this.loading.entrySet()) { + if (failed.getValue().getState() == PluginState.FAILED) { + Throwable reasonThrowable = failed.getValue().getFailureCause(); + String reason = reasonThrowable != null ? reasonThrowable.toString() : "Unknown"; + sb.append(" - ").append(failed.getKey()).append(": ").append(reason).append('\n'); + } } } } @@ -286,48 +368,63 @@ public class PluginManager { } private void validatePluginDeps(@Nonnull PendingLoadPlugin pendingLoadPlugin, @Nullable Map pending) { - Semver serverVersion = ManifestUtil.getVersion(); - SemverRange serverVersionRange = pendingLoadPlugin.getManifest().getServerVersion(); - if (serverVersionRange != null && serverVersion != null && !serverVersionRange.satisfies(serverVersion)) { - throw new MissingPluginDependencyException( - String.format("Failed to load '%s' because version of server does not satisfy '%s'! ", pendingLoadPlugin.getIdentifier(), serverVersion) - ); - } else { - for (Entry entry : pendingLoadPlugin.getManifest().getDependencies().entrySet()) { - PluginIdentifier identifier = entry.getKey(); - PluginManifest dependency = null; - if (pending != null) { - PendingLoadPlugin pendingDependency = pending.get(identifier); - if (pendingDependency != null) { - dependency = pendingDependency.getManifest(); - } - } - - if (dependency == null) { - PluginBase loadedBase = this.plugins.get(identifier); - if (loadedBase != null) { - dependency = loadedBase.getManifest(); - } - } - - if (dependency == null) { - throw new MissingPluginDependencyException( - String.format("Failed to load '%s' because the dependency '%s' could not be found!", pendingLoadPlugin.getIdentifier(), identifier) - ); - } - - SemverRange expectedVersion = entry.getValue(); - if (!dependency.getVersion().satisfies(expectedVersion)) { - throw new MissingPluginDependencyException( - String.format( - "Failed to load '%s' because version of dependency '%s'(%s) does not satisfy '%s'!", + String serverVersion = ManifestUtil.getVersion(); + if (!pendingLoadPlugin.getManifest().getGroup().equals("Hytale")) { + String targetServerVersion = pendingLoadPlugin.getManifest().getServerVersion(); + if (targetServerVersion == null || serverVersion != null && !targetServerVersion.equals(serverVersion)) { + if (targetServerVersion != null && !"*".equals(targetServerVersion)) { + LOGGER.at(Level.WARNING) + .log( + "Plugin '%s' targets a different server version %s. You may encounter issues, please check for plugin updates.", pendingLoadPlugin.getIdentifier(), - identifier, - dependency.getVersion(), - expectedVersion - ) - ); + serverVersion + ); + } else { + LOGGER.at(Level.WARNING) + .log( + "Plugin '%s' does not specify a target server version. You may encounter issues, please check for plugin updates. This will be a hard error in the future", + pendingLoadPlugin.getIdentifier() + ); } + + this.hasOutdatedPlugins = true; + } + } + + for (Entry entry : pendingLoadPlugin.getManifest().getDependencies().entrySet()) { + PluginIdentifier identifier = entry.getKey(); + PluginManifest dependency = null; + if (pending != null) { + PendingLoadPlugin pendingDependency = pending.get(identifier); + if (pendingDependency != null) { + dependency = pendingDependency.getManifest(); + } + } + + if (dependency == null) { + PluginBase loadedBase = this.plugins.get(identifier); + if (loadedBase != null) { + dependency = loadedBase.getManifest(); + } + } + + if (dependency == null) { + throw new MissingPluginDependencyException( + String.format("Failed to load '%s' because the dependency '%s' could not be found!", pendingLoadPlugin.getIdentifier(), identifier) + ); + } + + SemverRange expectedVersion = entry.getValue(); + if (!dependency.getVersion().satisfies(expectedVersion)) { + throw new MissingPluginDependencyException( + String.format( + "Failed to load '%s' because version of dependency '%s'(%s) does not satisfy '%s'!", + pendingLoadPlugin.getIdentifier(), + identifier, + dependency.getVersion(), + expectedVersion + ) + ); } } } @@ -357,7 +454,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()); @@ -374,32 +471,42 @@ public class PluginManager { @Nullable private PendingLoadJavaPlugin loadPendingJavaPlugin(@Nonnull Path file) { try { - URL url = file.toUri().toURL(); - PluginClassLoader pluginClassLoader = this.classLoaders.computeIfAbsent(file, path -> new PluginClassLoader(this, false, url)); - URL resource = pluginClassLoader.findResource("manifest.json"); - if (resource == null) { - LOGGER.at(Level.SEVERE).log("Failed to load pending plugin from '%s'. Failed to load manifest file!", file.toString()); - return null; + PendingLoadJavaPlugin var22; + try (FileSystem fs = FileSystems.newFileSystem(file)) { + Path resource = fs.getPath("manifest.json"); + if (!Files.exists(resource)) { + LOGGER.at(Level.SEVERE).log("Failed to load pending plugin from '%s'. Failed to load manifest file!", file.toString()); + return null; + } + + PluginManifest manifest; + try ( + InputStream stream = Files.newInputStream(resource); + InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8); + ) { + char[] buffer = RawJsonReader.READ_BUFFER.get(); + RawJsonReader rawJsonReader = new RawJsonReader(reader, buffer); + ExtraInfo extraInfo = ExtraInfo.THREAD_LOCAL.get(); + manifest = PluginManifest.CODEC.decodeJson(rawJsonReader, extraInfo); + if (manifest == null) { + LOGGER.at(Level.SEVERE).log("Failed to load pending plugin from '%s'. Failed to decode manifest file!", file.toString()); + return null; + } + + extraInfo.getValidationResults().logOrThrowValidatorExceptions(LOGGER); + } + + URL url = file.toUri().toURL(); + PluginClassLoader pluginClassLoader = this.classLoaders + .computeIfAbsent(file, path -> new PluginClassLoader(this, new PluginIdentifier(manifest), false, url)); + var22 = new PendingLoadJavaPlugin(file, manifest, pluginClassLoader); } - PendingLoadJavaPlugin var11; - try ( - InputStream stream = resource.openStream(); - InputStreamReader reader = new InputStreamReader(stream, 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(LOGGER); - var11 = new PendingLoadJavaPlugin(file, manifest, pluginClassLoader); - } - - return var11; - } catch (MalformedURLException var16) { - LOGGER.at(Level.SEVERE).withCause(var16).log("Failed to load pending plugin from '%s'. Failed to create URLClassLoader!", file.toString()); - } catch (IOException var17) { - LOGGER.at(Level.SEVERE).withCause(var17).log("Failed to load pending plugin %s. Failed to load manifest file!", file.toString()); + return var22; + } catch (MalformedURLException var17) { + LOGGER.at(Level.SEVERE).withCause(var17).log("Failed to load pending plugin from '%s'. Failed to create URLClassLoader!", file.toString()); + } catch (IOException var18) { + LOGGER.at(Level.SEVERE).withCause(var18).log("Failed to load pending plugin %s. Failed to load manifest file!", file.toString()); } return null; @@ -427,27 +534,36 @@ public class PluginManager { ExtraInfo extraInfo = ExtraInfo.THREAD_LOCAL.get(); PluginManifest manifest = PluginManifest.CODEC.decodeJson(rawJsonReader, extraInfo); extraInfo.getValidationResults().logOrThrowValidatorExceptions(LOGGER); - PendingLoadJavaPlugin plugin; - if (connection instanceof JarURLConnection jarURLConnection) { - URL classpathUrl = jarURLConnection.getJarFileURL(); - Path path = Path.of(classpathUrl.toURI()); - PluginClassLoader pluginClassLoader = this.classLoaders.computeIfAbsent(path, f -> new PluginClassLoader(this, true, classpathUrl)); - plugin = new PendingLoadJavaPlugin(path, manifest, pluginClassLoader); - } else { - URI pluginUri = manifestUrl.toURI().resolve("."); - Path path = Paths.get(pluginUri); - URL classpathUrl = pluginUri.toURL(); - PluginClassLoader pluginClassLoader = this.classLoaders.computeIfAbsent(path, f -> new PluginClassLoader(this, true, classpathUrl)); - plugin = new PendingLoadJavaPlugin(path, manifest, pluginClassLoader); + if (manifest != null) { + PendingLoadJavaPlugin plugin; + if (connection instanceof JarURLConnection jarURLConnection) { + URL classpathUrl = jarURLConnection.getJarFileURL(); + Path path = Path.of(classpathUrl.toURI()); + PluginClassLoader pluginClassLoader = this.classLoaders + .computeIfAbsent(path, f -> new PluginClassLoader(this, new PluginIdentifier(manifest), true, classpathUrl)); + plugin = new PendingLoadJavaPlugin(path, manifest, pluginClassLoader); + } else { + URI pluginUri = manifestUrl.toURI().resolve("."); + Path path = Paths.get(pluginUri); + URL classpathUrl = pluginUri.toURL(); + PluginClassLoader pluginClassLoader = this.classLoaders + .computeIfAbsent(path, f -> new PluginClassLoader(this, new PluginIdentifier(manifest), true, classpathUrl)); + plugin = new PendingLoadJavaPlugin(path, manifest, pluginClassLoader); + } + + LOGGER.at(Level.INFO).log("- %s", plugin.getIdentifier()); + if (this.canLoadOnBoot(plugin)) { + loadPendingPlugin(pending, plugin); + } else { + rejectedBootList.put(plugin.getIdentifier(), plugin.getManifest()); + } + continue; } - LOGGER.at(Level.INFO).log("- %s", plugin.getIdentifier()); - if (this.canLoadOnBoot(plugin.getManifest())) { - loadPendingPlugin(pending, plugin); - } else { - rejectedBootList.put(plugin.getIdentifier(), plugin.getManifest()); - } + LOGGER.at(Level.SEVERE).log("Failed to load pending plugin from '%s'. Failed to decode manifest file!", manifestUrl); } + + return; } URL manifestsUrl = classLoader.getResource("manifests.json"); @@ -456,19 +572,19 @@ public class PluginManager { InputStream stream = manifestsUrl.openStream(); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8); ) { - char[] bufferx = RawJsonReader.READ_BUFFER.get(); - RawJsonReader rawJsonReaderx = new RawJsonReader(reader, bufferx); - ExtraInfo extraInfox = ExtraInfo.THREAD_LOCAL.get(); - PluginManifest[] manifests = PluginManifest.ARRAY_CODEC.decodeJson(rawJsonReaderx, extraInfox); - extraInfox.getValidationResults().logOrThrowValidatorExceptions(LOGGER); + char[] buffer = RawJsonReader.READ_BUFFER.get(); + RawJsonReader rawJsonReader = new RawJsonReader(reader, buffer); + ExtraInfo extraInfo = ExtraInfo.THREAD_LOCAL.get(); + PluginManifest[] manifests = PluginManifest.ARRAY_CODEC.decodeJson(rawJsonReader, extraInfo); + extraInfo.getValidationResults().logOrThrowValidatorExceptions(LOGGER); URL url = uri.toURL(); Path path = Paths.get(uri); - PluginClassLoader pluginClassLoader = this.classLoaders.computeIfAbsent(path, f -> new PluginClassLoader(this, true, url)); + PluginClassLoader pluginClassLoader = this.classLoaders.computeIfAbsent(path, f -> new PluginClassLoader(this, null, true, url)); - for (PluginManifest manifestx : manifests) { - PendingLoadJavaPlugin pluginx = new PendingLoadJavaPlugin(path, manifestx, pluginClassLoader); + for (PluginManifest manifest : manifests) { + PendingLoadJavaPlugin pluginx = new PendingLoadJavaPlugin(path, manifest, 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()); @@ -608,7 +724,7 @@ public class PluginManager { continue; } - PluginClassLoader pluginClassLoader = new PluginClassLoader(this, true, uri.toURL()); + PluginClassLoader pluginClassLoader = new PluginClassLoader(this, identifier, true, uri.toURL()); PendingLoadJavaPlugin pluginx = new PendingLoadJavaPlugin(Paths.get(uri), manifestx, pluginClassLoader); manifest = this.load(pluginx); } @@ -630,7 +746,7 @@ public class PluginManager { for (PluginManifest manifest : manifests) { if (new PluginIdentifier(manifest).equals(identifier)) { - PluginClassLoader pluginClassLoader = new PluginClassLoader(this, true, uri.toURL()); + PluginClassLoader pluginClassLoader = new PluginClassLoader(this, identifier, true, uri.toURL()); PendingLoadJavaPlugin pluginx = new PendingLoadJavaPlugin(Paths.get(uri), manifest, pluginClassLoader); return this.load(pluginx); } @@ -731,9 +847,9 @@ public class PluginManager { if (pendingLoadPlugin == null) { return false; } else { - this.validatePluginDeps(pendingLoadPlugin, null); - PluginBase plugin = pendingLoadPlugin.load(); - if (plugin != null) { + try { + this.validatePluginDeps(pendingLoadPlugin, null); + PluginBase plugin = pendingLoadPlugin.load(); this.lock.writeLock().lock(); try { @@ -750,13 +866,23 @@ public class PluginManager { } preload.thenAccept(v -> { - this.setup(plugin); - this.start(plugin); - this.pluginListPageManager.notifyPluginChange(this.plugins, plugin.getIdentifier()); + if (!this.setup(plugin)) { + this.pluginListPageManager.notifyPluginChange(this.plugins, plugin.getIdentifier()); + } else if (!this.start(plugin)) { + this.pluginListPageManager.notifyPluginChange(this.plugins, plugin.getIdentifier()); + } else { + this.pluginListPageManager.notifyPluginChange(this.plugins, plugin.getIdentifier()); + } }); + this.pluginListPageManager.notifyPluginChange(this.plugins, pendingLoadPlugin.getIdentifier()); + } catch (ClassNotFoundException var10) { + LOGGER.at(Level.SEVERE).withCause(var10).log("Failed to load plugin %s. Failed to find main class!", pendingLoadPlugin.getPath()); + } catch (NoSuchMethodException var11) { + LOGGER.at(Level.SEVERE).withCause(var11).log("Failed to load plugin %s. Requires default constructor!", pendingLoadPlugin.getPath()); + } catch (Throwable var12) { + LOGGER.at(Level.SEVERE).withCause(var12).log("Failed to load plugin %s", pendingLoadPlugin.getPath()); } - this.pluginListPageManager.notifyPluginChange(this.plugins, pendingLoadPlugin.getIdentifier()); return false; } } @@ -766,11 +892,16 @@ public class PluginManager { LOGGER.at(Level.FINE).log("Setting up plugin %s", plugin.getIdentifier()); boolean prev = AssetStore.DISABLE_DYNAMIC_DEPENDENCIES; AssetStore.DISABLE_DYNAMIC_DEPENDENCIES = false; - plugin.setup0(); - AssetStore.DISABLE_DYNAMIC_DEPENDENCIES = prev; + + try { + plugin.setup0(); + } finally { + AssetStore.DISABLE_DYNAMIC_DEPENDENCIES = prev; + } + AssetModule.get().initPendingStores(); HytaleServer.get().doneSetup(plugin); - if (plugin.getState() != PluginState.DISABLED) { + if (!plugin.getState().isInactive()) { IEventDispatcher dispatch = HytaleServer.get() .getEventBus() .dispatchFor(PluginSetupEvent.class, (Class)plugin.getClass()); @@ -796,7 +927,7 @@ public class PluginManager { LOGGER.at(Level.FINE).log("Starting plugin %s", plugin.getIdentifier()); plugin.start0(); HytaleServer.get().doneStart(plugin); - if (plugin.getState() != PluginState.DISABLED) { + if (!plugin.getState().isInactive()) { LOGGER.at(Level.INFO).log("Enabled plugin %s", plugin.getIdentifier()); return true; } @@ -817,6 +948,7 @@ public class PluginManager { if (dependency == null || dependency.getState() != requiredState) { LOGGER.at(Level.SEVERE).log(plugin.getName() + " is lacking dependency " + dependencyOnManifest.getName() + " at stage " + stage); LOGGER.at(Level.SEVERE).log(plugin.getName() + " DISABLED!"); + plugin.setFailureCause(new Exception("Missing dependency " + dependencyOnManifest.getName())); return false; } } @@ -826,7 +958,7 @@ public class PluginManager { private static void loadPendingPlugin(@Nonnull Map pending, @Nonnull PendingLoadPlugin plugin) { if (pending.putIfAbsent(plugin.getIdentifier(), plugin) != null) { - throw new IllegalArgumentException("Tried to load duplicate plugin"); + throw new IllegalArgumentException("Tried to load duplicate plugin: " + plugin.getIdentifier()); } else { for (PendingLoadPlugin subPlugin : plugin.createSubPendingLoadPlugins()) { loadPendingPlugin(pending, subPlugin); diff --git a/src/com/hypixel/hytale/server/core/plugin/PluginState.java b/src/com/hypixel/hytale/server/core/plugin/PluginState.java index 7a6967f2..0f06d5ca 100644 --- a/src/com/hypixel/hytale/server/core/plugin/PluginState.java +++ b/src/com/hypixel/hytale/server/core/plugin/PluginState.java @@ -6,5 +6,13 @@ public enum PluginState { START, ENABLED, SHUTDOWN, - DISABLED; + DISABLED, + FAILED; + + public boolean isInactive() { + return switch (this) { + case NONE, DISABLED, FAILED -> true; + default -> false; + }; + } } diff --git a/src/com/hypixel/hytale/server/core/plugin/commands/PluginCommand.java b/src/com/hypixel/hytale/server/core/plugin/commands/PluginCommand.java index 0f35e2c2..bbc0ba18 100644 --- a/src/com/hypixel/hytale/server/core/plugin/commands/PluginCommand.java +++ b/src/com/hypixel/hytale/server/core/plugin/commands/PluginCommand.java @@ -95,7 +95,7 @@ public class PluginCommand extends AbstractCommandCollection { if (identifier != null) { boolean onlyBootList = this.bootFlag.get(context); HytaleServerConfig serverConfig = HytaleServer.get().getConfig(); - HytaleServerConfig.ModConfig.setBoot(serverConfig, identifier, true); + HytaleServerConfig.setBoot(serverConfig, identifier, true); if (serverConfig.consumeHasChanged()) { HytaleServerConfig.save(serverConfig).join(); } @@ -221,7 +221,7 @@ public class PluginCommand extends AbstractCommandCollection { if (identifier != null) { boolean onlyBootList = this.bootFlag.get(context); HytaleServerConfig serverConfig = HytaleServer.get().getConfig(); - HytaleServerConfig.ModConfig.setBoot(serverConfig, identifier, false); + HytaleServerConfig.setBoot(serverConfig, identifier, false); if (serverConfig.consumeHasChanged()) { HytaleServerConfig.save(serverConfig).join(); } diff --git a/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadJavaPlugin.java b/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadJavaPlugin.java index 6bb39ec0..9ccea665 100644 --- a/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadJavaPlugin.java +++ b/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadJavaPlugin.java @@ -8,7 +8,6 @@ import com.hypixel.hytale.server.core.plugin.PluginClassLoader; import com.hypixel.hytale.server.core.plugin.PluginManager; import java.lang.reflect.Constructor; import java.nio.file.Path; -import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -33,28 +32,18 @@ public class PendingLoadJavaPlugin extends PendingLoadPlugin { return this.urlClassLoader.isInServerClassPath(); } - @Nullable - public JavaPlugin load() { - try { - PluginManifest manifest = this.getManifest(); - Class mainClass = this.urlClassLoader.loadLocalClass(manifest.getMain()); - if (JavaPlugin.class.isAssignableFrom(mainClass)) { - Constructor constructor = mainClass.getConstructor(JavaPluginInit.class); - Path dataDirectory = PluginManager.MODS_PATH.resolve(manifest.getGroup() + "_" + manifest.getName()); - JavaPluginInit init = new JavaPluginInit(manifest, dataDirectory, this.getPath(), this.urlClassLoader); - return (JavaPlugin)constructor.newInstance(init); - } - + @Nonnull + public JavaPlugin load() throws Exception { + PluginManifest manifest = this.getManifest(); + Class mainClass = this.urlClassLoader.loadLocalClass(manifest.getMain()); + if (JavaPlugin.class.isAssignableFrom(mainClass)) { + Constructor constructor = mainClass.getConstructor(JavaPluginInit.class); + Path dataDirectory = PluginManager.MODS_PATH.resolve(manifest.getGroup() + "_" + manifest.getName()); + JavaPluginInit init = new JavaPluginInit(manifest, dataDirectory, this.getPath(), this.urlClassLoader); + return (JavaPlugin)constructor.newInstance(init); + } else { throw new ClassCastException(manifest.getMain() + " does not extend JavaPlugin"); - } catch (ClassNotFoundException var6) { - LOGGER.at(Level.SEVERE).withCause(var6).log("Failed to load plugin %s. Failed to find main class!", this.getPath()); - } catch (NoSuchMethodException var7) { - LOGGER.at(Level.SEVERE).withCause(var7).log("Failed to load plugin %s. Requires default constructor!", this.getPath()); - } catch (Throwable var8) { - LOGGER.at(Level.SEVERE).withCause(var8).log("Failed to load plugin %s", this.getPath()); } - - return null; } @Nonnull 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..1398cd43 100644 --- a/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadPlugin.java +++ b/src/com/hypixel/hytale/server/core/plugin/pending/PendingLoadPlugin.java @@ -48,8 +48,8 @@ public abstract class PendingLoadPlugin { public abstract PendingLoadPlugin createSubPendingLoadPlugin(PluginManifest var1); - @Nullable - public abstract PluginBase load(); + @Nonnull + public abstract PluginBase load() throws Exception; @Nonnull public List createSubPendingLoadPlugins() { @@ -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/PrefabStore.java b/src/com/hypixel/hytale/server/core/prefab/PrefabStore.java index 1cb76f17..c73f9095 100644 --- a/src/com/hypixel/hytale/server/core/prefab/PrefabStore.java +++ b/src/com/hypixel/hytale/server/core/prefab/PrefabStore.java @@ -2,6 +2,7 @@ package com.hypixel.hytale.server.core.prefab; import com.hypixel.hytale.assetstore.AssetPack; import com.hypixel.hytale.common.plugin.PluginManifest; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.server.core.asset.AssetModule; import com.hypixel.hytale.server.core.prefab.config.SelectionPrefabSerializer; import com.hypixel.hytale.server.core.prefab.selection.standard.BlockSelection; @@ -34,9 +35,19 @@ public class PrefabStore { private PrefabStore() { } + @Nonnull + private static Path resolvePrefabKey(@Nonnull Path basePath, @Nonnull String key) { + Path resolved = PathUtil.resolvePathWithinDir(basePath, key); + if (resolved == null) { + throw new PrefabLoadException(PrefabLoadException.Type.NOT_FOUND); + } else { + return resolved; + } + } + @Nonnull public BlockSelection getServerPrefab(@Nonnull String key) { - return this.getPrefab(this.getServerPrefabsPath().resolve(key)); + return this.getPrefab(resolvePrefabKey(this.getServerPrefabsPath(), key)); } @Nonnull @@ -56,7 +67,7 @@ public class PrefabStore { @Nonnull public Map getServerPrefabDir(@Nonnull String key) { - return this.getPrefabDir(this.getServerPrefabsPath().resolve(key)); + return this.getPrefabDir(resolvePrefabKey(this.getServerPrefabsPath(), key)); } @Nonnull @@ -80,7 +91,7 @@ public class PrefabStore { } public void saveWorldGenPrefab(@Nonnull String key, @Nonnull BlockSelection prefab, boolean overwrite) { - this.savePrefab(this.getWorldGenPrefabsPath().resolve(key), prefab, overwrite); + this.savePrefab(resolvePrefabKey(this.getWorldGenPrefabsPath(), key), prefab, overwrite); } public void savePrefab(@Nonnull Path path, @Nonnull BlockSelection prefab, boolean overwrite) { @@ -112,11 +123,17 @@ public class PrefabStore { @Nonnull public Path getWorldGenPrefabsPath(@Nullable String name) { name = name == null ? "Default" : name; - return Universe.getWorldGenPath().resolve(name).resolve("Prefabs"); + Path worldGenPath = Universe.getWorldGenPath(); + Path resolved = PathUtil.resolvePathWithinDir(worldGenPath, name); + if (resolved == null) { + throw new IllegalArgumentException("Invalid world gen name: " + name); + } else { + return resolved.resolve("Prefabs"); + } } public void saveServerPrefab(@Nonnull String key, @Nonnull BlockSelection prefab, boolean overwrite) { - this.savePrefab(this.getServerPrefabsPath().resolve(key), prefab, overwrite); + this.savePrefab(resolvePrefabKey(this.getServerPrefabsPath(), key), prefab, overwrite); } @Nonnull @@ -147,8 +164,8 @@ public class PrefabStore { public BlockSelection getAssetPrefabFromAnyPack(@Nonnull String key) { for (AssetPack pack : AssetModule.get().getAssetPacks()) { Path prefabsPath = this.getAssetPrefabsPathForPack(pack); - Path prefabPath = prefabsPath.resolve(key); - if (Files.exists(prefabPath)) { + Path prefabPath = PathUtil.resolvePathWithinDir(prefabsPath, key); + if (prefabPath != null && Files.exists(prefabPath)) { return this.getPrefab(prefabPath); } } @@ -160,8 +177,8 @@ public class PrefabStore { public Path findAssetPrefabPath(@Nonnull String key) { for (AssetPack pack : AssetModule.get().getAssetPacks()) { Path prefabsPath = this.getAssetPrefabsPathForPack(pack); - Path prefabPath = prefabsPath.resolve(key); - if (Files.exists(prefabPath)) { + Path prefabPath = PathUtil.resolvePathWithinDir(prefabsPath, key); + if (prefabPath != null && Files.exists(prefabPath)) { return prefabPath; } } @@ -185,12 +202,12 @@ public class PrefabStore { @Nonnull public BlockSelection getAssetPrefab(@Nonnull String key) { - return this.getPrefab(this.getAssetPrefabsPath().resolve(key)); + return this.getPrefab(resolvePrefabKey(this.getAssetPrefabsPath(), key)); } @Nonnull public Map getAssetPrefabDir(@Nonnull String key) { - return this.getPrefabDir(this.getAssetPrefabsPath().resolve(key)); + return this.getPrefabDir(resolvePrefabKey(this.getAssetPrefabsPath(), key)); } public void saveAssetPrefab(@Nonnull String key, @Nonnull BlockSelection prefab) { @@ -198,7 +215,7 @@ public class PrefabStore { } public void saveAssetPrefab(@Nonnull String key, @Nonnull BlockSelection prefab, boolean overwrite) { - this.savePrefab(this.getAssetPrefabsPath().resolve(key), prefab, overwrite); + this.savePrefab(resolvePrefabKey(this.getAssetPrefabsPath(), key), prefab, overwrite); } @Nonnull @@ -208,12 +225,12 @@ public class PrefabStore { @Nonnull public BlockSelection getWorldGenPrefab(@Nonnull Path prefabsPath, @Nonnull String key) { - return this.getPrefab(prefabsPath.resolve(key)); + return this.getPrefab(resolvePrefabKey(prefabsPath, key)); } @Nonnull public Map getWorldGenPrefabDir(@Nonnull String key) { - return this.getPrefabDir(this.getWorldGenPrefabsPath().resolve(key)); + return this.getPrefabDir(resolvePrefabKey(this.getWorldGenPrefabsPath(), key)); } public void saveWorldGenPrefab(@Nonnull String key, @Nonnull BlockSelection prefab) { 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..26319311 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 @@ -1,11 +1,11 @@ package com.hypixel.hytale.server.core.prefab.selection.buffer; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.server.core.util.io.FileUtil; 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; @@ -35,8 +35,12 @@ public class PrefabLoader { resolvePrefabFolder(rootFolder, prefabName, pathConsumer); } else { Path prefabPath = rootFolder.resolve(prefabName.replace('.', File.separatorChar) + ".prefab.json"); + if (!PathUtil.isChildOf(rootFolder, prefabPath)) { + throw new IllegalArgumentException("Invalid prefab name: " + prefabName); + } + if (!Files.exists(prefabPath)) { - throw new NoSuchFileException(prefabPath.toString()); + return; } pathConsumer.accept(prefabPath); @@ -46,22 +50,26 @@ 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 (!PathUtil.isChildOf(rootFolder, directoryPath)) { + throw new IllegalArgumentException("Invalid prefab name: " + prefabName); + } else 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/receiver/IPacketReceiver.java b/src/com/hypixel/hytale/server/core/receiver/IPacketReceiver.java index 38171f17..7b10f9f4 100644 --- a/src/com/hypixel/hytale/server/core/receiver/IPacketReceiver.java +++ b/src/com/hypixel/hytale/server/core/receiver/IPacketReceiver.java @@ -1,10 +1,10 @@ package com.hypixel.hytale.server.core.receiver; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import javax.annotation.Nonnull; public interface IPacketReceiver { - void write(@Nonnull Packet var1); + void write(@Nonnull ToClientPacket var1); - void writeNoCache(@Nonnull Packet var1); + void writeNoCache(@Nonnull ToClientPacket var1); } diff --git a/src/com/hypixel/hytale/server/core/ui/browser/ServerFileBrowser.java b/src/com/hypixel/hytale/server/core/ui/browser/ServerFileBrowser.java index ad82b111..bb2dc132 100644 --- a/src/com/hypixel/hytale/server/core/ui/browser/ServerFileBrowser.java +++ b/src/com/hypixel/hytale/server/core/ui/browser/ServerFileBrowser.java @@ -208,8 +208,9 @@ public class ServerFileBrowser { return this.handleAssetPackNavigation(fileName); } else { if (this.config.enableDirectoryNav()) { - Path targetPath = this.root.resolve(this.currentDir.toString()).resolve(fileName); - if (Files.isDirectory(targetPath)) { + Path currentPath = this.root.resolve(this.currentDir.toString()); + Path targetPath = PathUtil.resolvePathWithinDir(currentPath, fileName); + if (targetPath != null && Files.isDirectory(targetPath) && PathUtil.isChildOf(this.root, targetPath)) { this.currentDir = PathUtil.relativize(this.root, targetPath); return true; } @@ -327,8 +328,8 @@ public class ServerFileBrowser { if (packx != null) { Path packSubPath = this.getAssetPackSubPath(packx); if (packSubPath != null) { - Path targetDir = subDir.isEmpty() ? packSubPath : packSubPath.resolve(subDir); - if (Files.isDirectory(targetDir)) { + Path targetDir = subDir.isEmpty() ? packSubPath : PathUtil.resolvePathWithinDir(packSubPath, subDir); + if (targetDir != null && Files.isDirectory(targetDir)) { try (DirectoryStream stream = Files.newDirectoryStream(targetDir)) { for (Path file : stream) { String fileName = file.getFileName().toString(); @@ -382,8 +383,8 @@ public class ServerFileBrowser { if (packx != null) { Path packSubPath = this.getAssetPackSubPath(packx); if (packSubPath != null) { - Path searchRoot = subDir.isEmpty() ? packSubPath : packSubPath.resolve(subDir); - if (Files.isDirectory(searchRoot)) { + Path searchRoot = subDir.isEmpty() ? packSubPath : PathUtil.resolvePathWithinDir(packSubPath, subDir); + if (searchRoot != null && Files.isDirectory(searchRoot)) { this.searchInAssetPackDirectory(searchRoot, packName, subDir, allResults); } } @@ -472,18 +473,24 @@ public class ServerFileBrowser { if (packSubPath == null) { return false; } else { - Path targetDir = subDir.isEmpty() ? packSubPath : packSubPath.resolve(subDir); - Path targetPath = targetDir.resolve(fileName); - if (Files.isDirectory(targetPath)) { - if (this.isTerminalDirectory(targetPath)) { - return false; - } else { - String newPath = subDir.isEmpty() ? packName + "/" + fileName : packName + "/" + subDir + "/" + fileName; - this.currentDir = Paths.get(newPath); - return true; - } - } else { + Path targetDir = subDir.isEmpty() ? packSubPath : PathUtil.resolvePathWithinDir(packSubPath, subDir); + if (targetDir == null) { return false; + } else { + Path targetPath = PathUtil.resolvePathWithinDir(targetDir, fileName); + if (targetPath == null) { + return false; + } else if (Files.isDirectory(targetPath)) { + if (this.isTerminalDirectory(targetPath)) { + return false; + } else { + String newPath = subDir.isEmpty() ? packName + "/" + fileName : packName + "/" + subDir + "/" + fileName; + this.currentDir = Paths.get(newPath); + return true; + } + } else { + return false; + } } } } @@ -535,7 +542,7 @@ public class ServerFileBrowser { if (packSubPath == null) { return null; } else { - return subPath.isEmpty() ? packSubPath : packSubPath.resolve(subPath); + return subPath.isEmpty() ? packSubPath : PathUtil.resolvePathWithinDir(packSubPath, subPath); } } } else { @@ -573,7 +580,12 @@ public class ServerFileBrowser { } public void setCurrentDir(@Nonnull Path currentDir) { - this.currentDir = currentDir; + Path resolved = this.root.resolve(currentDir.toString()); + if (!PathUtil.isChildOf(this.root, resolved)) { + throw new IllegalArgumentException("Invalid path"); + } else { + this.currentDir = currentDir; + } } @Nonnull @@ -594,7 +606,7 @@ public class ServerFileBrowser { public void navigateTo(@Nonnull Path relativePath) { Path targetPath = this.root.resolve(this.currentDir.toString()).resolve(relativePath.toString()); - if (targetPath.normalize().startsWith(this.root.normalize())) { + if (PathUtil.isChildOf(this.root, targetPath)) { if (Files.isDirectory(targetPath)) { this.currentDir = PathUtil.relativize(this.root, targetPath); } @@ -624,18 +636,6 @@ public class ServerFileBrowser { return this.config; } - @Nullable - public Path resolveSecure(@Nonnull String relativePath) { - Path resolved = this.root.resolve(relativePath); - return !resolved.normalize().startsWith(this.root.normalize()) ? null : resolved; - } - - @Nullable - public Path resolveFromCurrent(@Nonnull String fileName) { - Path resolved = this.root.resolve(this.currentDir.toString()).resolve(fileName); - return !resolved.normalize().startsWith(this.root.normalize()) ? null : resolved; - } - @Nullable private Path findConfigRoot(@Nonnull String pathStr) { for (FileBrowserConfig.RootEntry rootEntry : this.config.roots()) { diff --git a/src/com/hypixel/hytale/server/core/universe/Universe.java b/src/com/hypixel/hytale/server/core/universe/Universe.java index baef1b1a..64f0c8b9 100644 --- a/src/com/hypixel/hytale/server/core/universe/Universe.java +++ b/src/com/hypixel/hytale/server/core/universe/Universe.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.common.plugin.PluginIdentifier; import com.hypixel.hytale.common.plugin.PluginManifest; import com.hypixel.hytale.common.semver.SemverRange; import com.hypixel.hytale.common.util.CompletableFutureUtil; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.component.ComponentRegistryProxy; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; @@ -21,8 +22,10 @@ import com.hypixel.hytale.math.vector.Transform; import com.hypixel.hytale.metrics.MetricProvider; import com.hypixel.hytale.metrics.MetricResults; import com.hypixel.hytale.metrics.MetricsRegistry; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.NetworkChannel; import com.hypixel.hytale.protocol.PlayerSkin; +import com.hypixel.hytale.protocol.ToClientPacket; +import com.hypixel.hytale.protocol.io.netty.ProtocolUtil; import com.hypixel.hytale.protocol.packets.setup.ServerTags; import com.hypixel.hytale.server.core.Constants; import com.hypixel.hytale.server.core.HytaleServer; @@ -32,6 +35,7 @@ import com.hypixel.hytale.server.core.NameMatching; import com.hypixel.hytale.server.core.Options; import com.hypixel.hytale.server.core.auth.PlayerAuthentication; import com.hypixel.hytale.server.core.command.system.CommandRegistry; +import com.hypixel.hytale.server.core.config.BackupConfig; import com.hypixel.hytale.server.core.cosmetics.CosmeticsModule; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.entity.entities.Player; @@ -82,6 +86,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.provider.EmptyChunk import com.hypixel.hytale.server.core.universe.world.storage.provider.IChunkStorageProvider; import com.hypixel.hytale.server.core.universe.world.storage.provider.IndexedStorageChunkStorageProvider; import com.hypixel.hytale.server.core.universe.world.storage.provider.MigrationChunkStorageProvider; +import com.hypixel.hytale.server.core.universe.world.storage.provider.RocksDbChunkStorageProvider; import com.hypixel.hytale.server.core.universe.world.storage.resources.DefaultResourceStorageProvider; import com.hypixel.hytale.server.core.universe.world.storage.resources.DiskResourceStorageProvider; import com.hypixel.hytale.server.core.universe.world.storage.resources.EmptyResourceStorageProvider; @@ -91,6 +96,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; @@ -100,6 +106,9 @@ import com.hypixel.hytale.server.core.util.backup.BackupTask; import com.hypixel.hytale.server.core.util.io.FileUtil; import com.hypixel.hytale.sneakythrow.SneakyThrow; import io.netty.channel.Channel; +import io.netty.handler.codec.quic.QuicChannel; +import io.netty.handler.codec.quic.QuicStreamChannel; +import io.netty.handler.codec.quic.QuicStreamType; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.io.IOException; @@ -119,6 +128,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; @@ -141,6 +151,8 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv private ComponentType playerRefComponentType; @Nonnull private final Path path = Constants.UNIVERSE_PATH; + private final Path worldsPath = this.path.resolve("worlds"); + private final Path worldsDeletedPath = this.worldsPath.resolveSibling("worlds-deleted"); @Nonnull private final Map players = new ConcurrentHashMap<>(); @Nonnull @@ -151,8 +163,9 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv private final Map unmodifiableWorlds = Collections.unmodifiableMap(this.worlds); 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; @@ -164,20 +177,33 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv if (!Files.isDirectory(this.path) && !Options.getOptionSet().has(Options.BARE)) { try { Files.createDirectories(this.path); - } catch (IOException var3) { - throw new RuntimeException("Failed to create universe directory", var3); + } catch (IOException var4) { + throw new RuntimeException("Failed to create universe directory", var4); } } - if (Options.getOptionSet().has(Options.BACKUP)) { - int frequencyMinutes = Math.max(Options.getOptionSet().valueOf(Options.BACKUP_FREQUENCY_MINUTES), 1); + BackupConfig backupConfig = HytaleServer.get().getConfig().getBackupConfig(); + if (backupConfig.isConfigured()) { + int frequencyMinutes = backupConfig.getFrequencyMinutes(); 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); } @@ -185,18 +211,21 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv @Nonnull public CompletableFuture runBackup() { - return CompletableFuture.allOf(this.worlds.values().stream().map(world -> CompletableFuture.supplyAsync(() -> { - Store componentStore = world.getChunkStore().getStore(); - ChunkSavingSystems.Data data = componentStore.getResource(ChunkStore.SAVE_RESOURCE); - data.isSaving = false; - return data; - }, world).thenCompose(ChunkSavingSystems.Data::waitForSavingChunks)).toArray(CompletableFuture[]::new)) - .thenCompose(aVoid -> BackupTask.start(this.path, Options.getOptionSet().valueOf(Options.BACKUP_DIRECTORY))) - .thenCompose(success -> CompletableFuture.allOf(this.worlds.values().stream().map(world -> CompletableFuture.runAsync(() -> { - Store componentStore = world.getChunkStore().getStore(); - ChunkSavingSystems.Data data = componentStore.getResource(ChunkStore.SAVE_RESOURCE); - data.isSaving = true; - }, world)).toArray(CompletableFuture[]::new)).thenApply(aVoid -> success)); + Path backupDir = HytaleServer.get().getConfig().getBackupConfig().getDirectory(); + return backupDir == null + ? CompletableFuture.failedFuture(new IllegalStateException("Backup directory not configured")) + : CompletableFuture.allOf(this.worlds.values().stream().map(world -> CompletableFuture.supplyAsync(() -> { + Store componentStore = world.getChunkStore().getStore(); + ChunkSavingSystems.Data data = componentStore.getResource(ChunkStore.SAVE_RESOURCE); + data.isSaving = false; + return data; + }, world).thenCompose(ChunkSavingSystems.Data::waitForSavingChunks)).toArray(CompletableFuture[]::new)) + .thenCompose(aVoid -> BackupTask.start(this.path, backupDir)) + .thenCompose(success -> CompletableFuture.allOf(this.worlds.values().stream().map(world -> CompletableFuture.runAsync(() -> { + Store componentStore = world.getChunkStore().getStore(); + ChunkSavingSystems.Data data = componentStore.getResource(ChunkStore.SAVE_RESOURCE); + data.isSaving = true; + }, world)).toArray(CompletableFuture[]::new)).thenApply(aVoid -> success)); } @Override @@ -218,14 +247,12 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv IChunkStorageProvider.CODEC.register(Priority.DEFAULT, "Hytale", DefaultChunkStorageProvider.class, DefaultChunkStorageProvider.CODEC); IChunkStorageProvider.CODEC.register("Migration", MigrationChunkStorageProvider.class, MigrationChunkStorageProvider.CODEC); IChunkStorageProvider.CODEC.register("IndexedStorage", IndexedStorageChunkStorageProvider.class, IndexedStorageChunkStorageProvider.CODEC); + IChunkStorageProvider.CODEC.register("RocksDb", RocksDbChunkStorageProvider.class, RocksDbChunkStorageProvider.CODEC); IChunkStorageProvider.CODEC.register("Empty", EmptyChunkStorageProvider.class, EmptyChunkStorageProvider.CODEC); IResourceStorageProvider.CODEC.register(Priority.DEFAULT, "Hytale", DefaultResourceStorageProvider.class, DefaultResourceStorageProvider.CODEC); IResourceStorageProvider.CODEC.register("Disk", DiskResourceStorageProvider.class, DiskResourceStorageProvider.CODEC); IResourceStorageProvider.CODEC.register("Empty", EmptyResourceStorageProvider.class, EmptyResourceStorageProvider.CODEC); - this.indexedStorageCacheResourceType = chunkStoreRegistry.registerResource( - IndexedStorageChunkStorageProvider.IndexedStorageCache.class, IndexedStorageChunkStorageProvider.IndexedStorageCache::new - ); - chunkStoreRegistry.registerSystem(new IndexedStorageChunkStorageProvider.IndexedStorageCacheSetupSystem()); + this.worldMarkersResourceType = chunkStoreRegistry.registerResource(WorldMarkersResource.class, "SharedUserMapMarkers", WorldMarkersResource.CODEC); chunkStoreRegistry.registerSystem(new WorldPregenerateSystem()); entityStoreRegistry.registerSystem(new WorldConfigSaveSystem()); this.playerRefComponentType = entityStoreRegistry.registerComponent(PlayerRef.class, () -> { @@ -277,8 +304,8 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv LEGACY_BLOCK_ID_MAP = Collections.unmodifiableMap(map); } - } catch (IOException var14) { - this.getLogger().at(Level.SEVERE).withCause(var14).log("Failed to delete blockIdMap.json"); + } catch (IOException var15) { + this.getLogger().at(Level.SEVERE).withCause(var15).log("Failed to delete blockIdMap.json"); } if (Options.getOptionSet().has(Options.BARE)) { @@ -288,16 +315,23 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv ObjectArrayList> loadingWorlds = new ObjectArrayList<>(); try { - Path worldsPath = this.path.resolve("worlds"); - Files.createDirectories(worldsPath); + if (Files.exists(this.worldsDeletedPath)) { + FileUtil.deleteDirectory(this.worldsDeletedPath); + } + } catch (Throwable var14) { + throw new RuntimeException("Failed to complete deletion of " + this.worldsDeletedPath.toAbsolutePath(), var14); + } - try (DirectoryStream stream = Files.newDirectoryStream(worldsPath)) { + try { + Files.createDirectories(this.worldsPath); + + try (DirectoryStream stream = Files.newDirectoryStream(this.worldsPath)) { for (Path file : stream) { if (HytaleServer.get().isShuttingDown()) { return; } - if (!file.equals(worldsPath) && Files.isDirectory(file)) { + if (!file.equals(this.worldsPath) && Files.isDirectory(file)) { String name = file.getFileName().toString(); if (this.getWorld(name) == null) { loadingWorlds.add(this.loadWorldFromStart(file, name).exceptionally(throwable -> { @@ -360,12 +394,12 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv return this.universeReady; } - public ResourceType getIndexedStorageCacheResourceType() { - return this.indexedStorageCacheResourceType; + public ResourceType getWorldMarkersResourceType() { + return this.worldMarkersResourceType; } public boolean isWorldLoadable(@Nonnull String name) { - Path savePath = this.path.resolve("worlds").resolve(name); + Path savePath = this.validateWorldPath(name); return Files.isDirectory(savePath) && (Files.exists(savePath.resolve("config.bson")) || Files.exists(savePath.resolve("config.json"))); } @@ -384,7 +418,7 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv } else if (this.isWorldLoadable(name)) { throw new IllegalArgumentException("World " + name + " already exists on disk!"); } else { - Path savePath = this.path.resolve("worlds").resolve(name); + Path savePath = this.validateWorldPath(name); return this.worldConfigProvider.load(savePath, name).thenCompose(worldConfig -> { if (generatorType != null && !"default".equals(generatorType)) { BuilderCodec providerCodec = IWorldGenProvider.CODEC.getCodecFor(generatorType); @@ -398,12 +432,12 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv } if (chunkStorageType != null && !"default".equals(chunkStorageType)) { - BuilderCodec providerCodec = IChunkStorageProvider.CODEC.getCodecFor(chunkStorageType); + BuilderCodec> providerCodec = IChunkStorageProvider.CODEC.getCodecFor(chunkStorageType); if (providerCodec == null) { throw new IllegalArgumentException("Unknown chunkStorageType '" + chunkStorageType + "'"); } - IChunkStorageProvider provider = providerCodec.getDefaultValue(); + IChunkStorageProvider provider = (IChunkStorageProvider)providerCodec.getDefaultValue(); worldConfig.setChunkStorageProvider(provider); worldConfig.markChanged(); } @@ -413,6 +447,15 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv } } + public Path validateWorldPath(@Nonnull String name) { + Path savePath = PathUtil.resolvePathWithinDir(this.worldsPath, name); + if (savePath == null) { + throw new IllegalArgumentException("World " + name + " contains invalid characters!"); + } else { + return savePath; + } + } + @Nonnull @CheckReturnValue public CompletableFuture makeWorld(@Nonnull String name, @Nonnull Path savePath, @Nonnull WorldConfig worldConfig) { @@ -422,66 +465,70 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv @Nonnull @CheckReturnValue public CompletableFuture makeWorld(@Nonnull String name, @Nonnull Path savePath, @Nonnull WorldConfig worldConfig, boolean start) { - Map map = worldConfig.getRequiredPlugins(); - if (map != null) { - PluginManager pluginManager = PluginManager.get(); + if (!PathUtil.isChildOf(this.worldsPath, savePath) && !PathUtil.isInTrustedRoot(savePath)) { + throw new IllegalArgumentException("Invalid path"); + } else { + Map map = worldConfig.getRequiredPlugins(); + if (map != null) { + PluginManager pluginManager = PluginManager.get(); - for (Entry entry : map.entrySet()) { - if (!pluginManager.hasPlugin(entry.getKey(), entry.getValue())) { - this.getLogger().at(Level.SEVERE).log("Failed to load world! Missing plugin: %s, Version: %s", entry.getKey(), entry.getValue()); - throw new IllegalStateException("Missing plugin"); + for (Entry entry : map.entrySet()) { + if (!pluginManager.hasPlugin(entry.getKey(), entry.getValue())) { + this.getLogger().at(Level.SEVERE).log("Failed to load world! Missing plugin: %s, Version: %s", entry.getKey(), entry.getValue()); + throw new IllegalStateException("Missing plugin"); + } } } - } - if (this.worlds.containsKey(name)) { - throw new IllegalArgumentException("World " + name + " already exists!"); - } else { - return CompletableFuture.supplyAsync( - SneakyThrow.sneakySupplier( - () -> { - World world = new World(name, savePath, worldConfig); - AddWorldEvent event = HytaleServer.get().getEventBus().dispatchFor(AddWorldEvent.class, name).dispatch(new AddWorldEvent(world)); - if (!event.isCancelled() && !HytaleServer.get().isShuttingDown()) { - World oldWorldByName = this.worlds.putIfAbsent(name.toLowerCase(), world); - if (oldWorldByName != null) { - throw new ConcurrentModificationException( - "World with name " + name + " already exists but didn't before! Looks like you have a race condition." - ); - } else { - World oldWorldByUuid = this.worldsByUuid.putIfAbsent(worldConfig.getUuid(), world); - if (oldWorldByUuid != null) { + if (this.worlds.containsKey(name)) { + throw new IllegalArgumentException("World " + name + " already exists!"); + } else { + return CompletableFuture.supplyAsync( + SneakyThrow.sneakySupplier( + () -> { + World world = new World(name, savePath, worldConfig); + AddWorldEvent event = HytaleServer.get().getEventBus().dispatchFor(AddWorldEvent.class, name).dispatch(new AddWorldEvent(world)); + if (!event.isCancelled() && !HytaleServer.get().isShuttingDown()) { + World oldWorldByName = this.worlds.putIfAbsent(name.toLowerCase(), world); + if (oldWorldByName != null) { throw new ConcurrentModificationException( - "World with UUID " + worldConfig.getUuid() + " already exists but didn't before! Looks like you have a race condition." + "World with name " + name + " already exists but didn't before! Looks like you have a race condition." ); } else { - return world; + World oldWorldByUuid = this.worldsByUuid.putIfAbsent(worldConfig.getUuid(), world); + if (oldWorldByUuid != null) { + throw new ConcurrentModificationException( + "World with UUID " + worldConfig.getUuid() + " already exists but didn't before! Looks like you have a race condition." + ); + } else { + return world; + } } + } else { + throw new WorldLoadCancelledException(); } - } else { - throw new WorldLoadCancelledException(); } - } + ) ) - ) - .thenCompose(World::init) - .thenCompose( - world -> !Options.getOptionSet().has(Options.MIGRATIONS) && start - ? world.start().thenApply(v -> world) - : CompletableFuture.completedFuture(world) - ) - .whenComplete((world, throwable) -> { - if (throwable != null) { - String nameLower = name.toLowerCase(); - if (this.worlds.containsKey(nameLower)) { - try { - this.removeWorldExceptionally(name); - } catch (Exception var6x) { - this.getLogger().at(Level.WARNING).withCause(var6x).log("Failed to clean up world '%s' after init failure", name); + .thenCompose(World::init) + .thenCompose( + world -> !Options.getOptionSet().has(Options.MIGRATIONS) && start + ? world.start().thenApply(v -> world) + : CompletableFuture.completedFuture(world) + ) + .whenComplete((world, throwable) -> { + if (throwable != null) { + String nameLower = name.toLowerCase(); + if (this.worlds.containsKey(nameLower)) { + try { + this.removeWorldExceptionally(name, Map.of()); + } catch (Exception var6x) { + this.getLogger().at(Level.WARNING).withCause(var6x).log("Failed to clean up world '%s' after init failure", name); + } } } - } - }); + }); + } } } @@ -504,7 +551,7 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv if (this.worlds.containsKey(name)) { throw new IllegalArgumentException("World " + name + " already loaded!"); } else { - Path savePath = this.path.resolve("worlds").resolve(name); + Path savePath = this.validateWorldPath(name); if (!Files.isDirectory(savePath)) { throw new IllegalArgumentException("World " + name + " does not exist!"); } else { @@ -551,7 +598,11 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv this.worlds.remove(nameLower); this.worldsByUuid.remove(world.getWorldConfig().getUuid()); if (world.isAlive()) { - world.stopIndividualWorld(); + if (world.isInThread()) { + world.stopIndividualWorld(); + } else { + CompletableFuture.runAsync(world::stopIndividualWorld).join(); + } } world.validateDeleteOnRemove(); @@ -560,7 +611,7 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv } } - public void removeWorldExceptionally(@Nonnull String name) { + public void removeWorldExceptionally(@Nonnull String name, Map players) { Objects.requireNonNull(name, "Name can't be null!"); this.getLogger().at(Level.INFO).log("Removing world exceptionally: %s", name); String nameLower = name.toLowerCase(); @@ -575,7 +626,11 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv this.worlds.remove(nameLower); this.worldsByUuid.remove(world.getWorldConfig().getUuid()); if (world.isAlive()) { - world.stopIndividualWorld(); + if (world.isInThread()) { + world.stopIndividualWorld(players); + } else { + CompletableFuture.runAsync(() -> world.stopIndividualWorld(players)).join(); + } } world.validateDeleteOnRemove(); @@ -587,6 +642,14 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv return this.path; } + public Path getWorldsPath() { + return this.worldsPath; + } + + public Path getWorldsDeletedPath() { + return this.worldsDeletedPath; + } + @Nonnull public Map getWorlds() { return this.unmodifiableWorlds; @@ -640,8 +703,29 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv GamePacketHandler playerConnection = new GamePacketHandler(channel, protocolVersion, auth); playerConnection.setQueuePackets(false); this.getLogger().at(Level.INFO).log("Adding player '%s (%s)", username, uuid); - return this.playerStorage - .load(uuid) + CompletableFuture setupFuture; + if (channel instanceof QuicStreamChannel streamChannel) { + QuicChannel conn = streamChannel.parent(); + conn.attr(ProtocolUtil.STREAM_CHANNEL_KEY).set(NetworkChannel.Default); + streamChannel.updatePriority(PacketHandler.DEFAULT_STREAM_PRIORITIES.get(NetworkChannel.Default)); + CompletableFuture chunkFuture = NettyUtil.createStream( + conn, QuicStreamType.UNIDIRECTIONAL, NetworkChannel.Chunks, PacketHandler.DEFAULT_STREAM_PRIORITIES.get(NetworkChannel.Chunks), playerConnection + ); + CompletableFuture worldMapFuture = NettyUtil.createStream( + conn, + QuicStreamType.UNIDIRECTIONAL, + NetworkChannel.WorldMap, + PacketHandler.DEFAULT_STREAM_PRIORITIES.get(NetworkChannel.WorldMap), + playerConnection + ); + setupFuture = CompletableFuture.allOf(chunkFuture, worldMapFuture); + } else { + playerConnection.setChannel(NetworkChannel.WorldMap, channel); + playerConnection.setChannel(NetworkChannel.Chunks, channel); + setupFuture = CompletableFuture.completedFuture(null); + } + + return setupFuture., Holder>thenCombine(this.playerStorage.load(uuid), (setupResult, playerData) -> playerData) .exceptionally(throwable -> { throw new RuntimeException("Exception when adding player to universe:", throwable); }) @@ -885,19 +969,19 @@ public class Universe extends JavaPlugin implements IMessageReceiver, MetricProv } } - public void broadcastPacket(@Nonnull Packet packet) { + public void broadcastPacket(@Nonnull ToClientPacket packet) { for (PlayerRef player : this.players.values()) { player.getPacketHandler().write(packet); } } - public void broadcastPacketNoCache(@Nonnull Packet packet) { + public void broadcastPacketNoCache(@Nonnull ToClientPacket packet) { for (PlayerRef player : this.players.values()) { player.getPacketHandler().writeNoCache(packet); } } - public void broadcastPacket(@Nonnull Packet... packets) { + public void broadcastPacket(@Nonnull ToClientPacket... packets) { for (PlayerRef player : this.players.values()) { player.getPacketHandler().write(packets); } diff --git a/src/com/hypixel/hytale/server/core/universe/datastore/DiskDataStore.java b/src/com/hypixel/hytale/server/core/universe/datastore/DiskDataStore.java index e44819ea..4cf60865 100644 --- a/src/com/hypixel/hytale/server/core/universe/datastore/DiskDataStore.java +++ b/src/com/hypixel/hytale/server/core/universe/datastore/DiskDataStore.java @@ -3,6 +3,7 @@ package com.hypixel.hytale.server.core.universe.datastore; import com.hypixel.hytale.codec.ExtraInfo; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.util.RawJsonReader; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.util.BsonUtil; @@ -33,20 +34,26 @@ public class DiskDataStore implements DataStore { public DiskDataStore(@Nonnull String path, BuilderCodec codec) { this.logger = HytaleLogger.get("DataStore|" + path); - this.path = Universe.get().getPath().resolve(path); - this.codec = codec; - if (Files.isDirectory(this.path)) { - try (DirectoryStream paths = Files.newDirectoryStream(this.path, "*.bson")) { - for (Path oldPath : paths) { - Path newPath = getPathFromId(this.path, getIdFromPath(oldPath)); + Path universePath = Universe.get().getPath(); + Path resolved = PathUtil.resolvePathWithinDir(universePath, path); + if (resolved == null) { + throw new IllegalStateException("Data store path must be within universe directory: " + path); + } else { + this.path = resolved; + this.codec = codec; + if (Files.isDirectory(this.path)) { + try (DirectoryStream paths = Files.newDirectoryStream(this.path, "*.bson")) { + for (Path oldPath : paths) { + Path newPath = getPathFromId(this.path, getIdFromPath(oldPath)); - try { - Files.move(oldPath, newPath); - } catch (IOException var9) { + try { + Files.move(oldPath, newPath); + } catch (IOException var11) { + } } + } catch (IOException var13) { + this.logger.at(Level.SEVERE).withCause(var13).log("Failed to migrate files form .bson to .json!"); } - } catch (IOException var11) { - this.logger.at(Level.SEVERE).withCause(var11).log("Failed to migrate files form .bson to .json!"); } } } @@ -126,12 +133,20 @@ public class DiskDataStore implements DataStore { @Nonnull protected static Path getPathFromId(@Nonnull Path path, String id) { - return path.resolve(id + ".json"); + if (!PathUtil.isValidName(id)) { + throw new IllegalArgumentException("Invalid ID: " + id); + } else { + return path.resolve(id + ".json"); + } } @Nonnull protected static Path getBackupPathFromId(@Nonnull Path path, String id) { - return path.resolve(id + ".json.bak"); + if (!PathUtil.isValidName(id)) { + throw new IllegalArgumentException("Invalid ID: " + id); + } else { + return path.resolve(id + ".json.bak"); + } } @Nonnull diff --git a/src/com/hypixel/hytale/server/core/universe/playerdata/DiskPlayerStorageProvider.java b/src/com/hypixel/hytale/server/core/universe/playerdata/DiskPlayerStorageProvider.java index 391df204..fe4e3fbb 100644 --- a/src/com/hypixel/hytale/server/core/universe/playerdata/DiskPlayerStorageProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/playerdata/DiskPlayerStorageProvider.java @@ -24,7 +24,7 @@ import org.bson.BsonDocument; public class DiskPlayerStorageProvider implements PlayerStorageProvider { public static final String ID = "Disk"; public static final BuilderCodec CODEC = BuilderCodec.builder(DiskPlayerStorageProvider.class, DiskPlayerStorageProvider::new) - .append(new KeyedCodec<>("Path", Codec.STRING), (o, s) -> o.path = PathUtil.get(s), o -> o.path.toString()) + .append(new KeyedCodec<>("Path", Codec.STRING), (o, s) -> o.path = Path.of(s), o -> o.path.toString()) .add() .build(); @Nonnull @@ -38,7 +38,11 @@ public class DiskPlayerStorageProvider implements PlayerStorageProvider { @Nonnull @Override public PlayerStorage getPlayerStorage() { - return new DiskPlayerStorageProvider.DiskPlayerStorage(this.path); + if (!PathUtil.isInTrustedRoot(this.path)) { + throw new IllegalStateException("Player storage path must be within a trusted directory: " + this.path); + } else { + return new DiskPlayerStorageProvider.DiskPlayerStorage(this.path); + } } @Nonnull diff --git a/src/com/hypixel/hytale/server/core/universe/world/PlayerUtil.java b/src/com/hypixel/hytale/server/core/universe/world/PlayerUtil.java index ede7be56..f0afac45 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/PlayerUtil.java +++ b/src/com/hypixel/hytale/server/core/universe/world/PlayerUtil.java @@ -5,7 +5,7 @@ import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.function.consumer.TriConsumer; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.asset.type.model.config.Model; import com.hypixel.hytale.server.core.cosmetics.CosmeticsModule; @@ -78,7 +78,7 @@ public class PlayerUtil { } } - public static void broadcastPacketToPlayers(@Nonnull ComponentAccessor componentAccessor, @Nonnull Packet packet) { + public static void broadcastPacketToPlayers(@Nonnull ComponentAccessor componentAccessor, @Nonnull ToClientPacket packet) { World world = componentAccessor.getExternalData().getWorld(); for (PlayerRef targetPlayerRef : world.getPlayerRefs()) { @@ -86,7 +86,7 @@ public class PlayerUtil { } } - public static void broadcastPacketToPlayersNoCache(@Nonnull ComponentAccessor componentAccessor, @Nonnull Packet packet) { + public static void broadcastPacketToPlayersNoCache(@Nonnull ComponentAccessor componentAccessor, @Nonnull ToClientPacket packet) { World world = componentAccessor.getExternalData().getWorld(); for (PlayerRef targetPlayerRef : world.getPlayerRefs()) { @@ -94,7 +94,7 @@ public class PlayerUtil { } } - public static void broadcastPacketToPlayers(@Nonnull ComponentAccessor componentAccessor, @Nonnull Packet... packets) { + public static void broadcastPacketToPlayers(@Nonnull ComponentAccessor componentAccessor, @Nonnull ToClientPacket... packets) { World world = componentAccessor.getExternalData().getWorld(); for (PlayerRef targetPlayerRef : world.getPlayerRefs()) { diff --git a/src/com/hypixel/hytale/server/core/universe/world/SoundUtil.java b/src/com/hypixel/hytale/server/core/universe/world/SoundUtil.java index c4d5b640..f9b52382 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/SoundUtil.java +++ b/src/com/hypixel/hytale/server/core/universe/world/SoundUtil.java @@ -2,13 +2,17 @@ package com.hypixel.hytale.server.core.universe.world; import com.hypixel.hytale.component.ComponentAccessor; import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.spatial.SpatialResource; import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.protocol.ItemSoundEvent; import com.hypixel.hytale.protocol.Position; import com.hypixel.hytale.protocol.SoundCategory; import com.hypixel.hytale.protocol.packets.world.PlaySoundEvent2D; import com.hypixel.hytale.protocol.packets.world.PlaySoundEvent3D; import com.hypixel.hytale.protocol.packets.world.PlaySoundEventEntity; +import com.hypixel.hytale.server.core.asset.type.item.config.Item; +import com.hypixel.hytale.server.core.asset.type.itemsound.config.ItemSoundSet; import com.hypixel.hytale.server.core.asset.type.soundevent.config.SoundEvent; import com.hypixel.hytale.server.core.entity.Entity; import com.hypixel.hytale.server.core.entity.EntityUtils; @@ -22,6 +26,21 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class SoundUtil { + public static void playItemSoundEvent( + @Nonnull Ref ref, @Nonnull Store store, @Nonnull Item item, @Nonnull ItemSoundEvent itemSoundEvent + ) { + ItemSoundSet soundSet = ItemSoundSet.getAssetMap().getAsset(item.getItemSoundSetIndex()); + if (soundSet != null) { + String soundEventId = soundSet.getSoundEventIds().get(itemSoundEvent); + if (soundEventId != null) { + int soundEventIndex = SoundEvent.getAssetMap().getIndex(soundEventId); + if (soundEventIndex != 0) { + playSoundEvent2d(ref, soundEventIndex, SoundCategory.UI, store); + } + } + } + } + public static void playSoundEventEntity(int soundEventIndex, int networkId, @Nonnull ComponentAccessor componentAccessor) { playSoundEventEntity(soundEventIndex, networkId, 1.0F, 1.0F, componentAccessor); } diff --git a/src/com/hypixel/hytale/server/core/universe/world/World.java b/src/com/hypixel/hytale/server/core/universe/world/World.java index ce02880b..c4ee429d 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/World.java +++ b/src/com/hypixel/hytale/server/core/universe/world/World.java @@ -83,7 +83,9 @@ import com.hypixel.hytale.server.core.util.io.FileUtil; import com.hypixel.hytale.server.core.util.thread.TickingThread; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.awt.Color; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -98,6 +100,7 @@ import java.util.Random; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; @@ -252,21 +255,55 @@ public class World extends TickingThread implements Executor, ExecutorMetricsReg } public void stopIndividualWorld() { + this.stopIndividualWorld(this.players); + } + + public void stopIndividualWorld(Map players) { this.logger.at(Level.INFO).log("Removing individual world: %s", this.name); World defaultWorld = Universe.get().getDefaultWorld(); - if (defaultWorld != null) { - this.drainPlayersTo(defaultWorld).join(); + if (defaultWorld != null && !defaultWorld.equals(this)) { + Message message; + if (this.getFailureException() == null) { + message = Message.translation("server.universe.worldRemoved"); + } else if (this.getPossibleFailureCause() == null) { + message = Message.translation("server.universe.worldCrash.unknown"); + } else { + message = Message.translation("server.universe.worldCrash.mod").param("mod", this.getPossibleFailureCause().toString()); + } + + message.color(Color.RED); + + for (PlayerRef playerRef : players.values()) { + playerRef.sendMessage(message); + } + + if (this.isInThread()) { + this.drainPlayersTo(defaultWorld, players.values()).join(); + } else { + CompletableFuture.>supplyAsync(() -> this.drainPlayersTo(defaultWorld, players.values()), this) + .thenCompose(v -> (CompletionStage)v) + .join(); + } } else { - for (PlayerRef playerRef : this.players.values()) { - playerRef.getPacketHandler().disconnect("The world you were in was shutdown and there was no default world to move you to!"); + String messagex; + if (this.getFailureException() == null) { + messagex = "The world you were on was removed"; + } else if (this.getPossibleFailureCause() == null) { + messagex = "The world you were on has crashed"; + } else { + messagex = "The world you were on has crashed (possibly caused by " + this.getPossibleFailureCause() + ")"; + } + + for (PlayerRef playerRef : players.values()) { + playerRef.getPacketHandler().disconnect(messagex); } } if (this.alive.getAndSet(false)) { try { super.stop(); - } catch (Throwable var4) { - this.logger.at(Level.SEVERE).withCause(var4).log("Exception while shutting down world:"); + } catch (Throwable var6) { + this.logger.at(Level.SEVERE).withCause(var6).log("Exception while shutting down world:"); } } } @@ -274,13 +311,23 @@ public class World extends TickingThread implements Executor, ExecutorMetricsReg public void validateDeleteOnRemove() { if (this.worldConfig.isDeleteOnRemove()) { try { - FileUtil.deleteDirectory(this.getSavePath()); + this.deleteWorldFromDisk(); } catch (Throwable var2) { this.logger.at(Level.SEVERE).withCause(var2).log("Exception while deleting world on remove:"); } } } + private void deleteWorldFromDisk() throws IOException { + Path originDir = this.getSavePath(); + Path filename = originDir.getFileName(); + String noCollisionsName = filename + "_del" + UUID.randomUUID().toString().substring(0, 8); + Path deletionDir = Universe.get().getWorldsDeletedPath().resolve(noCollisionsName); + Files.createDirectories(deletionDir.getParent()); + FileUtil.atomicMove(originDir, deletionDir); + FileUtil.deleteDirectory(deletionDir); + } + @Override protected boolean isIdle() { return this.players.isEmpty(); @@ -332,6 +379,7 @@ public class World extends TickingThread implements Executor, ExecutorMetricsReg this.chunkLighting.stop(); this.worldMapManager.stop(); this.logger.at(Level.INFO).log("Removing players..."); + Object2ObjectOpenHashMap currentPlayers = new Object2ObjectOpenHashMap<>(this.players); for (PlayerRef playerRef : this.playerRefs) { if (playerRef.getReference() != null) { @@ -350,6 +398,7 @@ public class World extends TickingThread implements Executor, ExecutorMetricsReg this.consumeTaskQueue(); this.entityStore.shutdown(); this.consumeTaskQueue(); + this.eventRegistry.shutdownAndCleanup(true); } finally { this.logger.at(Level.INFO).log("Saving Config..."); if (this.worldConfig.isSavingConfig()) { @@ -359,7 +408,8 @@ public class World extends TickingThread implements Executor, ExecutorMetricsReg this.acceptingTasks.set(false); if (this.alive.getAndSet(false)) { - Universe.get().removeWorldExceptionally(this.name); + this.stopIndividualWorld(currentPlayers); + Universe.get().removeWorldExceptionally(this.name, currentPlayers); } HytaleServer.get().reportSingleplayerStatus("Closing world '" + this.name + "'"); @@ -909,7 +959,7 @@ public class World extends TickingThread implements Executor, ExecutorMetricsReg LegacyEntityTrackerSystems.clear(playerComponent, holder); ChunkTracker chunkTrackerComponent = holder.getComponent(ChunkTracker.getComponentType()); if (chunkTrackerComponent != null) { - chunkTrackerComponent.clear(); + chunkTrackerComponent.unloadAll(playerRefComponent); } } @@ -922,25 +972,19 @@ public class World extends TickingThread implements Executor, ExecutorMetricsReg } @Nonnull - public CompletableFuture drainPlayersTo(@Nonnull World fallbackTargetWorld) { - return CompletableFuture.completedFuture((Void)null) - .thenComposeAsync( - aVoid -> { - ObjectArrayList> futures = new ObjectArrayList<>(); + public CompletableFuture drainPlayersTo(@Nonnull World fallbackTargetWorld, Collection players) { + ObjectArrayList> futures = new ObjectArrayList<>(); - for (PlayerRef playerRef : this.playerRefs) { - Holder holder = playerRef.removeFromStore(); - DrainPlayerFromWorldEvent event = HytaleServer.get() - .getEventBus() - .dispatchFor(DrainPlayerFromWorldEvent.class, this.name) - .dispatch(new DrainPlayerFromWorldEvent(holder, fallbackTargetWorld, null)); - futures.add(event.getWorld().addPlayer(playerRef, event.getTransform())); - } + for (PlayerRef playerRef : players) { + Holder holder = playerRef.getReference() != null ? playerRef.removeFromStore() : playerRef.getHolder(); + DrainPlayerFromWorldEvent event = HytaleServer.get() + .getEventBus() + .dispatchFor(DrainPlayerFromWorldEvent.class, this.name) + .dispatch(new DrainPlayerFromWorldEvent(holder, fallbackTargetWorld, null)); + futures.add(event.getWorld().addPlayer(playerRef, event.getTransform())); + } - return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)); - }, - this - ); + return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)); } @Nonnull diff --git a/src/com/hypixel/hytale/server/core/universe/world/WorldConfig.java b/src/com/hypixel/hytale/server/core/universe/world/WorldConfig.java index 4df8241e..7977d7c4 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/WorldConfig.java +++ b/src/com/hypixel/hytale/server/core/universe/world/WorldConfig.java @@ -82,7 +82,7 @@ public class WorldConfig { .add() .append(new KeyedCodec<>("WorldMap", IWorldMapProvider.CODEC), (o, i) -> o.worldMapProvider = i, o -> o.worldMapProvider) .add() - .append( + .>append( new KeyedCodec<>("ChunkStorage", IChunkStorageProvider.CODEC), (o, i) -> o.chunkStorageProvider = i, o -> o.chunkStorageProvider ) .documentation("Sets the storage system that will be used by the world to store chunks.") @@ -229,7 +229,7 @@ public class WorldConfig { private ISpawnProvider spawnProvider = null; private IWorldGenProvider worldGenProvider = IWorldGenProvider.CODEC.getDefault(); private IWorldMapProvider worldMapProvider = IWorldMapProvider.CODEC.getDefault(); - private IChunkStorageProvider chunkStorageProvider = IChunkStorageProvider.CODEC.getDefault(); + private IChunkStorageProvider chunkStorageProvider = IChunkStorageProvider.CODEC.getDefault(); @Nonnull private WorldConfig.ChunkConfig chunkConfig = new WorldConfig.ChunkConfig(); private boolean isTicking = true; @@ -356,11 +356,11 @@ public class WorldConfig { this.worldMapProvider = worldMapProvider; } - public IChunkStorageProvider getChunkStorageProvider() { + public IChunkStorageProvider getChunkStorageProvider() { return this.chunkStorageProvider; } - public void setChunkStorageProvider(IChunkStorageProvider chunkStorageProvider) { + public void setChunkStorageProvider(IChunkStorageProvider chunkStorageProvider) { this.chunkStorageProvider = chunkStorageProvider; } 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..0a70bb54 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,8 @@ 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.NetworkChannel; import com.hypixel.hytale.protocol.SoundCategory; import com.hypixel.hytale.protocol.packets.worldmap.ClearWorldMap; import com.hypixel.hytale.protocol.packets.worldmap.MapChunk; @@ -21,6 +23,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 +75,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; @@ -89,7 +94,7 @@ public class WorldMapTracker implements Tickable { } World world = this.player.getWorld(); - if (world != null) { + if (world != null && this.player.getPlayerConnection().getChannel(NetworkChannel.WorldMap).isWritable()) { if (this.transformComponent == null) { this.transformComponent = this.player.getTransformComponent(); if (this.transformComponent == null) { @@ -483,8 +488,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 +557,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/WorldNotificationHandler.java b/src/com/hypixel/hytale/server/core/universe/world/WorldNotificationHandler.java index 7977da13..9897f8ff 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/WorldNotificationHandler.java +++ b/src/com/hypixel/hytale/server/core/universe/world/WorldNotificationHandler.java @@ -4,8 +4,8 @@ import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.protocol.BlockParticleEvent; import com.hypixel.hytale.protocol.BlockPosition; -import com.hypixel.hytale.protocol.Packet; import com.hypixel.hytale.protocol.Position; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.world.SpawnBlockParticleSystem; import com.hypixel.hytale.protocol.packets.world.UpdateBlockDamage; import com.hypixel.hytale.server.core.modules.entity.player.ChunkTracker; @@ -33,7 +33,7 @@ public class WorldNotificationHandler { public void updateState(int x, int y, int z, BlockState state, BlockState oldState, @Nullable Predicate skip) { if (y >= 0 && y < 320) { - Consumer> removeOldState; + Consumer> removeOldState; Predicate canPlayerSeeOld; if (oldState instanceof SendableBlockState sendableBlockState && state != oldState) { removeOldState = sendableBlockState::unloadFrom; @@ -44,7 +44,7 @@ public class WorldNotificationHandler { } Predicate canPlayerSee; - Consumer> updateBlockState; + Consumer> updateBlockState; if (state instanceof SendableBlockState sendableBlockState) { updateBlockState = sendableBlockState::sendTo; canPlayerSee = sendableBlockState::canPlayerSee; @@ -55,7 +55,7 @@ public class WorldNotificationHandler { if (removeOldState != null || updateBlockState != null) { long indexChunk = ChunkUtil.indexChunkFromBlock(x, z); - List packets = new ObjectArrayList<>(); + List packets = new ObjectArrayList<>(); for (PlayerRef playerRef : this.world.getPlayerRefs()) { ChunkTracker chunkTracker = playerRef.getChunkTracker(); @@ -68,7 +68,7 @@ public class WorldNotificationHandler { updateBlockState.accept(packets); } - for (Packet packet : packets) { + for (ToClientPacket packet : packets) { playerRef.getPacketHandler().write(packet); } @@ -103,12 +103,12 @@ public class WorldNotificationHandler { this.sendPacketIfChunkLoaded(this.getBlockDamagePacket(x, y, z, health, healthDelta), x, z, filter); } - public void sendPacketIfChunkLoaded(@Nonnull Packet packet, int x, int z) { + public void sendPacketIfChunkLoaded(@Nonnull ToClientPacket packet, int x, int z) { long indexChunk = ChunkUtil.indexChunkFromBlock(x, z); this.sendPacketIfChunkLoaded(packet, indexChunk); } - public void sendPacketIfChunkLoaded(@Nonnull Packet packet, long indexChunk) { + public void sendPacketIfChunkLoaded(@Nonnull ToClientPacket packet, long indexChunk) { for (PlayerRef playerRef : this.world.getPlayerRefs()) { if (playerRef.getChunkTracker().isLoaded(indexChunk)) { playerRef.getPacketHandler().write(packet); @@ -116,12 +116,12 @@ public class WorldNotificationHandler { } } - public void sendPacketIfChunkLoaded(@Nonnull Packet packet, int x, int z, @Nullable Predicate filter) { + public void sendPacketIfChunkLoaded(@Nonnull ToClientPacket packet, int x, int z, @Nullable Predicate filter) { long indexChunk = ChunkUtil.indexChunkFromBlock(x, z); this.sendPacketIfChunkLoaded(packet, indexChunk, filter); } - public void sendPacketIfChunkLoaded(@Nonnull Packet packet, long indexChunk, @Nullable Predicate filter) { + public void sendPacketIfChunkLoaded(@Nonnull ToClientPacket packet, long indexChunk, @Nullable Predicate filter) { for (PlayerRef playerRef : this.world.getPlayerRefs()) { if ((filter == null || filter.test(playerRef)) && playerRef.getChunkTracker().isLoaded(indexChunk)) { playerRef.getPacketHandler().write(packet); @@ -129,12 +129,12 @@ public class WorldNotificationHandler { } } - private void sendPacketIfChunkLoaded(@Nonnull PlayerRef player, @Nonnull Packet packet, int x, int z) { + private void sendPacketIfChunkLoaded(@Nonnull PlayerRef player, @Nonnull ToClientPacket packet, int x, int z) { long indexChunk = ChunkUtil.indexChunkFromBlock(x, z); this.sendPacketIfChunkLoaded(player, packet, indexChunk); } - private void sendPacketIfChunkLoaded(@Nonnull PlayerRef playerRef, @Nonnull Packet packet, long indexChunk) { + private void sendPacketIfChunkLoaded(@Nonnull PlayerRef playerRef, @Nonnull ToClientPacket packet, long indexChunk) { if (playerRef.getChunkTracker().isLoaded(indexChunk)) { playerRef.getPacketHandler().write(packet); } 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/BlockChunk.java b/src/com/hypixel/hytale/server/core/universe/world/chunk/BlockChunk.java index b3bd2429..d6ca098b 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/chunk/BlockChunk.java +++ b/src/com/hypixel/hytale/server/core/universe/world/chunk/BlockChunk.java @@ -19,7 +19,7 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.protocol.CachedPacket; import com.hypixel.hytale.protocol.Opacity; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.protocol.packets.world.SetChunkEnvironments; import com.hypixel.hytale.protocol.packets.world.SetChunkHeightmap; import com.hypixel.hytale.protocol.packets.world.SetChunkTintmap; @@ -575,7 +575,7 @@ public class BlockChunk implements Component { Store store, CommandBuffer commandBuffer, PlayerRef player, - @Nonnull List> results + @Nonnull List> results ) { BlockChunk component = archetypeChunk.getComponent(index, this.componentType); results.add(component.getCachedHeightmapPacket().exceptionally(throwable -> { diff --git a/src/com/hypixel/hytale/server/core/universe/world/chunk/BlockComponentChunk.java b/src/com/hypixel/hytale/server/core/universe/world/chunk/BlockComponentChunk.java index d9f547de..d8d87904 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/chunk/BlockComponentChunk.java +++ b/src/com/hypixel/hytale/server/core/universe/world/chunk/BlockComponentChunk.java @@ -21,7 +21,7 @@ import com.hypixel.hytale.component.system.RefChangeSystem; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.vector.Vector3i; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.server.core.modules.LegacyModule; import com.hypixel.hytale.server.core.modules.block.BlockModule; import com.hypixel.hytale.server.core.universe.PlayerRef; @@ -384,7 +384,7 @@ public class BlockComponentChunk implements Component { @Nonnull Store store, CommandBuffer commandBuffer, PlayerRef player, - @Nonnull List results + @Nonnull List results ) { BlockComponentChunk component = archetypeChunk.getComponent(index, this.componentType); ObjectCollection> references = component.entityReferences.values(); @@ -411,7 +411,7 @@ public class BlockComponentChunk implements Component { @Nonnull Store store, CommandBuffer commandBuffer, PlayerRef player, - @Nonnull List results + @Nonnull List results ) { BlockComponentChunk component = archetypeChunk.getComponent(index, this.componentType); ObjectCollection> references = component.entityReferences.values(); diff --git a/src/com/hypixel/hytale/server/core/universe/world/chunk/EntityChunk.java b/src/com/hypixel/hytale/server/core/universe/world/chunk/EntityChunk.java index f24e5c00..fa022a16 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/chunk/EntityChunk.java +++ b/src/com/hypixel/hytale/server/core/universe/world/chunk/EntityChunk.java @@ -290,10 +290,9 @@ public class EntityChunk implements Component { worldChunkComponent.markNeedsSaving(); } else { TransformComponent transformComponent = holder.getComponent(TransformComponent.getComponentType()); - - assert transformComponent != null; - - transformComponent.setChunkLocation(ref, worldChunkComponent); + if (transformComponent != null) { + transformComponent.setChunkLocation(ref, worldChunkComponent); + } } } 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..cfaf2ee7 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,104 @@ 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 environmentId = 0; + int runCounter = 0; + + for (int y = 319; y >= 0; y--) { + 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; + } + } + + this.count(environmentId, runCounter); + } + } + } } 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/chunk/section/BlockSection.java b/src/com/hypixel/hytale/server/core/universe/world/chunk/section/BlockSection.java index 7e3b5e21..b85cc846 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/chunk/section/BlockSection.java +++ b/src/com/hypixel/hytale/server/core/universe/world/chunk/section/BlockSection.java @@ -249,64 +249,68 @@ public class BlockSection implements Component { } public boolean set(int blockIdx, int blockId, int rotation, int filler) { - long lock = this.chunkSectionLock.writeLock(); + if (rotation >= 0 && rotation < RotationTuple.VALUES.length) { + long lock = this.chunkSectionLock.writeLock(); - boolean changed; - try { - ISectionPalette.SetResult result = this.chunkSection.set(blockIdx, blockId); - if (result == ISectionPalette.SetResult.REQUIRES_PROMOTE) { - this.chunkSection = this.chunkSection.promote(); - ISectionPalette.SetResult repeatResult = this.chunkSection.set(blockIdx, blockId); - if (repeatResult != ISectionPalette.SetResult.ADDED_OR_REMOVED) { - throw new IllegalStateException("Promoted chunk section failed to correctly add the new block!"); - } - } else { - if (result == ISectionPalette.SetResult.ADDED_OR_REMOVED) { - this.maximumHitboxExtent = -1.0; + boolean changed; + try { + ISectionPalette.SetResult result = this.chunkSection.set(blockIdx, blockId); + if (result == ISectionPalette.SetResult.REQUIRES_PROMOTE) { + this.chunkSection = this.chunkSection.promote(); + ISectionPalette.SetResult repeatResult = this.chunkSection.set(blockIdx, blockId); + if (repeatResult != ISectionPalette.SetResult.ADDED_OR_REMOVED) { + throw new IllegalStateException("Promoted chunk section failed to correctly add the new block!"); + } + } else { + if (result == ISectionPalette.SetResult.ADDED_OR_REMOVED) { + this.maximumHitboxExtent = -1.0; + } + + if (this.chunkSection.shouldDemote()) { + this.chunkSection = this.chunkSection.demote(); + } } - if (this.chunkSection.shouldDemote()) { - this.chunkSection = this.chunkSection.demote(); + changed = result != ISectionPalette.SetResult.UNCHANGED; + result = this.fillerSection.set(blockIdx, filler); + if (result == ISectionPalette.SetResult.REQUIRES_PROMOTE) { + this.fillerSection = this.fillerSection.promote(); + ISectionPalette.SetResult repeatResult = this.fillerSection.set(blockIdx, filler); + if (repeatResult != ISectionPalette.SetResult.ADDED_OR_REMOVED) { + throw new IllegalStateException("Promoted chunk section failed to correctly add the new block!"); + } + } else if (this.fillerSection.shouldDemote()) { + this.fillerSection = this.fillerSection.demote(); } + + changed |= result != ISectionPalette.SetResult.UNCHANGED; + result = this.rotationSection.set(blockIdx, rotation); + if (result == ISectionPalette.SetResult.REQUIRES_PROMOTE) { + this.rotationSection = this.rotationSection.promote(); + ISectionPalette.SetResult repeatResult = this.rotationSection.set(blockIdx, rotation); + if (repeatResult != ISectionPalette.SetResult.ADDED_OR_REMOVED) { + throw new IllegalStateException("Promoted chunk section failed to correctly add the new block!"); + } + } else if (this.rotationSection.shouldDemote()) { + this.rotationSection = this.rotationSection.demote(); + } + + changed |= result != ISectionPalette.SetResult.UNCHANGED; + if (changed && this.loaded) { + this.changedPositions.add(blockIdx); + } + } finally { + this.chunkSectionLock.unlockWrite(lock); } - changed = result != ISectionPalette.SetResult.UNCHANGED; - result = this.fillerSection.set(blockIdx, filler); - if (result == ISectionPalette.SetResult.REQUIRES_PROMOTE) { - this.fillerSection = this.fillerSection.promote(); - ISectionPalette.SetResult repeatResult = this.fillerSection.set(blockIdx, filler); - if (repeatResult != ISectionPalette.SetResult.ADDED_OR_REMOVED) { - throw new IllegalStateException("Promoted chunk section failed to correctly add the new block!"); - } - } else if (this.fillerSection.shouldDemote()) { - this.fillerSection = this.fillerSection.demote(); + if (changed) { + this.invalidateLocalLight(); } - changed |= result != ISectionPalette.SetResult.UNCHANGED; - result = this.rotationSection.set(blockIdx, rotation); - if (result == ISectionPalette.SetResult.REQUIRES_PROMOTE) { - this.rotationSection = this.rotationSection.promote(); - ISectionPalette.SetResult repeatResult = this.rotationSection.set(blockIdx, rotation); - if (repeatResult != ISectionPalette.SetResult.ADDED_OR_REMOVED) { - throw new IllegalStateException("Promoted chunk section failed to correctly add the new block!"); - } - } else if (this.rotationSection.shouldDemote()) { - this.rotationSection = this.rotationSection.demote(); - } - - changed |= result != ISectionPalette.SetResult.UNCHANGED; - if (changed && this.loaded) { - this.changedPositions.add(blockIdx); - } - } finally { - this.chunkSectionLock.unlockWrite(lock); + return changed; + } else { + throw new IllegalArgumentException("Rotation index out of bounds. Got " + rotation + " but expected 0-" + (RotationTuple.VALUES.length - 1)); } - - if (changed) { - this.invalidateLocalLight(); - } - - return changed; } @Nonnull 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..49ce377e 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 @@ -54,8 +54,8 @@ public class WorldSettingsCommand extends AbstractCommandCollection { "type", ArgTypes.STRING, "ChunkStorage Type", - worldConfig -> IChunkStorageProvider.CODEC.getIdFor((Class)worldConfig.getChunkStorageProvider().getClass()), - (worldConfig, path) -> worldConfig.setChunkStorageProvider(IChunkStorageProvider.CODEC.getCodecFor(path).getDefaultValue()) + worldConfig -> IChunkStorageProvider.CODEC.getIdFor((Class>)worldConfig.getChunkStorageProvider().getClass()), + (worldConfig, path) -> worldConfig.setChunkStorageProvider((IChunkStorageProvider)IChunkStorageProvider.CODEC.getCodecFor(path).getDefaultValue()) ); this.generateSubCommand( "ticking", "server.commands.world.settings.ticking.desc", "ticking", ArgTypes.BOOLEAN, "Ticking", WorldConfig::isTicking, WorldConfig::setTicking @@ -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/BlockInspectPhysicsCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/block/BlockInspectPhysicsCommand.java index 5fecdffb..75e96b7f 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/commands/block/BlockInspectPhysicsCommand.java +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/block/BlockInspectPhysicsCommand.java @@ -26,7 +26,7 @@ public class BlockInspectPhysicsCommand extends AbstractPlayerCommand { private static final Message MESSAGE_COMMANDS_BLOCK_INSPECT_PHYS_NO_BLOCKS = Message.translation("server.commands.block.inspectphys.noblocks"); @Nonnull private static final Message MESSAGE_COMMANDS_BLOCK_INSPECT_PHYS_DONE = Message.translation("server.commands.block.inspectphys.done"); - private final FlagArg ALL = this.withFlagArg("all", ""); + private final FlagArg ALL = this.withFlagArg("all", "server.commands.block.inspectphys.all.desc"); public BlockInspectPhysicsCommand() { super("inspectphys", "server.commands.block.inspectphys.desc"); diff --git a/src/com/hypixel/hytale/server/core/universe/world/commands/block/BlockSetStateCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/block/BlockSetStateCommand.java index 09ee31eb..dc4f154c 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/commands/block/BlockSetStateCommand.java +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/block/BlockSetStateCommand.java @@ -8,10 +8,10 @@ import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk; import javax.annotation.Nonnull; public class BlockSetStateCommand extends SimpleBlockCommand { - private final RequiredArg stateArg = this.withRequiredArg("state", "", ArgTypes.STRING); + private final RequiredArg stateArg = this.withRequiredArg("state", "server.commands.block.setstate.arg.state", ArgTypes.STRING); public BlockSetStateCommand() { - super("setstate", ""); + super("setstate", "server.commands.block.setstate.desc"); } @Override 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..3de98f2f 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 @@ -33,18 +33,18 @@ public class BlockBulkFindCommand extends AbstractWorldCommand { @Nonnull private static final Message MESSAGE_COMMANDS_BLOCK_FIND_DONE = Message.translation("server.commands.block.find.done"); @Nonnull - private final RequiredArg chunkXArg = this.withRequiredArg("chunkX", "", ArgTypes.RELATIVE_INT_COORD); + private final RequiredArg chunkXArg = this.withRequiredArg("chunkX", "server.commands.block.find.chunkX.desc", ArgTypes.RELATIVE_INT_COORD); @Nonnull - private final RequiredArg chunkZArg = this.withRequiredArg("chunkZ", "", ArgTypes.RELATIVE_INT_COORD); + private final RequiredArg chunkZArg = this.withRequiredArg("chunkZ", "server.commands.block.find.chunkZ.desc", ArgTypes.RELATIVE_INT_COORD); @Nonnull - private final RequiredArg blockTypeArg = this.withRequiredArg("block", "", ArgTypes.BLOCK_TYPE_KEY); + private final RequiredArg blockTypeArg = this.withRequiredArg("block", "server.commands.block.find.block.desc", ArgTypes.BLOCK_TYPE_KEY); @Nonnull - private final RequiredArg countArg = this.withRequiredArg("count", "", ArgTypes.INTEGER); + private final RequiredArg countArg = this.withRequiredArg("count", "server.commands.block.find.count.desc", ArgTypes.INTEGER); @Nonnull - private final RequiredArg timeoutArg = this.withRequiredArg("timeout", "", ArgTypes.INTEGER); + private final RequiredArg timeoutArg = this.withRequiredArg("timeout", "server.commands.block.find.timeout.desc", 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/commands/block/bulk/BlockBulkFindHereCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkFindHereCommand.java index 70cec30f..d45c1ff7 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkFindHereCommand.java +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkFindHereCommand.java @@ -29,11 +29,13 @@ import javax.annotation.Nonnull; public class BlockBulkFindHereCommand extends AbstractPlayerCommand { @Nonnull - private final FlagArg printNameArg = this.withFlagArg("print", ""); + private final FlagArg printNameArg = this.withFlagArg("print", "server.commands.block.find-here.print.desc"); @Nonnull - private final RequiredArg blockTypeArg = this.withRequiredArg("block", "", ArgTypes.BLOCK_TYPE_KEY); + private final RequiredArg blockTypeArg = this.withRequiredArg("block", "server.commands.block.find-here.block.desc", ArgTypes.BLOCK_TYPE_KEY); @Nonnull - private final DefaultArg radiusArg = this.withDefaultArg("radius", "", ArgTypes.INTEGER, 3, ""); + private final DefaultArg radiusArg = this.withDefaultArg( + "radius", "server.commands.block.find-here.radius.desc", ArgTypes.INTEGER, 3, "server.commands.block.bulk.find-here.radius.default" + ); public BlockBulkFindHereCommand() { super("find-here", "server.commands.block.find-here.desc"); @@ -81,7 +83,12 @@ public class BlockBulkFindHereCommand extends AbstractPlayerCommand { long diff = System.nanoTime() - start; BlockType findBlock = BlockType.getAssetMap().getAsset(blockId); String blockName = printBlockName ? " " + findBlock.getId() : ""; - playerRef.sendMessage(Message.translation("Found " + found.get() + blockName + " blocks in " + TimeUnit.NANOSECONDS.toSeconds(diff) + " seconds!")); + playerRef.sendMessage( + Message.translation("server.commands.block.find-here.result") + .param("count", found.get()) + .param("blockName", blockName) + .param("time", TimeUnit.NANOSECONDS.toSeconds(diff)) + ); } ); } diff --git a/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkReplaceCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkReplaceCommand.java index e906784a..449ecad4 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkReplaceCommand.java +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/block/bulk/BlockBulkReplaceCommand.java @@ -32,14 +32,16 @@ import javax.annotation.Nonnull; public class BlockBulkReplaceCommand extends AbstractPlayerCommand { @Nonnull - private final RequiredArg findArg = this.withRequiredArg("find", "", ArgTypes.BLOCK_TYPE_KEY); + private final RequiredArg findArg = this.withRequiredArg("find", "server.commands.block.bulk.replace.find.desc", ArgTypes.BLOCK_TYPE_KEY); @Nonnull - private final RequiredArg replaceArg = this.withRequiredArg("replaceWith", "", ArgTypes.BLOCK_TYPE_KEY); + private final RequiredArg replaceArg = this.withRequiredArg( + "replaceWith", "server.commands.block.bulk.replace.replaceWith.desc", ArgTypes.BLOCK_TYPE_KEY + ); @Nonnull - private final RequiredArg radiusArg = this.withRequiredArg("radius", "", ArgTypes.INTEGER); + private final RequiredArg radiusArg = this.withRequiredArg("radius", "server.commands.block.bulk.replace.radius.desc", ArgTypes.INTEGER); public BlockBulkReplaceCommand() { - super("replace", ""); + super("replace", "server.commands.block.bulk.replace.desc"); } @Override @@ -97,7 +99,9 @@ public class BlockBulkReplaceCommand extends AbstractPlayerCommand { long diff = System.nanoTime() - start; playerRef.sendMessage( - Message.translation("Found and replaced " + replaced.get() + " blocks in " + TimeUnit.NANOSECONDS.toSeconds(diff) + " seconds!") + Message.translation("server.commands.block.bulk.replace.result") + .param("count", replaced.get()) + .param("time", TimeUnit.NANOSECONDS.toSeconds(diff)) ); } ); diff --git a/src/com/hypixel/hytale/server/core/universe/world/commands/world/WorldCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/world/WorldCommand.java index 636a4ea9..9ff22d7a 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/commands/world/WorldCommand.java +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/world/WorldCommand.java @@ -23,5 +23,6 @@ public class WorldCommand extends AbstractCommandCollection { this.addSubCommand(new WorldSettingsCommand()); this.addSubCommand(new WorldPerfCommand()); this.addSubCommand(new WorldTpsCommand()); + this.addSubCommand(new WorldRocksDbCommand()); } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/commands/world/WorldRocksDbCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/world/WorldRocksDbCommand.java new file mode 100644 index 00000000..6400ee34 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/world/WorldRocksDbCommand.java @@ -0,0 +1,44 @@ +package com.hypixel.hytale.server.core.universe.world.commands.world; + +import com.hypixel.fastutil.util.SneakyThrow; +import com.hypixel.hytale.server.core.Message; +import com.hypixel.hytale.server.core.command.system.CommandContext; +import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncWorldCommand; +import com.hypixel.hytale.server.core.command.system.basecommands.AbstractCommandCollection; +import com.hypixel.hytale.server.core.universe.world.World; +import com.hypixel.hytale.server.core.universe.world.storage.provider.RocksDbChunkStorageProvider; +import java.util.concurrent.CompletableFuture; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; + +public class WorldRocksDbCommand extends AbstractCommandCollection { + public WorldRocksDbCommand() { + super("rocksdb", "server.commands.world.rocksdb"); + this.addSubCommand(new WorldRocksDbCommand.CompactCommand()); + } + + public static class CompactCommand extends AbstractAsyncWorldCommand { + public CompactCommand() { + super("compact", "server.commands.world.rocksdb.compact"); + } + + @NonNullDecl + @Override + protected CompletableFuture executeAsync(@NonNullDecl CommandContext context, @NonNullDecl World world) { + if (world.getChunkStore().getStorageData() instanceof RocksDbChunkStorageProvider.RocksDbResource rocksDbResource) { + context.sendMessage(Message.translation("server.commands.world.rocksdb.compact.start")); + return CompletableFuture.runAsync(() -> { + try { + rocksDbResource.db.compactRange(rocksDbResource.chunkColumn); + } catch (Exception var3) { + throw SneakyThrow.sneakyThrow(var3); + } + + context.sendMessage(Message.translation("server.commands.world.rocksdb.compact.end")); + }); + } else { + context.sendMessage(Message.translation("server.commands.world.rocksdb.compact.wrong")); + return CompletableFuture.completedFuture(null); + } + } + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/commands/worldconfig/WorldConfigSetPvpCommand.java b/src/com/hypixel/hytale/server/core/universe/world/commands/worldconfig/WorldConfigSetPvpCommand.java index 418029d0..8bd28c7b 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/commands/worldconfig/WorldConfigSetPvpCommand.java +++ b/src/com/hypixel/hytale/server/core/universe/world/commands/worldconfig/WorldConfigSetPvpCommand.java @@ -9,7 +9,6 @@ import com.hypixel.hytale.server.core.command.system.basecommands.AbstractWorldC import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.WorldConfig; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.hypixel.hytale.server.core.util.message.MessageFormat; import javax.annotation.Nonnull; public class WorldConfigSetPvpCommand extends AbstractWorldCommand { @@ -27,7 +26,7 @@ public class WorldConfigSetPvpCommand extends AbstractWorldCommand { worldConfig.setPvpEnabled(isPvpEnabled); worldConfig.markChanged(); context.sendMessage( - Message.translation("server.universe.setpvp.info").param("status", MessageFormat.enabled(isPvpEnabled)).param("worldName", world.getName()) + Message.translation("server.universe.setpvp.info").param("enabled", isPvpEnabled ? "true" : "false").param("worldName", world.getName()) ); } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/connectedblocks/builtin/StairConnectedBlockRuleSet.java b/src/com/hypixel/hytale/server/core/universe/world/connectedblocks/builtin/StairConnectedBlockRuleSet.java index 2415dbe4..14e47989 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/connectedblocks/builtin/StairConnectedBlockRuleSet.java +++ b/src/com/hypixel/hytale/server/core/universe/world/connectedblocks/builtin/StairConnectedBlockRuleSet.java @@ -55,6 +55,7 @@ public class StairConnectedBlockRuleSet extends ConnectedBlockRuleSet implements .append(new KeyedCodec<>("MaterialName", Codec.STRING), (ruleSet, materialName) -> ruleSet.materialName = materialName, ruleSet -> ruleSet.materialName) .add() .build(); + protected Object2IntMap stairTypeToBlockId; private ConnectedBlockOutput straight; private ConnectedBlockOutput cornerLeft; private ConnectedBlockOutput cornerRight; @@ -62,38 +63,6 @@ public class StairConnectedBlockRuleSet extends ConnectedBlockRuleSet implements private ConnectedBlockOutput invertedCornerRight; private String materialName = "Stair"; private Int2ObjectMap blockIdToStairType; - protected Object2IntMap stairTypeToBlockId; - - @Override - public boolean onlyUpdateOnPlacement() { - return false; - } - - @Override - public void updateCachedBlockTypes(BlockType baseBlockType, BlockTypeAssetMap assetMap) { - int baseIndex = assetMap.getIndex(baseBlockType.getId()); - Int2ObjectMap blockIdToStairType = new Int2ObjectOpenHashMap<>(); - Object2IntMap stairTypeToBlockId = new Object2IntOpenHashMap<>(); - stairTypeToBlockId.defaultReturnValue(baseIndex); - ConnectedBlockOutput[] outputs = new ConnectedBlockOutput[]{ - this.straight, this.cornerLeft, this.cornerRight, this.invertedCornerLeft, this.invertedCornerRight - }; - StairConnectedBlockRuleSet.StairType[] stairTypes = StairConnectedBlockRuleSet.StairType.VALUES; - - for (int i = 0; i < outputs.length; i++) { - ConnectedBlockOutput output = outputs[i]; - if (output != null) { - int index = output.resolve(baseBlockType, assetMap); - if (index != -1) { - blockIdToStairType.put(index, stairTypes[i]); - stairTypeToBlockId.put(stairTypes[i], index); - } - } - } - - this.blockIdToStairType = blockIdToStairType; - this.stairTypeToBlockId = stairTypeToBlockId; - } @Nullable protected static ObjectIntPair getStairData(World world, Vector3i coordinate, @Nullable String requiredMaterialName) { @@ -129,6 +98,130 @@ public class StairConnectedBlockRuleSet extends ConnectedBlockRuleSet implements } } + protected static StairConnectedBlockRuleSet.StairConnection getCornerConnection( + World world, + StairLikeConnectedBlockRuleSet currentRuleSet, + Vector3i coordinate, + Vector3i mutablePos, + int rotation, + Rotation currentYaw, + boolean upsideDown, + int width + ) { + StairConnectedBlockRuleSet.StairConnection backConnection = null; + mutablePos.assign(Vector3i.NORTH).scale(width); + currentYaw.rotateY(mutablePos, mutablePos); + mutablePos.add(coordinate.x, coordinate.y, coordinate.z); + ObjectIntPair backStair = getStairData(world, mutablePos, currentRuleSet.getMaterialName()); + if (backStair == null && width > 1) { + mutablePos.assign(Vector3i.NORTH).scale(width + 1); + currentYaw.rotateY(mutablePos, mutablePos); + mutablePos.add(coordinate.x, coordinate.y, coordinate.z); + backStair = getStairData(world, mutablePos, currentRuleSet.getMaterialName()); + if (backStair != null && backStair.first() == StairConnectedBlockRuleSet.StairType.STRAIGHT) { + backStair = null; + } + } + + if (backStair != null) { + StairConnectedBlockRuleSet.StairType otherStairType = backStair.left(); + RotationTuple otherStairRotation = RotationTuple.get(backStair.rightInt()); + Rotation otherYaw = otherStairRotation.yaw(); + boolean otherUpsideDown = otherStairRotation.pitch() != Rotation.None; + if (otherUpsideDown) { + otherYaw = otherYaw.flip(); + } + + if (canConnectTo(currentYaw, otherYaw, upsideDown, otherUpsideDown)) { + mutablePos.assign(Vector3i.SOUTH); + otherYaw.rotateY(mutablePos, mutablePos); + mutablePos.add(coordinate.x, coordinate.y, coordinate.z); + ObjectIntPair sidewaysStair = getStairData(world, mutablePos, currentRuleSet.getMaterialName()); + if (sidewaysStair == null || sidewaysStair.rightInt() != rotation) { + backConnection = getConnection(currentYaw, otherYaw, otherStairType, false, upsideDown); + } + } + } + + return backConnection; + } + + protected static StairConnectedBlockRuleSet.StairConnection getInvertedCornerConnection( + World world, StairLikeConnectedBlockRuleSet currentRuleSet, Vector3i coordinate, Vector3i mutablePos, Rotation currentYaw, boolean upsideDown + ) { + StairConnectedBlockRuleSet.StairConnection frontConnection = null; + mutablePos.assign(Vector3i.SOUTH); + currentYaw.rotateY(mutablePos, mutablePos); + mutablePos.add(coordinate.x, coordinate.y, coordinate.z); + ObjectIntPair frontStair = getStairData(world, mutablePos, currentRuleSet.getMaterialName()); + if (frontStair != null) { + StairConnectedBlockRuleSet.StairType otherStairType = frontStair.left(); + RotationTuple otherStairRotation = RotationTuple.get(frontStair.rightInt()); + Rotation otherYaw = otherStairRotation.yaw(); + boolean otherUpsideDown = otherStairRotation.pitch() != Rotation.None; + if (otherUpsideDown) { + otherYaw = otherYaw.flip(); + } + + if (canConnectTo(currentYaw, otherYaw, upsideDown, otherUpsideDown)) { + frontConnection = getConnection(currentYaw, otherYaw, otherStairType, true, upsideDown); + } + } + + return frontConnection; + } + + private static boolean canConnectTo(Rotation currentYaw, Rotation otherYaw, boolean upsideDown, boolean otherUpsideDown) { + return otherUpsideDown == upsideDown && otherYaw != currentYaw && otherYaw.add(Rotation.OneEighty) != currentYaw; + } + + private static StairConnectedBlockRuleSet.StairConnection getConnection( + Rotation currentYaw, Rotation otherYaw, StairConnectedBlockRuleSet.StairType otherStairType, boolean inverted, boolean upsideDown + ) { + if (otherYaw == currentYaw.add(Rotation.Ninety) + && otherStairType != StairConnectedBlockRuleSet.StairType.invertedCorner(upsideDown ^ inverted) + && otherStairType != StairConnectedBlockRuleSet.StairType.corner(upsideDown ^ !inverted)) { + return StairConnectedBlockRuleSet.StairConnection.CORNER_LEFT; + } else { + return otherYaw == currentYaw.subtract(Rotation.Ninety) + && otherStairType != StairConnectedBlockRuleSet.StairType.invertedCorner(upsideDown ^ !inverted) + && otherStairType != StairConnectedBlockRuleSet.StairType.corner(upsideDown ^ inverted) + ? StairConnectedBlockRuleSet.StairConnection.CORNER_RIGHT + : null; + } + } + + @Override + public boolean onlyUpdateOnPlacement() { + return false; + } + + @Override + public void updateCachedBlockTypes(BlockType baseBlockType, BlockTypeAssetMap assetMap) { + int baseIndex = assetMap.getIndex(baseBlockType.getId()); + Int2ObjectMap blockIdToStairType = new Int2ObjectOpenHashMap<>(); + Object2IntMap stairTypeToBlockId = new Object2IntOpenHashMap<>(); + stairTypeToBlockId.defaultReturnValue(baseIndex); + ConnectedBlockOutput[] outputs = new ConnectedBlockOutput[]{ + this.straight, this.cornerLeft, this.cornerRight, this.invertedCornerLeft, this.invertedCornerRight + }; + StairConnectedBlockRuleSet.StairType[] stairTypes = StairConnectedBlockRuleSet.StairType.VALUES; + + for (int i = 0; i < outputs.length; i++) { + ConnectedBlockOutput output = outputs[i]; + if (output != null) { + int index = output.resolve(baseBlockType, assetMap); + if (index != -1) { + blockIdToStairType.put(index, stairTypes[i]); + stairTypeToBlockId.put(stairTypes[i], index); + } + } + } + + this.blockIdToStairType = blockIdToStairType; + this.stairTypeToBlockId = stairTypeToBlockId; + } + @Override public StairConnectedBlockRuleSet.StairType getStairType(int blockId) { return this.blockIdToStairType.get(blockId); @@ -193,99 +286,6 @@ public class StairConnectedBlockRuleSet extends ConnectedBlockRuleSet implements } } - protected static StairConnectedBlockRuleSet.StairConnection getCornerConnection( - World world, - StairLikeConnectedBlockRuleSet currentRuleSet, - Vector3i coordinate, - Vector3i mutablePos, - int rotation, - Rotation currentYaw, - boolean upsideDown, - int width - ) { - StairConnectedBlockRuleSet.StairConnection backConnection = null; - mutablePos.assign(Vector3i.NORTH).scale(width); - currentYaw.rotateY(mutablePos, mutablePos); - mutablePos.add(coordinate.x, coordinate.y, coordinate.z); - ObjectIntPair backStair = getStairData(world, mutablePos, currentRuleSet.getMaterialName()); - if (backStair == null && width > 1) { - mutablePos.assign(Vector3i.NORTH).scale(width + 1); - currentYaw.rotateY(mutablePos, mutablePos); - mutablePos.add(coordinate.x, coordinate.y, coordinate.z); - backStair = getStairData(world, mutablePos, currentRuleSet.getMaterialName()); - if (backStair != null && backStair.first() == StairConnectedBlockRuleSet.StairType.STRAIGHT) { - backStair = null; - } - } - - if (backStair != null) { - StairConnectedBlockRuleSet.StairType otherStairType = backStair.left(); - RotationTuple otherStairRotation = RotationTuple.get(backStair.rightInt()); - Rotation otherYaw = otherStairRotation.yaw(); - boolean otherUpsideDown = otherStairRotation.pitch() != Rotation.None; - if (otherUpsideDown) { - otherYaw = otherYaw.flip(); - } - - if (canConnectTo(currentYaw, otherYaw, upsideDown, otherUpsideDown)) { - mutablePos.assign(Vector3i.SOUTH); - otherYaw.rotateY(mutablePos, mutablePos); - mutablePos.add(coordinate.x, coordinate.y, coordinate.z); - ObjectIntPair sidewaysStair = getStairData(world, mutablePos, currentRuleSet.getMaterialName()); - if (sidewaysStair == null || sidewaysStair.rightInt() != rotation) { - backConnection = getConnection(currentYaw, otherYaw, otherStairType, false); - } - } - } - - return backConnection; - } - - protected static StairConnectedBlockRuleSet.StairConnection getInvertedCornerConnection( - World world, StairLikeConnectedBlockRuleSet currentRuleSet, Vector3i coordinate, Vector3i mutablePos, Rotation currentYaw, boolean upsideDown - ) { - StairConnectedBlockRuleSet.StairConnection frontConnection = null; - mutablePos.assign(Vector3i.SOUTH); - currentYaw.rotateY(mutablePos, mutablePos); - mutablePos.add(coordinate.x, coordinate.y, coordinate.z); - ObjectIntPair frontStair = getStairData(world, mutablePos, currentRuleSet.getMaterialName()); - if (frontStair != null) { - StairConnectedBlockRuleSet.StairType otherStairType = frontStair.left(); - RotationTuple otherStairRotation = RotationTuple.get(frontStair.rightInt()); - Rotation otherYaw = otherStairRotation.yaw(); - boolean otherUpsideDown = otherStairRotation.pitch() != Rotation.None; - if (otherUpsideDown) { - otherYaw = otherYaw.flip(); - } - - if (canConnectTo(currentYaw, otherYaw, upsideDown, otherUpsideDown)) { - frontConnection = getConnection(currentYaw, otherYaw, otherStairType, true); - } - } - - return frontConnection; - } - - private static boolean canConnectTo(Rotation currentYaw, Rotation otherYaw, boolean upsideDown, boolean otherUpsideDown) { - return otherUpsideDown == upsideDown && otherYaw != currentYaw && otherYaw.add(Rotation.OneEighty) != currentYaw; - } - - private static StairConnectedBlockRuleSet.StairConnection getConnection( - Rotation currentYaw, Rotation otherYaw, StairConnectedBlockRuleSet.StairType otherStairType, boolean inverted - ) { - if (otherYaw == currentYaw.add(Rotation.Ninety) - && otherStairType != StairConnectedBlockRuleSet.StairType.invertedCorner(inverted) - && otherStairType != StairConnectedBlockRuleSet.StairType.corner(!inverted)) { - return StairConnectedBlockRuleSet.StairConnection.CORNER_LEFT; - } else { - return otherYaw == currentYaw.subtract(Rotation.Ninety) - && otherStairType != StairConnectedBlockRuleSet.StairType.invertedCorner(!inverted) - && otherStairType != StairConnectedBlockRuleSet.StairType.corner(inverted) - ? StairConnectedBlockRuleSet.StairConnection.CORNER_RIGHT - : null; - } - } - @Nullable @Override public com.hypixel.hytale.protocol.ConnectedBlockRuleSet toPacket(BlockTypeAssetMap assetMap) { 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/BlockStateModule.java b/src/com/hypixel/hytale/server/core/universe/world/meta/BlockStateModule.java index eaa50c63..1a500d65 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/meta/BlockStateModule.java +++ b/src/com/hypixel/hytale/server/core/universe/world/meta/BlockStateModule.java @@ -28,7 +28,7 @@ import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.math.vector.Vector3i; import com.hypixel.hytale.metrics.MetricResults; import com.hypixel.hytale.metrics.MetricsRegistry; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.asset.type.blocktype.config.StateData; @@ -419,7 +419,7 @@ public class BlockStateModule extends JavaPlugin { Store store, CommandBuffer commandBuffer, PlayerRef player, - List results + List results ) { SendableBlockState state = (SendableBlockState)BlockState.getBlockState(index, archetypeChunk); if (state.canPlayerSee(player)) { @@ -501,7 +501,7 @@ public class BlockStateModule extends JavaPlugin { Store store, CommandBuffer commandBuffer, PlayerRef player, - List results + List results ) { SendableBlockState state = (SendableBlockState)BlockState.getBlockState(index, archetypeChunk); if (state.canPlayerSee(player)) { 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/meta/state/SendableBlockState.java b/src/com/hypixel/hytale/server/core/universe/world/meta/state/SendableBlockState.java index 97a8636a..6f22b243 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/meta/state/SendableBlockState.java +++ b/src/com/hypixel/hytale/server/core/universe/world/meta/state/SendableBlockState.java @@ -1,14 +1,14 @@ package com.hypixel.hytale.server.core.universe.world.meta.state; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.server.core.universe.PlayerRef; import java.util.List; @Deprecated public interface SendableBlockState { - void sendTo(List var1); + void sendTo(List var1); - void unloadFrom(List var1); + void unloadFrom(List var1); default boolean canPlayerSee(PlayerRef player) { return true; diff --git a/src/com/hypixel/hytale/server/core/universe/world/storage/ChunkStore.java b/src/com/hypixel/hytale/server/core/universe/world/storage/ChunkStore.java index 44d38fab..c8c706d8 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/storage/ChunkStore.java +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/ChunkStore.java @@ -2,6 +2,8 @@ package com.hypixel.hytale.server.core.universe.world.storage; import com.hypixel.fastutil.longs.Long2ObjectConcurrentHashMap; import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.store.CodecKey; import com.hypixel.hytale.codec.store.CodecStore; import com.hypixel.hytale.common.util.FormatUtil; @@ -14,6 +16,7 @@ import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.IResourceStorage; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.RemoveReason; +import com.hypixel.hytale.component.Resource; import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.SystemGroup; @@ -25,7 +28,7 @@ import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.metrics.MetricProvider; import com.hypixel.hytale.metrics.MetricsRegistry; -import com.hypixel.hytale.protocol.Packet; +import com.hypixel.hytale.protocol.ToClientPacket; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.World; @@ -93,6 +96,7 @@ public class ChunkStore implements WorldProvider { @Nonnull private final Long2ObjectConcurrentHashMap chunks = new Long2ObjectConcurrentHashMap<>(true, ChunkUtil.NOT_FOUND); private Store store; + private Object storageData; @Nullable private IChunkLoader loader; @Nullable @@ -120,6 +124,10 @@ public class ChunkStore implements WorldProvider { return this.store; } + public Object getStorageData() { + return this.storageData; + } + @Nullable public IChunkLoader getLoader() { return this.loader; @@ -753,6 +761,10 @@ public class ChunkStore implements WorldProvider { } public static class ChunkLoaderSaverSetupSystem extends StoreSystem { + private final ResourceType chunkStorageResourceType = this.registerResource( + ChunkStore.ChunkStorage.class, "ChunkStorage", ChunkStore.ChunkStorage.CODEC + ); + @Nullable @Override public SystemGroup getGroup() { @@ -763,13 +775,21 @@ public class ChunkStore implements WorldProvider { public void onSystemAddedToStore(@Nonnull Store store) { ChunkStore data = store.getExternalData(); World world = data.getWorld(); - IChunkStorageProvider chunkStorageProvider = world.getWorldConfig().getChunkStorageProvider(); + IChunkStorageProvider chunkStorageProvider = world.getWorldConfig().getChunkStorageProvider(); + ChunkStore.ChunkStorage chunkStorage = store.getResource(this.chunkStorageResourceType); try { - data.loader = chunkStorageProvider.getLoader(store); - data.saver = chunkStorageProvider.getSaver(store); - } catch (IOException var6) { - throw SneakyThrow.sneakyThrow(var6); + if (chunkStorage.currentProvider != null && !chunkStorage.currentProvider.isSame(chunkStorageProvider)) { + data.storageData = chunkStorageProvider.migrateFrom(store, chunkStorage.currentProvider); + } else { + data.storageData = chunkStorageProvider.initialize(store); + } + + chunkStorage.currentProvider = chunkStorageProvider; + data.loader = ((IChunkStorageProvider)chunkStorageProvider).getLoader(data.storageData, store); + data.saver = ((IChunkStorageProvider)chunkStorageProvider).getSaver(data.storageData, store); + } catch (IOException var7) { + throw SneakyThrow.sneakyThrow(var7); } } @@ -789,18 +809,44 @@ public class ChunkStore implements WorldProvider { data.saver = null; oldSaver.close(); } - } catch (IOException var4) { - ChunkStore.LOGGER.at(Level.SEVERE).withCause(var4).log("Failed to close storage!"); + + World world = data.getWorld(); + IChunkStorageProvider chunkStorageProvider = world.getWorldConfig().getChunkStorageProvider(); + ((IChunkStorageProvider)chunkStorageProvider).close(data.storageData, store); + } catch (IOException var5) { + ChunkStore.LOGGER.at(Level.SEVERE).withCause(var5).log("Failed to close storage!"); } } } - public abstract static class LoadFuturePacketDataQuerySystem extends EntityDataSystem> { + private static class ChunkStorage implements Resource { + public static final BuilderCodec CODEC = BuilderCodec.builder(ChunkStore.ChunkStorage.class, ChunkStore.ChunkStorage::new) + .append(new KeyedCodec<>("CurrentProvider", IChunkStorageProvider.CODEC), (o, i) -> o.currentProvider = i, o -> o.currentProvider) + .add() + .build(); + @Nullable + private IChunkStorageProvider currentProvider; + + public ChunkStorage(@Nullable IChunkStorageProvider currentProvider) { + this.currentProvider = currentProvider; + } + + public ChunkStorage() { + } + + @Nullable + @Override + public Resource clone() { + return new ChunkStore.ChunkStorage(this.currentProvider); + } } - public abstract static class LoadPacketDataQuerySystem extends EntityDataSystem { + public abstract static class LoadFuturePacketDataQuerySystem extends EntityDataSystem> { } - public abstract static class UnloadPacketDataQuerySystem extends EntityDataSystem { + public abstract static class LoadPacketDataQuerySystem extends EntityDataSystem { + } + + public abstract static class UnloadPacketDataQuerySystem extends EntityDataSystem { } } 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/storage/provider/DefaultChunkStorageProvider.java b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/DefaultChunkStorageProvider.java index a3bf827e..2ce60ef1 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/DefaultChunkStorageProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/DefaultChunkStorageProvider.java @@ -7,33 +7,53 @@ import com.hypixel.hytale.server.core.universe.world.storage.IChunkLoader; import com.hypixel.hytale.server.core.universe.world.storage.IChunkSaver; import java.io.IOException; import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; -public class DefaultChunkStorageProvider implements IChunkStorageProvider { - @Nonnull - public static final DefaultChunkStorageProvider INSTANCE = new DefaultChunkStorageProvider(); +public class DefaultChunkStorageProvider implements IChunkStorageProvider { + public static final int VERSION = 0; public static final String ID = "Hytale"; @Nonnull - public static final BuilderCodec CODEC = BuilderCodec.builder(DefaultChunkStorageProvider.class, () -> INSTANCE) + private static final IChunkStorageProvider DEFAULT_INDEXED = new IndexedStorageChunkStorageProvider(); + @Nonnull + public static final BuilderCodec CODEC = BuilderCodec.builder( + DefaultChunkStorageProvider.class, DefaultChunkStorageProvider::new + ) + .versioned() + .codecVersion(0) .documentation("Selects the default recommended storage as decided by the server.") .build(); - @Nonnull - public static final IChunkStorageProvider DEFAULT = new IndexedStorageChunkStorageProvider(); + private IChunkStorageProvider provider = DEFAULT_INDEXED; - @Nonnull @Override - public IChunkLoader getLoader(@Nonnull Store store) throws IOException { - return DEFAULT.getLoader(store); + public Object initialize(@Nonnull Store store) throws IOException { + return this.provider.initialize(store); + } + + @Override + public void close(@Nonnull Object o, @NonNullDecl Store store) throws IOException { + ((IChunkStorageProvider)this.provider).close(o, store); } @Nonnull @Override - public IChunkSaver getSaver(@Nonnull Store store) throws IOException { - return DEFAULT.getSaver(store); + public IChunkLoader getLoader(@Nonnull Object o, @Nonnull Store store) throws IOException { + return ((IChunkStorageProvider)this.provider).getLoader(o, store); + } + + @Nonnull + @Override + public IChunkSaver getSaver(@Nonnull Object o, @Nonnull Store store) throws IOException { + return ((IChunkStorageProvider)this.provider).getSaver(o, store); + } + + @Override + public boolean isSame(IChunkStorageProvider other) { + return other.getClass().equals(this.getClass()) || this.provider.isSame(other); } @Nonnull @Override public String toString() { - return "DefaultChunkStorageProvider{DEFAULT=" + DEFAULT + "}"; + return "DefaultChunkStorageProvider{DEFAULT=" + this.provider + "}"; } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/EmptyChunkStorageProvider.java b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/EmptyChunkStorageProvider.java index 52d20207..926970f7 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/EmptyChunkStorageProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/EmptyChunkStorageProvider.java @@ -8,10 +8,12 @@ import com.hypixel.hytale.server.core.universe.world.storage.IChunkLoader; import com.hypixel.hytale.server.core.universe.world.storage.IChunkSaver; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.longs.LongSets; +import java.io.IOException; import java.util.concurrent.CompletableFuture; import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; -public class EmptyChunkStorageProvider implements IChunkStorageProvider { +public class EmptyChunkStorageProvider implements IChunkStorageProvider { public static final String ID = "Empty"; @Nonnull public static final EmptyChunkStorageProvider INSTANCE = new EmptyChunkStorageProvider(); @@ -20,19 +22,24 @@ public class EmptyChunkStorageProvider implements IChunkStorageProvider { .documentation("A chunk storage provider that discards any chunks to save and will always fail to find chunks.") .build(); @Nonnull - public static final EmptyChunkStorageProvider.EmptyChunkLoader EMPTY_CHUNK_LOADER = new EmptyChunkStorageProvider.EmptyChunkLoader(); + private static final EmptyChunkStorageProvider.EmptyChunkLoader EMPTY_CHUNK_LOADER = new EmptyChunkStorageProvider.EmptyChunkLoader(); @Nonnull - public static final EmptyChunkStorageProvider.EmptyChunkSaver EMPTY_CHUNK_SAVER = new EmptyChunkStorageProvider.EmptyChunkSaver(); + private static final EmptyChunkStorageProvider.EmptyChunkSaver EMPTY_CHUNK_SAVER = new EmptyChunkStorageProvider.EmptyChunkSaver(); + + public Void initialize(@NonNullDecl Store store) throws IOException { + return null; + } + + public void close(@NonNullDecl Void o, @NonNullDecl Store store) throws IOException { + } @Nonnull - @Override - public IChunkLoader getLoader(@Nonnull Store store) { + public IChunkLoader getLoader(@Nonnull Void object, @Nonnull Store store) { return EMPTY_CHUNK_LOADER; } @Nonnull - @Override - public IChunkSaver getSaver(@Nonnull Store store) { + public IChunkSaver getSaver(@Nonnull Void object, @Nonnull Store store) { return EMPTY_CHUNK_SAVER; } diff --git a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/IChunkStorageProvider.java b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/IChunkStorageProvider.java index e69af576..c32adab1 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/IChunkStorageProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/IChunkStorageProvider.java @@ -1,20 +1,87 @@ package com.hypixel.hytale.server.core.universe.world.storage.provider; import com.hypixel.hytale.codec.lookup.BuilderCodecMapCodec; +import com.hypixel.hytale.component.Holder; 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.server.core.HytaleServer; +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.IChunkLoader; import com.hypixel.hytale.server.core.universe.world.storage.IChunkSaver; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongSet; import java.io.IOException; +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ForkJoinPool; import javax.annotation.Nonnull; -public interface IChunkStorageProvider { +public interface IChunkStorageProvider { @Nonnull - BuilderCodecMapCodec CODEC = new BuilderCodecMapCodec<>("Type", true); + BuilderCodecMapCodec> CODEC = new BuilderCodecMapCodec<>("Type", true); + + Data initialize(@Nonnull Store var1) throws IOException; + + default Data migrateFrom(@Nonnull Store store, IChunkStorageProvider other) throws IOException { + OtherData oldData = other.initialize(store); + Data newData = this.initialize(store); + + try ( + IChunkLoader oldLoader = other.getLoader(oldData, store); + IChunkSaver newSaver = this.getSaver(newData, store); + ) { + World world = store.getExternalData().getWorld(); + HytaleLogger logger = world.getLogger(); + LongSet chunks = oldLoader.getIndexes(); + LongIterator iterator = chunks.iterator(); + logger.atInfo().log("Migrating %d chunks", chunks.size()); + HytaleServer.get().reportSingleplayerStatus(String.format("Migrating chunks for %s", world.getName()), 0.0); + int count = 0; + ArrayList> inFlight = new ArrayList<>(); + + while (iterator.hasNext()) { + long chunk = iterator.nextLong(); + int chunkX = ChunkUtil.xOfChunkIndex(chunk); + int chunkZ = ChunkUtil.zOfChunkIndex(chunk); + inFlight.add(oldLoader.loadHolder(chunkX, chunkZ).thenCompose(v -> newSaver.saveHolder(chunkX, chunkZ, (Holder)v)).exceptionally(t -> { + logger.atSevere().withCause(t).log("Failed to load chunk at %d, %d, skipping", chunkX, chunkZ); + return null; + })); + if (++count % 100 == 0) { + logger.atInfo().log("Migrated %d/%d chunks", count, chunks.size()); + double progress = MathUtil.round((double)count / chunks.size(), 2) * 100.0; + HytaleServer.get().reportSingleplayerStatus(String.format("Migrating chunks for %s", world.getName()), progress); + } + + inFlight.removeIf(CompletableFuture::isDone); + if (inFlight.size() >= ForkJoinPool.getCommonPoolParallelism()) { + CompletableFuture.anyOf(inFlight.toArray(CompletableFuture[]::new)).join(); + inFlight.removeIf(CompletableFuture::isDone); + } + } + + CompletableFuture.allOf(inFlight.toArray(CompletableFuture[]::new)).join(); + inFlight.clear(); + logger.atInfo().log("Finished migrating %d chunks", chunks.size()); + } finally { + other.close(oldData, store); + } + + return newData; + } + + void close(@Nonnull Data var1, @Nonnull Store var2) throws IOException; @Nonnull - IChunkLoader getLoader(@Nonnull Store var1) throws IOException; + IChunkLoader getLoader(@Nonnull Data var1, @Nonnull Store var2) throws IOException; @Nonnull - IChunkSaver getSaver(@Nonnull Store var1) throws IOException; + IChunkSaver getSaver(@Nonnull Data var1, @Nonnull Store var2) throws IOException; + + default boolean isSame(IChunkStorageProvider other) { + return other.getClass().equals(this.getClass()); + } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/IndexedStorageChunkStorageProvider.java b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/IndexedStorageChunkStorageProvider.java index c8bd04fa..2c6e1bc7 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/IndexedStorageChunkStorageProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/IndexedStorageChunkStorageProvider.java @@ -6,15 +6,11 @@ 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.component.Resource; -import com.hypixel.hytale.component.ResourceType; import com.hypixel.hytale.component.Store; -import com.hypixel.hytale.component.SystemGroup; -import com.hypixel.hytale.component.system.StoreSystem; import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.metrics.MetricProvider; import com.hypixel.hytale.metrics.MetricResults; import com.hypixel.hytale.metrics.MetricsRegistry; -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.BufferChunkLoader; import com.hypixel.hytale.server.core.universe.world.storage.BufferChunkSaver; @@ -42,8 +38,9 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; -public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider { +public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider { public static final String ID = "IndexedStorage"; @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( @@ -60,16 +57,25 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider .build(); private boolean flushOnWrite = false; - @Nonnull - @Override - public IChunkLoader getLoader(@Nonnull Store store) { - return new IndexedStorageChunkStorageProvider.IndexedStorageChunkLoader(store, this.flushOnWrite); + public IndexedStorageChunkStorageProvider.IndexedStorageCache initialize(@NonNullDecl Store store) throws IOException { + World world = store.getExternalData().getWorld(); + IndexedStorageChunkStorageProvider.IndexedStorageCache cache = new IndexedStorageChunkStorageProvider.IndexedStorageCache(); + cache.path = world.getSavePath().resolve("chunks"); + return cache; + } + + public void close(@NonNullDecl IndexedStorageChunkStorageProvider.IndexedStorageCache cache, @NonNullDecl Store store) throws IOException { + cache.close(); } @Nonnull - @Override - public IChunkSaver getSaver(@Nonnull Store store) { - return new IndexedStorageChunkStorageProvider.IndexedStorageChunkSaver(store, this.flushOnWrite); + public IChunkLoader getLoader(@Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache cache, @Nonnull Store store) { + return new IndexedStorageChunkStorageProvider.IndexedStorageChunkLoader(store, cache, this.flushOnWrite); + } + + @Nonnull + public IChunkSaver getSaver(@Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache cache, @Nonnull Store store) { + return new IndexedStorageChunkStorageProvider.IndexedStorageChunkSaver(store, cache, this.flushOnWrite); } @Nonnull @@ -116,10 +122,6 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider private final Long2ObjectConcurrentHashMap cache = new Long2ObjectConcurrentHashMap<>(true, ChunkUtil.NOT_FOUND); private Path path; - public static ResourceType getResourceType() { - return Universe.get().getIndexedStorageCacheResourceType(); - } - @Nonnull public Long2ObjectConcurrentHashMap getCache() { return this.cache; @@ -286,35 +288,21 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider } } - public static class IndexedStorageCacheSetupSystem extends StoreSystem { - @Nullable - @Override - public SystemGroup getGroup() { - return ChunkStore.INIT_GROUP; - } - - @Override - public void onSystemAddedToStore(@Nonnull Store store) { - World world = store.getExternalData().getWorld(); - store.getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()).path = world.getSavePath().resolve("chunks"); - } - - @Override - public void onSystemRemovedFromStore(@Nonnull Store store) { - } - } - public static class IndexedStorageChunkLoader extends BufferChunkLoader implements MetricProvider { + @Nonnull + private final IndexedStorageChunkStorageProvider.IndexedStorageCache cache; private final boolean flushOnWrite; - public IndexedStorageChunkLoader(@Nonnull Store store, boolean flushOnWrite) { + public IndexedStorageChunkLoader( + @Nonnull Store store, @Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache cache, boolean flushOnWrite + ) { super(store); + this.cache = cache; this.flushOnWrite = flushOnWrite; } @Override public void close() throws IOException { - this.getStore().getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()).close(); } @Nonnull @@ -325,10 +313,8 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider int localX = x & 31; int localZ = z & 31; int index = ChunkUtil.indexColumn(localX, localZ); - IndexedStorageChunkStorageProvider.IndexedStorageCache indexedStorageCache = this.getStore() - .getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()); return CompletableFuture.supplyAsync(SneakyThrow.sneakySupplier(() -> { - IndexedStorageFile chunks = indexedStorageCache.getOrTryOpen(regionX, regionZ, this.flushOnWrite); + IndexedStorageFile chunks = this.cache.getOrTryOpen(regionX, regionZ, this.flushOnWrite); return chunks == null ? null : chunks.readBlob(index); })); } @@ -336,7 +322,7 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider @Nonnull @Override public LongSet getIndexes() throws IOException { - return this.getStore().getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()).getIndexes(); + return this.cache.getIndexes(); } @Nullable @@ -344,23 +330,25 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider public MetricResults toMetricResults() { return this.getStore().getExternalData().getSaver() instanceof IndexedStorageChunkStorageProvider.IndexedStorageChunkSaver ? null - : this.getStore().getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()).toMetricResults(); + : this.cache.toMetricResults(); } } public static class IndexedStorageChunkSaver extends BufferChunkSaver implements MetricProvider { + @Nonnull + private final IndexedStorageChunkStorageProvider.IndexedStorageCache cache; private final boolean flushOnWrite; - protected IndexedStorageChunkSaver(@Nonnull Store store, boolean flushOnWrite) { + protected IndexedStorageChunkSaver( + @Nonnull Store store, @Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache cache, boolean flushOnWrite + ) { super(store); + this.cache = cache; this.flushOnWrite = flushOnWrite; } @Override public void close() throws IOException { - IndexedStorageChunkStorageProvider.IndexedStorageCache indexedStorageCache = this.getStore() - .getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()); - indexedStorageCache.close(); } @Nonnull @@ -371,10 +359,8 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider int localX = x & 31; int localZ = z & 31; int index = ChunkUtil.indexColumn(localX, localZ); - IndexedStorageChunkStorageProvider.IndexedStorageCache indexedStorageCache = this.getStore() - .getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()); return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> { - IndexedStorageFile chunks = indexedStorageCache.getOrCreate(regionX, regionZ, this.flushOnWrite); + IndexedStorageFile chunks = this.cache.getOrCreate(regionX, regionZ, this.flushOnWrite); chunks.writeBlob(index, buffer); })); } @@ -387,10 +373,8 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider int localX = x & 31; int localZ = z & 31; int index = ChunkUtil.indexColumn(localX, localZ); - IndexedStorageChunkStorageProvider.IndexedStorageCache indexedStorageCache = this.getStore() - .getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()); return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> { - IndexedStorageFile chunks = indexedStorageCache.getOrTryOpen(regionX, regionZ, this.flushOnWrite); + IndexedStorageFile chunks = this.cache.getOrTryOpen(regionX, regionZ, this.flushOnWrite); if (chunks != null) { chunks.removeBlob(index); } @@ -400,17 +384,17 @@ public class IndexedStorageChunkStorageProvider implements IChunkStorageProvider @Nonnull @Override public LongSet getIndexes() throws IOException { - return this.getStore().getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()).getIndexes(); + return this.cache.getIndexes(); } @Override public void flush() throws IOException { - this.getStore().getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()).flush(); + this.cache.flush(); } @Override public MetricResults toMetricResults() { - return this.getStore().getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()).toMetricResults(); + return this.cache.toMetricResults(); } } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/MigrationChunkStorageProvider.java b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/MigrationChunkStorageProvider.java index 124cccb0..9ec57078 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/MigrationChunkStorageProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/MigrationChunkStorageProvider.java @@ -16,8 +16,9 @@ import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.function.Function; import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; -public class MigrationChunkStorageProvider implements IChunkStorageProvider { +public class MigrationChunkStorageProvider implements IChunkStorageProvider { public static final String ID = "Migration"; @Nonnull public static final BuilderCodec CODEC = BuilderCodec.builder( @@ -26,7 +27,7 @@ public class MigrationChunkStorageProvider implements IChunkStorageProvider { .documentation( "A provider that combines multiple storage providers in a chain to assist with migrating worlds between storage formats.\n\nCan also be used to set storage to load chunks but block saving them if combined with the **Empty** storage provider" ) - .append( + .[]>append( new KeyedCodec<>("Loaders", new ArrayCodec<>(IChunkStorageProvider.CODEC, IChunkStorageProvider[]::new)), (migration, o) -> migration.from = o, migration -> migration.from @@ -35,12 +36,12 @@ public class MigrationChunkStorageProvider implements IChunkStorageProvider { "A list of storage providers to use as chunk loaders.\n\nEach loader will be tried in order to load a chunk, returning the chunk if found otherwise trying the next loaded until found or none are left." ) .add() - .append(new KeyedCodec<>("Saver", IChunkStorageProvider.CODEC), (migration, o) -> migration.to = o, migration -> migration.to) + .>append(new KeyedCodec<>("Saver", IChunkStorageProvider.CODEC), (migration, o) -> migration.to = o, migration -> migration.to) .documentation("The storage provider to use to save chunks.") .add() .build(); - private IChunkStorageProvider[] from; - private IChunkStorageProvider to; + private IChunkStorageProvider[] from; + private IChunkStorageProvider to; public MigrationChunkStorageProvider() { } @@ -50,22 +51,40 @@ public class MigrationChunkStorageProvider implements IChunkStorageProvider { this.to = to; } + public MigrationChunkStorageProvider.MigrationData initialize(@NonNullDecl Store store) throws IOException { + MigrationChunkStorageProvider.MigrationData data = new MigrationChunkStorageProvider.MigrationData(); + data.loaderData = new Object[this.from.length]; + + for (int i = 0; i < this.from.length; i++) { + data.loaderData[i] = this.from[i].initialize(store); + } + + data.saverData = this.to.initialize(store); + return data; + } + + public void close(@NonNullDecl MigrationChunkStorageProvider.MigrationData migrationData, @NonNullDecl Store store) throws IOException { + for (int i = 0; i < this.from.length; i++) { + ((IChunkStorageProvider)this.from[i]).close(migrationData.loaderData[i], store); + } + + ((IChunkStorageProvider)this.to).close(migrationData.saverData, store); + } + @Nonnull - @Override - public IChunkLoader getLoader(@Nonnull Store store) throws IOException { + public IChunkLoader getLoader(@Nonnull MigrationChunkStorageProvider.MigrationData migrationData, @Nonnull Store store) throws IOException { IChunkLoader[] loaders = new IChunkLoader[this.from.length]; for (int i = 0; i < this.from.length; i++) { - loaders[i] = this.from[i].getLoader(store); + loaders[i] = ((IChunkStorageProvider)this.from[i]).getLoader(migrationData.loaderData[i], store); } return new MigrationChunkStorageProvider.MigrationChunkLoader(loaders); } @Nonnull - @Override - public IChunkSaver getSaver(@Nonnull Store store) throws IOException { - return this.to.getSaver(store); + public IChunkSaver getSaver(@Nonnull MigrationChunkStorageProvider.MigrationData migrationData, @Nonnull Store store) throws IOException { + return ((IChunkStorageProvider)this.to).getSaver(migrationData.saverData, store); } @Nonnull @@ -138,4 +157,9 @@ public class MigrationChunkStorageProvider implements IChunkStorageProvider { return indexes; } } + + public static class MigrationData { + private Object[] loaderData; + private Object saverData; + } } diff --git a/src/com/hypixel/hytale/server/core/universe/world/storage/provider/RocksDbChunkStorageProvider.java b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/RocksDbChunkStorageProvider.java new file mode 100644 index 00000000..8adfdb73 --- /dev/null +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/provider/RocksDbChunkStorageProvider.java @@ -0,0 +1,229 @@ +package com.hypixel.hytale.server.core.universe.world.storage.provider; + +import com.hypixel.hytale.codec.builder.BuilderCodec; +import com.hypixel.hytale.component.Store; +import com.hypixel.hytale.math.util.ChunkUtil; +import com.hypixel.hytale.server.core.universe.world.storage.BufferChunkLoader; +import com.hypixel.hytale.server.core.universe.world.storage.BufferChunkSaver; +import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; +import com.hypixel.hytale.server.core.universe.world.storage.IChunkLoader; +import com.hypixel.hytale.server.core.universe.world.storage.IChunkSaver; +import com.hypixel.hytale.sneakythrow.SneakyThrow; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ForkJoinPool; +import javax.annotation.Nonnull; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; +import org.rocksdb.BlockBasedTableConfig; +import org.rocksdb.BloomFilter; +import org.rocksdb.ColumnFamilyDescriptor; +import org.rocksdb.ColumnFamilyHandle; +import org.rocksdb.ColumnFamilyOptions; +import org.rocksdb.CompactionPriority; +import org.rocksdb.CompactionStyle; +import org.rocksdb.CompressionType; +import org.rocksdb.DBOptions; +import org.rocksdb.FlushOptions; +import org.rocksdb.IndexType; +import org.rocksdb.Options; +import org.rocksdb.RocksDB; +import org.rocksdb.RocksDBException; +import org.rocksdb.RocksIterator; + +public class RocksDbChunkStorageProvider implements IChunkStorageProvider { + public static final String ID = "RocksDb"; + public static final BuilderCodec CODEC = BuilderCodec.builder( + RocksDbChunkStorageProvider.class, RocksDbChunkStorageProvider::new + ) + .build(); + + public RocksDbChunkStorageProvider.RocksDbResource initialize(@NonNullDecl Store store) throws IOException { + try { + RocksDbChunkStorageProvider.RocksDbResource var9; + try ( + Options options = new Options() + .setCreateIfMissing(true) + .setCreateMissingColumnFamilies(true) + .setIncreaseParallelism(ForkJoinPool.getCommonPoolParallelism()); + BloomFilter bloomFilter = new BloomFilter(9.9); + ColumnFamilyOptions chunkColumnOptions = new ColumnFamilyOptions() + .setCompressionType(CompressionType.LZ4_COMPRESSION) + .setBottommostCompressionType(CompressionType.ZSTD_COMPRESSION) + .setTableFormatConfig( + new BlockBasedTableConfig().setIndexType(IndexType.kHashSearch).setFilterPolicy(bloomFilter).setOptimizeFiltersForMemory(true) + ) + .setCompactionStyle(CompactionStyle.LEVEL) + .optimizeLevelStyleCompaction(134217728L) + .setLevelCompactionDynamicLevelBytes(true) + .setCompactionPriority(CompactionPriority.MinOverlappingRatio) + .useFixedLengthPrefixExtractor(8) + .setEnableBlobFiles(true) + .setEnableBlobGarbageCollection(true) + .setBlobCompressionType(CompressionType.ZSTD_COMPRESSION); + DBOptions dbOptions = new DBOptions(options); + ) { + RocksDbChunkStorageProvider.RocksDbResource resource = new RocksDbChunkStorageProvider.RocksDbResource(); + List columns = List.of( + new ColumnFamilyDescriptor("default".getBytes(StandardCharsets.UTF_8)), + new ColumnFamilyDescriptor("chunks".getBytes(StandardCharsets.UTF_8), chunkColumnOptions) + ); + ArrayList handles = new ArrayList<>(); + resource.db = RocksDB.open(dbOptions, String.valueOf(store.getExternalData().getWorld().getSavePath().resolve("db")), columns, handles); + resource.chunkColumn = handles.get(1); + handles.get(0).close(); + var9 = resource; + } + + return var9; + } catch (RocksDBException var18) { + throw SneakyThrow.sneakyThrow(var18); + } + } + + public void close(@NonNullDecl RocksDbChunkStorageProvider.RocksDbResource resource, @NonNullDecl Store store) throws IOException { + try { + resource.db.syncWal(); + } catch (RocksDBException var4) { + throw SneakyThrow.sneakyThrow(var4); + } + + resource.chunkColumn.close(); + resource.db.close(); + resource.db = null; + } + + @Nonnull + public IChunkLoader getLoader(@Nonnull RocksDbChunkStorageProvider.RocksDbResource resource, @Nonnull Store store) throws IOException { + return new RocksDbChunkStorageProvider.Loader(store, resource); + } + + @Nonnull + public IChunkSaver getSaver(@Nonnull RocksDbChunkStorageProvider.RocksDbResource resource, @Nonnull Store store) throws IOException { + return new RocksDbChunkStorageProvider.Saver(store, resource); + } + + private static byte[] toKey(int x, int z) { + return new byte[]{(byte)(x >>> 24), (byte)(x >>> 16), (byte)(x >>> 8), (byte)x, (byte)(z >>> 24), (byte)(z >>> 16), (byte)(z >>> 8), (byte)z}; + } + + private static int keyToX(byte[] key) { + return (key[0] & 0xFF) << 24 | (key[1] & 0xFF) << 16 | (key[2] & 0xFF) << 8 | key[3] & 0xFF; + } + + private static int keyToZ(byte[] key) { + return (key[4] & 0xFF) << 24 | (key[5] & 0xFF) << 16 | (key[6] & 0xFF) << 8 | key[7] & 0xFF; + } + + public static class Loader extends BufferChunkLoader implements IChunkLoader { + private final RocksDbChunkStorageProvider.RocksDbResource db; + + public Loader(Store store, RocksDbChunkStorageProvider.RocksDbResource db) { + super(store); + this.db = db; + } + + @Override + public CompletableFuture loadBuffer(int x, int z) { + return CompletableFuture.supplyAsync(SneakyThrow.sneakySupplier(() -> { + byte[] key = RocksDbChunkStorageProvider.toKey(x, z); + byte[] data = this.db.db.get(this.db.chunkColumn, key); + return data == null ? null : ByteBuffer.wrap(data); + })); + } + + @Nonnull + @Override + public LongSet getIndexes() throws IOException { + LongOpenHashSet set = new LongOpenHashSet(); + + try (RocksIterator iter = this.db.db.newIterator(this.db.chunkColumn)) { + iter.seekToFirst(); + + while (iter.isValid()) { + byte[] key = iter.key(); + set.add(ChunkUtil.indexChunk(RocksDbChunkStorageProvider.keyToX(key), RocksDbChunkStorageProvider.keyToZ(key))); + iter.next(); + } + } + + return set; + } + + @Override + public void close() throws IOException { + } + } + + public static class RocksDbResource { + public RocksDB db; + public ColumnFamilyHandle chunkColumn; + } + + public static class Saver extends BufferChunkSaver implements IChunkSaver { + private final RocksDbChunkStorageProvider.RocksDbResource db; + + public Saver(Store store, RocksDbChunkStorageProvider.RocksDbResource db) { + super(store); + this.db = db; + } + + @Nonnull + @Override + public CompletableFuture saveBuffer(int x, int z, @Nonnull ByteBuffer buffer) { + return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> { + if (buffer.hasArray()) { + this.db.db.put(this.db.chunkColumn, RocksDbChunkStorageProvider.toKey(x, z), buffer.array()); + } else { + byte[] buf = new byte[buffer.remaining()]; + buffer.get(buf); + this.db.db.put(this.db.chunkColumn, RocksDbChunkStorageProvider.toKey(x, z), buf); + } + })); + } + + @Nonnull + @Override + public CompletableFuture removeBuffer(int x, int z) { + return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> this.db.db.delete(this.db.chunkColumn, RocksDbChunkStorageProvider.toKey(x, z)))); + } + + @Nonnull + @Override + public LongSet getIndexes() throws IOException { + LongOpenHashSet set = new LongOpenHashSet(); + + try (RocksIterator iter = this.db.db.newIterator(this.db.chunkColumn)) { + iter.seekToFirst(); + + while (iter.isValid()) { + byte[] key = iter.key(); + set.add(ChunkUtil.indexChunk(RocksDbChunkStorageProvider.keyToX(key), RocksDbChunkStorageProvider.keyToZ(key))); + iter.next(); + } + } + + return set; + } + + @Override + public void flush() throws IOException { + try { + try (FlushOptions opts = new FlushOptions().setWaitForFlush(true)) { + this.db.db.flush(opts); + } + } catch (RocksDBException var6) { + throw SneakyThrow.sneakyThrow(var6); + } + } + + @Override + public void close() throws IOException { + } + } +} diff --git a/src/com/hypixel/hytale/server/core/universe/world/storage/resources/DiskResourceStorageProvider.java b/src/com/hypixel/hytale/server/core/universe/world/storage/resources/DiskResourceStorageProvider.java index 27f48a90..f178ef72 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/storage/resources/DiskResourceStorageProvider.java +++ b/src/com/hypixel/hytale/server/core/universe/world/storage/resources/DiskResourceStorageProvider.java @@ -5,6 +5,7 @@ import com.hypixel.hytale.codec.ExtraInfo; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.codec.util.RawJsonReader; +import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.component.ComponentRegistry; import com.hypixel.hytale.component.IResourceStorage; import com.hypixel.hytale.component.Resource; @@ -46,7 +47,12 @@ public class DiskResourceStorageProvider implements IResourceStorageProvider { @Nonnull @Override public IResourceStorage getResourceStorage(@Nonnull World world) { - return new DiskResourceStorageProvider.DiskResourceStorage(world.getSavePath().resolve(this.path)); + Path resolved = PathUtil.resolvePathWithinDir(world.getSavePath(), this.path); + if (resolved == null) { + throw new IllegalStateException("Resource storage path must be within world directory: " + this.path); + } else { + return new DiskResourceStorageProvider.DiskResourceStorage(resolved); + } } @Nonnull 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/worldlocationcondition/WorldLocationCondition.java b/src/com/hypixel/hytale/server/core/universe/world/worldlocationcondition/WorldLocationCondition.java index 404f37e0..cb262746 100644 --- a/src/com/hypixel/hytale/server/core/universe/world/worldlocationcondition/WorldLocationCondition.java +++ b/src/com/hypixel/hytale/server/core/universe/world/worldlocationcondition/WorldLocationCondition.java @@ -6,10 +6,12 @@ import com.hypixel.hytale.server.core.universe.world.World; import javax.annotation.Nonnull; public abstract class WorldLocationCondition { + @Nonnull public static final CodecMapCodec CODEC = new CodecMapCodec<>("Type"); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(WorldLocationCondition.class).build(); - public abstract boolean test(World var1, int var2, int var3, int var4); + public abstract boolean test(@Nonnull World var1, int var2, int var3, int var4); @Override public abstract boolean equals(Object var1); 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/update/UpdateModule.java b/src/com/hypixel/hytale/server/core/update/UpdateModule.java index a0c4d58c..4337b7af 100644 --- a/src/com/hypixel/hytale/server/core/update/UpdateModule.java +++ b/src/com/hypixel/hytale/server/core/update/UpdateModule.java @@ -6,10 +6,10 @@ import com.hypixel.hytale.common.util.java.ManifestUtil; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.Constants; import com.hypixel.hytale.server.core.HytaleServer; -import com.hypixel.hytale.server.core.HytaleServerConfig; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.ShutdownReason; import com.hypixel.hytale.server.core.auth.ServerAuthManager; +import com.hypixel.hytale.server.core.config.UpdateConfig; import com.hypixel.hytale.server.core.permissions.PermissionsModule; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; @@ -31,10 +31,13 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; public class UpdateModule extends JavaPlugin { + @Nonnull public static final PluginManifest MANIFEST = PluginManifest.corePlugin(UpdateModule.class).build(); + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); public static final boolean KILL_SWITCH_ENABLED = SystemUtil.getEnvBoolean("HYTALE_DISABLE_UPDATES"); private static UpdateModule instance; + @Nonnull private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { Thread t = new Thread(r, "UpdateChecker"); t.setDaemon(true); @@ -83,7 +86,7 @@ public class UpdateModule extends JavaPlugin { } if (this.shouldEnableUpdateChecker()) { - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); int intervalSeconds = config.getCheckIntervalSeconds(); LOGGER.at(Level.INFO).log("Update checker enabled (interval: %ds)", intervalSeconds); this.updateCheckTask = this.scheduler.scheduleAtFixedRate(this::performUpdateCheck, 60L, intervalSeconds, TimeUnit.SECONDS); @@ -93,9 +96,9 @@ public class UpdateModule extends JavaPlugin { private synchronized void startAutoApplyTaskIfNeeded() { if (this.autoApplyTask == null) { - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); - HytaleServerConfig.UpdateConfig.AutoApplyMode autoApplyMode = config.getAutoApplyMode(); - if (autoApplyMode != HytaleServerConfig.UpdateConfig.AutoApplyMode.DISABLED) { + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + UpdateConfig.AutoApplyMode autoApplyMode = config.getAutoApplyMode(); + if (autoApplyMode != UpdateConfig.AutoApplyMode.DISABLED) { LOGGER.at(Level.INFO).log("Starting auto-apply task (mode: %s, delay: %d min)", autoApplyMode, config.getAutoApplyDelayMinutes()); this.autoApplyTask = this.scheduler.scheduleAtFixedRate(this::performAutoApplyCheck, 0L, 60L, TimeUnit.SECONDS); } @@ -216,7 +219,7 @@ public class UpdateModule extends JavaPlugin { LOGGER.at(Level.INFO).log("Update checker disabled: singleplayer mode"); return false; } else { - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); if (!config.isEnabled()) { LOGGER.at(Level.INFO).log("Update checker disabled: disabled in config"); return false; @@ -263,12 +266,12 @@ public class UpdateModule extends JavaPlugin { LOGGER.at(Level.FINE).log("Already running latest version: %s", currentVersion); } else { this.logUpdateAvailable(currentVersion, manifest.version); - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); if (config.isNotifyPlayersOnAvailable()) { this.notifyPlayers(manifest.version); } - if (config.getAutoApplyMode() != HytaleServerConfig.UpdateConfig.AutoApplyMode.DISABLED) { + if (config.getAutoApplyMode() != UpdateConfig.AutoApplyMode.DISABLED) { LOGGER.at(Level.INFO).log("Auto-downloading update %s...", manifest.version); this.autoDownloadUpdate(updateService, manifest); } @@ -317,8 +320,8 @@ public class UpdateModule extends JavaPlugin { private void logUpdateAvailable(@Nullable String currentVersion, @Nonnull String latestVersion) { LOGGER.at(Level.INFO).log("Update available: %s (current: %s)", latestVersion, currentVersion); - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); - if (config.getAutoApplyMode() == HytaleServerConfig.UpdateConfig.AutoApplyMode.DISABLED) { + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + if (config.getAutoApplyMode() == UpdateConfig.AutoApplyMode.DISABLED) { LOGGER.at(Level.INFO).log("Run '/update download' to stage the update"); } } @@ -338,16 +341,16 @@ public class UpdateModule extends JavaPlugin { } private void checkAutoApply(@Nonnull String stagedVersion) { - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); - HytaleServerConfig.UpdateConfig.AutoApplyMode mode = config.getAutoApplyMode(); - if (mode != HytaleServerConfig.UpdateConfig.AutoApplyMode.DISABLED) { + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + UpdateConfig.AutoApplyMode mode = config.getAutoApplyMode(); + if (mode != UpdateConfig.AutoApplyMode.DISABLED) { Universe universe = Universe.get(); if (universe != null) { int playerCount = universe.getPlayers().size(); if (playerCount == 0) { LOGGER.at(Level.INFO).log("No players online - auto-applying update %s", stagedVersion); this.triggerAutoApply(); - } else if (mode != HytaleServerConfig.UpdateConfig.AutoApplyMode.WHEN_EMPTY) { + } else if (mode != UpdateConfig.AutoApplyMode.WHEN_EMPTY) { int delayMinutes = config.getAutoApplyDelayMinutes(); long now = System.currentTimeMillis(); long applyTime = now + delayMinutes * 60 * 1000L; diff --git a/src/com/hypixel/hytale/server/core/update/UpdateService.java b/src/com/hypixel/hytale/server/core/update/UpdateService.java index 22141926..da062ecd 100644 --- a/src/com/hypixel/hytale/server/core/update/UpdateService.java +++ b/src/com/hypixel/hytale/server/core/update/UpdateService.java @@ -8,9 +8,9 @@ import com.hypixel.hytale.codec.util.RawJsonReader; import com.hypixel.hytale.common.util.java.ManifestUtil; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.HytaleServer; -import com.hypixel.hytale.server.core.HytaleServerConfig; import com.hypixel.hytale.server.core.auth.AuthConfig; import com.hypixel.hytale.server.core.auth.ServerAuthManager; +import com.hypixel.hytale.server.core.config.UpdateConfig; import com.hypixel.hytale.server.core.util.ServiceHttpClientFactory; import com.hypixel.hytale.server.core.util.io.FileUtil; import java.io.IOException; @@ -238,7 +238,7 @@ public class UpdateService { @Nonnull public static String getEffectivePatchline() { - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); String patchline = config.getPatchline(); if (patchline != null && !patchline.isEmpty()) { return patchline; diff --git a/src/com/hypixel/hytale/server/core/update/command/UpdateApplyCommand.java b/src/com/hypixel/hytale/server/core/update/command/UpdateApplyCommand.java index ea667483..2c1bf2a3 100644 --- a/src/com/hypixel/hytale/server/core/update/command/UpdateApplyCommand.java +++ b/src/com/hypixel/hytale/server/core/update/command/UpdateApplyCommand.java @@ -2,13 +2,13 @@ package com.hypixel.hytale.server.core.update.command; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.HytaleServer; -import com.hypixel.hytale.server.core.HytaleServerConfig; import com.hypixel.hytale.server.core.Message; -import com.hypixel.hytale.server.core.Options; import com.hypixel.hytale.server.core.ShutdownReason; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.arguments.system.FlagArg; import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase; +import com.hypixel.hytale.server.core.config.BackupConfig; +import com.hypixel.hytale.server.core.config.UpdateConfig; import com.hypixel.hytale.server.core.universe.Universe; import com.hypixel.hytale.server.core.update.UpdateService; import com.hypixel.hytale.server.core.util.io.FileUtil; @@ -20,9 +20,13 @@ import java.util.logging.Level; import javax.annotation.Nonnull; public class UpdateApplyCommand extends CommandBase { + @Nonnull private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + @Nonnull private static final Message MSG_NO_STAGED = Message.translation("server.commands.update.no_staged"); + @Nonnull private static final Message MSG_BACKUP_FAILED = Message.translation("server.commands.update.backup_failed"); + @Nonnull private final FlagArg confirmFlag = this.withFlagArg("confirm", "server.commands.update.apply.confirm.desc"); private static final String[] CONFIG_FILES = new String[]{"config.json", "permissions.json", "bans.json", "whitelist.json"}; @@ -45,11 +49,12 @@ public class UpdateApplyCommand extends CommandBase { context.sendMessage(Message.translation("server.commands.update.applying").param("version", stagedVersion)); } - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); try { this.backupCurrentFiles(); - if (config.isRunBackupBeforeUpdate() && Options.getOptionSet().has(Options.BACKUP_DIRECTORY)) { + BackupConfig backupConfig = HytaleServer.get().getConfig().getBackupConfig(); + if (config.isRunBackupBeforeUpdate() && backupConfig.getDirectory() != null) { Universe universe = Universe.get(); if (universe != null) { LOGGER.at(Level.INFO).log("Running server backup before update..."); @@ -57,14 +62,14 @@ public class UpdateApplyCommand extends CommandBase { LOGGER.at(Level.INFO).log("Server backup completed"); } } else if (config.isRunBackupBeforeUpdate()) { - LOGGER.at(Level.WARNING).log("RunBackupBeforeUpdate is enabled but backups are not configured (no --backup-dir)"); + LOGGER.at(Level.WARNING).log("RunBackupBeforeUpdate is enabled but backups are not configured"); } if (config.isBackupConfigBeforeUpdate()) { this.backupConfigFiles(); } - } catch (IOException var5) { - LOGGER.at(Level.SEVERE).withCause(var5).log("Failed to create backups before update"); + } catch (IOException var6) { + LOGGER.at(Level.SEVERE).withCause(var6).log("Failed to create backups before update"); context.sendMessage(MSG_BACKUP_FAILED); return; } diff --git a/src/com/hypixel/hytale/server/core/update/command/UpdatePatchlineCommand.java b/src/com/hypixel/hytale/server/core/update/command/UpdatePatchlineCommand.java index fe993d3c..865fe56e 100644 --- a/src/com/hypixel/hytale/server/core/update/command/UpdatePatchlineCommand.java +++ b/src/com/hypixel/hytale/server/core/update/command/UpdatePatchlineCommand.java @@ -1,12 +1,12 @@ package com.hypixel.hytale.server.core.update.command; import com.hypixel.hytale.server.core.HytaleServer; -import com.hypixel.hytale.server.core.HytaleServerConfig; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg; import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes; import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase; +import com.hypixel.hytale.server.core.config.UpdateConfig; import com.hypixel.hytale.server.core.update.UpdateService; import javax.annotation.Nonnull; @@ -33,7 +33,7 @@ public class UpdatePatchlineCommand extends CommandBase { @Override protected void executeSync(@Nonnull CommandContext context) { String newPatchline = this.patchlineArg.get(context); - HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); + UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig(); config.setPatchline(newPatchline); context.sendMessage(Message.translation("server.commands.update.patchline.changed").param("patchline", newPatchline)); } diff --git a/src/com/hypixel/hytale/server/core/util/BsonUtil.java b/src/com/hypixel/hytale/server/core/util/BsonUtil.java index fa199587..9ee352a4 100644 --- a/src/com/hypixel/hytale/server/core/util/BsonUtil.java +++ b/src/com/hypixel/hytale/server/core/util/BsonUtil.java @@ -9,6 +9,7 @@ import com.hypixel.hytale.common.util.ExceptionUtil; import com.hypixel.hytale.common.util.PathUtil; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.util.io.ByteBufUtil; +import com.hypixel.hytale.server.core.util.io.FileUtil; import com.hypixel.hytale.sneakythrow.SneakyThrow; import io.netty.buffer.ByteBuf; import java.io.BufferedWriter; @@ -17,7 +18,6 @@ import java.io.StringWriter; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributes; import java.util.concurrent.CompletableFuture; @@ -80,26 +80,6 @@ public class BsonUtil { ByteBufUtil.writeByteArray(buf, writeToBytes(doc)); } - @Nonnull - public static CompletableFuture writeDocumentBytes(@Nonnull Path file, BsonDocument document) { - try { - if (Files.isRegularFile(file)) { - Path resolve = file.resolveSibling(file.getFileName() + ".bak"); - Files.move(file, resolve, StandardCopyOption.REPLACE_EXISTING); - } - - byte[] bytes; - try (BasicOutputBuffer bob = new BasicOutputBuffer()) { - codec.encode(new BsonBinaryWriter(bob), document, encoderContext); - bytes = bob.toByteArray(); - } - - return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> Files.write(file, bytes))); - } catch (IOException var8) { - return CompletableFuture.failedFuture(var8); - } - } - @Nonnull public static CompletableFuture writeDocument(@Nonnull Path file, BsonDocument document) { return writeDocument(file, document, true); @@ -113,13 +93,8 @@ public class BsonUtil { Files.createDirectories(parent); } - if (backup && Files.isRegularFile(file)) { - Path resolve = file.resolveSibling(file.getFileName() + ".bak"); - Files.move(file, resolve, StandardCopyOption.REPLACE_EXISTING); - } - String json = toJson(document); - return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> Files.writeString(file, json))); + return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> FileUtil.writeStringAtomic(file, json, backup))); } catch (IOException var5) { return CompletableFuture.failedFuture(var5); } @@ -227,18 +202,21 @@ public class BsonUtil { Files.createDirectories(parent); } - if (Files.isRegularFile(path)) { - Path resolve = path.resolveSibling(path.getFileName() + ".bak"); - Files.move(path, resolve, StandardCopyOption.REPLACE_EXISTING); - } - ExtraInfo extraInfo = ExtraInfo.THREAD_LOCAL.get(); BsonValue bsonValue = codec.encode(value, extraInfo); extraInfo.getValidationResults().logOrThrowValidatorExceptions(logger); BsonDocument document = bsonValue.asDocument(); + Path tmpPath = path.resolveSibling(path.getFileName() + ".tmp"); + Path bakPath = path.resolveSibling(path.getFileName() + ".bak"); - try (BufferedWriter writer = Files.newBufferedWriter(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { + try (BufferedWriter writer = Files.newBufferedWriter(tmpPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { BSON_DOCUMENT_CODEC.encode(new JsonWriter(writer, SETTINGS), document, encoderContext); } + + if (Files.isRegularFile(path)) { + FileUtil.atomicMove(path, bakPath); + } + + FileUtil.atomicMove(tmpPath, path); } } diff --git a/src/com/hypixel/hytale/server/core/util/DumpUtil.java b/src/com/hypixel/hytale/server/core/util/DumpUtil.java index eace33d6..95cb36ea 100644 --- a/src/com/hypixel/hytale/server/core/util/DumpUtil.java +++ b/src/com/hypixel/hytale/server/core/util/DumpUtil.java @@ -1,6 +1,5 @@ package com.hypixel.hytale.server.core.util; -import com.hypixel.fastutil.longs.Long2ObjectConcurrentHashMap; import com.hypixel.hytale.common.plugin.PluginManifest; import com.hypixel.hytale.common.util.FormatUtil; import com.hypixel.hytale.common.util.StringUtil; @@ -10,7 +9,6 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.metric.ArchetypeChunkData; import com.hypixel.hytale.component.system.ISystem; import com.hypixel.hytale.logger.backend.HytaleFileHandler; -import com.hypixel.hytale.math.util.ChunkUtil; import com.hypixel.hytale.math.util.MathUtil; import com.hypixel.hytale.metrics.InitStackThread; import com.hypixel.hytale.metrics.MetricsRegistry; @@ -33,14 +31,11 @@ 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.storage.provider.IndexedStorageChunkStorageProvider; import com.hypixel.hytale.server.core.universe.world.worldgen.WorldGenTimingsCollector; -import com.hypixel.hytale.storage.IndexedStorageFile; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOException; @@ -618,9 +613,9 @@ public class DumpUtil { printComponentStore(writer, width, height, "Chunks", startNanos, world.getChunkStore().getStore()); printComponentStore(writer, width, height, "Entities", startNanos, world.getEntityStore().getStore()); }, world).orTimeout(30L, TimeUnit.SECONDS).join(); - } catch (CompletionException var41) { - if (!(var41.getCause() instanceof TimeoutException)) { - var41.printStackTrace(); + } catch (CompletionException var40) { + if (!(var40.getCause() instanceof TimeoutException)) { + var40.printStackTrace(); writer.println("\t\tFAILED TO DUMP COMPONENT STORES! EXCEPTION!"); } else { writer.println("\t\tFAILED TO DUMP COMPONENT STORES! TIMEOUT!"); @@ -644,35 +639,6 @@ public class DumpUtil { } else { writer.println("\t\tNo Timings Data Collected!"); } - - IndexedStorageChunkStorageProvider.IndexedStorageCache storageCache = world.getChunkStore() - .getStore() - .getResource(IndexedStorageChunkStorageProvider.IndexedStorageCache.getResourceType()); - if (storageCache != null) { - Long2ObjectConcurrentHashMap cache = storageCache.getCache(); - writer.println(); - writer.println("\tIndexed Storage Cache:"); - - for (Entry entry : cache.long2ObjectEntrySet()) { - long key = entry.getLongKey(); - writer.println("\t\t" + ChunkUtil.xOfChunkIndex(key) + ", " + ChunkUtil.zOfChunkIndex(key)); - IndexedStorageFile storageFile = entry.getValue(); - - try { - writer.println("\t\t- Size: " + FormatUtil.bytesToString(storageFile.size())); - } catch (IOException var40) { - writer.println("\t\t- Size: ERROR: " + var40.getMessage()); - } - - writer.println("\t\t- Blob Count: " + storageFile.keys().size()); - int segmentSize = storageFile.segmentSize(); - int segmentCount = storageFile.segmentCount(); - writer.println("\t\t- Segment Size: " + segmentSize); - writer.println("\t\t- Segment Count: " + segmentCount); - writer.println("\t\t- Segment Used %: " + (double)(segmentCount * 100) / segmentSize + "%"); - writer.println("\t\t- " + storageFile); - } - } } ); List playersNotInWorld = Universe.get().getPlayers().stream().filter(refx -> refx.getReference() == null).toList(); diff --git a/src/com/hypixel/hytale/server/core/util/MessageUtil.java b/src/com/hypixel/hytale/server/core/util/MessageUtil.java index b635f27d..58c44597 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: + label171: 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 label171; case "decimal": case null: default: @@ -177,7 +183,7 @@ public class MessageUtil { case LongParamValue l -> Long.toString(l.value); default -> ""; }; - break label147; + break label171; } case "plural": if (options != null) { @@ -193,6 +199,40 @@ public class MessageUtil { selected = pluralTexts.isEmpty() ? "" : pluralTexts.values().iterator().next(); } + 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 = ""; + } + break; + case "select": + if (options != null) { + Map selectOptions = parseSelectOptions(options); + String selectKey = replacement.toString(); + String selected; + if (selectOptions.containsKey(selectKey)) { + selected = selectOptions.get(selectKey); + } else if (selectOptions.containsKey("other")) { + selected = selectOptions.get("other"); + } else { + selected = selectOptions.isEmpty() ? "" : selectOptions.values().iterator().next(); + } + formattedReplacement = formatText(selected, params, messageParams); } case null: @@ -434,4 +474,81 @@ public class MessageUtil { private static String getKoreanPluralCategory(int n) { return "other"; } + + @Nonnull + private static Map parseSelectOptions(@Nonnull String options) { + HashMap result = new HashMap<>(); + int i = 0; + int len = options.length(); + + while (i < len) { + while (i < len && Character.isWhitespace(options.charAt(i))) { + i++; + } + + if (i >= len) { + break; + } + + int keyStart = i; + + while (i < len && !Character.isWhitespace(options.charAt(i)) && options.charAt(i) != '{') { + i++; + } + + if (i == keyStart) { + break; + } + + String key = options.substring(keyStart, i); + + while (i < len && Character.isWhitespace(options.charAt(i))) { + i++; + } + + if (i >= len || options.charAt(i) != '{') { + break; + } + + int braceEnd = findMatchingBrace(options, i); + if (braceEnd < 0) { + break; + } + + if (braceEnd > i + 1) { + result.put(key, options.substring(i + 1, braceEnd)); + } else { + result.put(key, ""); + } + + i = braceEnd + 1; + } + + return result; + } + + @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..2f15958c 100644 --- a/src/com/hypixel/hytale/server/core/util/backup/BackupTask.java +++ b/src/com/hypixel/hytale/server/core/util/backup/BackupTask.java @@ -1,7 +1,8 @@ package com.hypixel.hytale.server.core.util.backup; import com.hypixel.hytale.logger.HytaleLogger; -import com.hypixel.hytale.server.core.Options; +import com.hypixel.hytale.server.core.HytaleServer; +import com.hypixel.hytale.server.core.config.BackupConfig; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; @@ -45,7 +46,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); @@ -65,7 +66,8 @@ public class BackupTask { } private static void cleanOrArchiveOldBackups(@Nonnull Path sourceDir, @Nonnull Path archiveDir) throws IOException { - int maxCount = Options.getOptionSet().valueOf(Options.BACKUP_MAX_COUNT); + BackupConfig backupConfig = HytaleServer.get().getConfig().getBackupConfig(); + int maxCount = backupConfig.getMaxCount(); if (maxCount >= 1) { List oldBackups = BackupUtil.findOldBackups(sourceDir, maxCount); if (oldBackups != null && !oldBackups.isEmpty()) { @@ -73,7 +75,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 +90,14 @@ 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 { + BackupConfig backupConfig = HytaleServer.get().getConfig().getBackupConfig(); + int maxCount = backupConfig.getArchiveMaxCount(); 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 +111,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/core/util/io/FileUtil.java b/src/com/hypixel/hytale/server/core/util/io/FileUtil.java index 7c24b18b..2b32958c 100644 --- a/src/com/hypixel/hytale/server/core/util/io/FileUtil.java +++ b/src/com/hypixel/hytale/server/core/util/io/FileUtil.java @@ -4,6 +4,7 @@ import com.hypixel.hytale.sneakythrow.SneakyThrow; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.CopyOption; import java.nio.file.FileVisitOption; import java.nio.file.Files; @@ -104,4 +105,27 @@ public class FileUtil { } } } + + public static void writeStringAtomic(@Nonnull Path file, @Nonnull String content, boolean backup) throws IOException { + Path tmpPath = file.resolveSibling(file.getFileName() + ".tmp"); + Path bakPath = file.resolveSibling(file.getFileName() + ".bak"); + Files.writeString(tmpPath, content); + if (backup && Files.isRegularFile(file)) { + atomicMove(file, bakPath); + } + + atomicMove(tmpPath, file); + } + + public static void atomicMove(@Nonnull Path source, @Nonnull Path target) throws IOException { + try { + Files.move(source, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + } catch (AtomicMoveNotSupportedException var3) { + Files.move(source, target, StandardCopyOption.REPLACE_EXISTING); + } + } + + public static void writeStringAtomic(@Nonnull Path file, @Nonnull String content) throws IOException { + writeStringAtomic(file, content, true); + } } diff --git a/src/com/hypixel/hytale/server/core/util/message/MessageFormat.java b/src/com/hypixel/hytale/server/core/util/message/MessageFormat.java index 52abde66..cb50d199 100644 --- a/src/com/hypixel/hytale/server/core/util/message/MessageFormat.java +++ b/src/com/hypixel/hytale/server/core/util/message/MessageFormat.java @@ -1,21 +1,13 @@ package com.hypixel.hytale.server.core.util.message; import com.hypixel.hytale.server.core.Message; -import java.awt.Color; import java.util.Collection; import javax.annotation.Nonnull; import javax.annotation.Nullable; public final class MessageFormat { - private static final Message ENABLED = Message.translation("server.general.enabled").color(Color.GREEN); - private static final Message DISABLED = Message.translation("server.general.disabled").color(Color.RED); private static final int LIST_MAX_INLINE_VALUES = 4; - @Nonnull - public static Message enabled(boolean b) { - return b ? ENABLED : DISABLED; - } - @Nonnull public static Message list(@Nullable Message header, @Nonnull Collection values) { Message msg = Message.empty(); diff --git a/src/com/hypixel/hytale/server/core/util/thread/TickingThread.java b/src/com/hypixel/hytale/server/core/util/thread/TickingThread.java index ef3de5fc..8470db5a 100644 --- a/src/com/hypixel/hytale/server/core/util/thread/TickingThread.java +++ b/src/com/hypixel/hytale/server/core/util/thread/TickingThread.java @@ -1,5 +1,6 @@ package com.hypixel.hytale.server.core.util.thread; +import com.hypixel.hytale.common.plugin.PluginIdentifier; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.metrics.metric.HistoricMetric; import java.util.concurrent.CompletableFuture; @@ -24,6 +25,10 @@ public abstract class TickingThread implements Runnable { private Thread thread; @Nonnull private CompletableFuture startedFuture = new CompletableFuture<>(); + @Nullable + private PluginIdentifier possibleFailureCause; + @Nullable + private Throwable failureException; public TickingThread(String threadName) { this(threadName, 30, false); @@ -74,7 +79,16 @@ public abstract class TickingThread implements Runnable { } catch (InterruptedException var9) { Thread.currentThread().interrupt(); } catch (Throwable var10) { - HytaleLogger.getLogger().at(Level.SEVERE).withCause(var10).log("Exception in thread %s:", this.thread); + this.failureException = var10; + this.possibleFailureCause = PluginIdentifier.identifyThirdPartyPlugin(var10); + if (this.possibleFailureCause == null) { + HytaleLogger.getLogger().at(Level.SEVERE).withCause(var10).log("Exception in thread %s:", this.thread); + } else { + HytaleLogger.getLogger() + .at(Level.SEVERE) + .withCause(var10) + .log("Exception in thread %s potentially caused by %s:", this.thread, this.possibleFailureCause); + } } if (this.needsShutdown.getAndSet(false)) { @@ -195,6 +209,16 @@ public abstract class TickingThread implements Runnable { return this.thread != null && this.thread.isAlive() && this.needsShutdown.get(); } + @Nullable + public PluginIdentifier getPossibleFailureCause() { + return this.possibleFailureCause; + } + + @Nullable + public Throwable getFailureException() { + return this.failureException; + } + @Deprecated protected void setThread(Thread thread) { this.thread = thread; diff --git a/src/com/hypixel/hytale/server/flock/Flock.java b/src/com/hypixel/hytale/server/flock/Flock.java index fe7fda68..5522f36c 100644 --- a/src/com/hypixel/hytale/server/flock/Flock.java +++ b/src/com/hypixel/hytale/server/flock/Flock.java @@ -19,6 +19,7 @@ public class Flock implements Component { private DamageData nextLeaderDamageData = new DamageData(); private DamageData currentLeaderDamageData = new DamageData(); private Flock.FlockRemovedStatus removedStatus = Flock.FlockRemovedStatus.NOT_REMOVED; + private int visFlockMemberCount; public static ComponentType getComponentType() { return FlockPlugin.get().getFlockComponentType(); @@ -71,6 +72,20 @@ public class Flock implements Component { this.removedStatus = status; } + public boolean hasVisFlockMember() { + return this.visFlockMemberCount > 0; + } + + public void incrementVisFlockMemberCount() { + this.visFlockMemberCount++; + } + + public void decrementVisFlockMemberCount() { + if (this.visFlockMemberCount > 0) { + this.visFlockMemberCount--; + } + } + public void onTargetKilled(@Nonnull ComponentAccessor componentAccessor, @Nonnull Ref targetEntityReference) { TransformComponent targetTransformComponent = componentAccessor.getComponent(targetEntityReference, TransformComponent.getComponentType()); if (targetTransformComponent != null) { diff --git a/src/com/hypixel/hytale/server/flock/FlockMembership.java b/src/com/hypixel/hytale/server/flock/FlockMembership.java index 83c394ba..0fa79edf 100644 --- a/src/com/hypixel/hytale/server/flock/FlockMembership.java +++ b/src/com/hypixel/hytale/server/flock/FlockMembership.java @@ -8,11 +8,14 @@ import com.hypixel.hytale.component.Component; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; +import com.hypixel.hytale.server.npc.role.RoleDebugFlags; +import com.hypixel.hytale.server.npc.role.support.DebugSupport; +import java.util.EnumSet; import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class FlockMembership implements Component { +public class FlockMembership implements Component, DebugSupport.DebugFlagsChangeListener { public static final int VERSION = 5; public static final BuilderCodec CODEC = BuilderCodec.builder(FlockMembership.class, FlockMembership::new) .legacyVersioned() @@ -31,6 +34,8 @@ public class FlockMembership implements Component { private FlockMembership.Type membershipType; @Nullable private Ref flockRef; + private transient boolean wasVisFlock; + private transient boolean listenerRegistered; public static ComponentType getComponentType() { return FlockPlugin.get().getFlockMembershipComponentType(); @@ -49,7 +54,7 @@ public class FlockMembership implements Component { return this.flockRef; } - public void setFlockRef(Ref flockRef) { + public void setFlockRef(@Nullable Ref flockRef) { this.flockRef = flockRef; } @@ -65,13 +70,52 @@ public class FlockMembership implements Component { this.flockRef = null; } + public void registerAsDebugListener(@Nonnull DebugSupport debugSupport, @Nonnull Flock flock) { + if (!this.listenerRegistered) { + this.wasVisFlock = debugSupport.isDebugFlagSet(RoleDebugFlags.VisFlock); + debugSupport.registerDebugFlagsListener(this); + this.listenerRegistered = true; + if (this.wasVisFlock) { + flock.incrementVisFlockMemberCount(); + } + } + } + + public void unregisterAsDebugListener(@Nonnull DebugSupport debugSupport, @Nonnull Flock flock) { + if (this.listenerRegistered) { + debugSupport.removeDebugFlagsListener(this); + this.listenerRegistered = false; + if (this.wasVisFlock) { + flock.decrementVisFlockMemberCount(); + } + } + } + + @Override + public void onDebugFlagsChanged(EnumSet newFlags) { + boolean isVisFlock = newFlags.contains(RoleDebugFlags.VisFlock); + if (isVisFlock != this.wasVisFlock) { + this.wasVisFlock = isVisFlock; + if (this.flockRef != null && this.flockRef.isValid()) { + Flock flock = this.flockRef.getStore().getComponent(this.flockRef, Flock.getComponentType()); + if (flock != null) { + if (isVisFlock) { + flock.incrementVisFlockMemberCount(); + } else { + flock.decrementVisFlockMemberCount(); + } + } + } + } + } + @Nonnull @Override public Component clone() { FlockMembership membership = new FlockMembership(); - membership.setFlockId(this.flockId); - membership.setFlockRef(this.flockRef); - membership.setMembershipType(this.membershipType); + membership.flockId = this.flockId; + membership.flockRef = this.flockRef; + membership.membershipType = this.membershipType; return membership; } diff --git a/src/com/hypixel/hytale/server/flock/FlockMembershipSystems.java b/src/com/hypixel/hytale/server/flock/FlockMembershipSystems.java index 78989a9c..55424273 100644 --- a/src/com/hypixel/hytale/server/flock/FlockMembershipSystems.java +++ b/src/com/hypixel/hytale/server/flock/FlockMembershipSystems.java @@ -4,6 +4,7 @@ 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.ComponentAccessor; import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Holder; import com.hypixel.hytale.component.Ref; @@ -92,6 +93,30 @@ public class FlockMembershipSystems { } } + private static void registerFlockDebugListener( + @Nonnull Ref ref, @Nonnull FlockMembership membership, @Nonnull Flock flock, @Nonnull ComponentAccessor accessor + ) { + NPCEntity npcComponent = accessor.getComponent(ref, NPCEntity.getComponentType()); + if (npcComponent != null) { + Role role = npcComponent.getRole(); + if (role != null) { + membership.registerAsDebugListener(role.getDebugSupport(), flock); + } + } + } + + private static void unregisterFlockDebugListener( + @Nonnull Ref ref, @Nonnull FlockMembership membership, @Nonnull Flock flock, @Nonnull ComponentAccessor accessor + ) { + NPCEntity npcComponent = accessor.getComponent(ref, NPCEntity.getComponentType()); + if (npcComponent != null) { + Role role = npcComponent.getRole(); + if (role != null) { + membership.unregisterAsDebugListener(role.getDebugSupport(), flock); + } + } + } + public static class EntityRef extends RefSystem { @Nonnull private final ComponentType flockMembershipComponentType; @@ -144,6 +169,7 @@ public class FlockMembershipSystems { throw new IllegalStateException(String.format("Entity %s attempting to reload into group with ID %s despite already being a member", ref, flockId)); } else { entityGroup.add(ref); + FlockMembershipSystems.registerFlockDebugListener(ref, flockMembershipComponent, flock, store); if (flockMembershipComponent.getMembershipType() == FlockMembership.Type.LEADER) { PersistentFlockData persistentFlockData = store.getComponent(ref, PersistentFlockData.getComponentType()); if (persistentFlockData != null) { @@ -208,6 +234,7 @@ public class FlockMembershipSystems { UUID flockId = uuidComponent.getUuid(); if (reason == RemoveReason.REMOVE || store.getArchetype(ref).contains(Player.getComponentType())) { + FlockMembershipSystems.unregisterFlockDebugListener(ref, membership, flockComponent, store); entityGroupComponent.remove(ref); if (flockComponent.isTrace()) { FlockPlugin.get() @@ -279,6 +306,7 @@ public class FlockMembershipSystems { .log("Flock %s: Set new leader, old=%s, new=%s, size=%s", flockId, ref, newLeader, entityGroupComponent.size()); } } else if (reason == RemoveReason.UNLOAD) { + FlockMembershipSystems.unregisterFlockDebugListener(ref, membership, flockComponent, store); entityGroupComponent.remove(ref); if (!entityGroupComponent.isDissolved() && membership.getMembershipType().isActingAsLeader()) { Ref interimLeader = entityGroupComponent.testMembers(member -> true, true); @@ -346,6 +374,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(); @@ -599,6 +669,7 @@ public class FlockMembershipSystems { } entityGroupComponent.add(ref); + FlockMembershipSystems.registerFlockDebugListener(ref, membershipComponent, flockComponent, store); if (mustBecomeLeader) { setNewLeader(flockId, entityGroupComponent, flockComponent, ref, store, commandBuffer); if (wasFirstJoiner && flockComponent.isTrace()) { @@ -660,6 +731,7 @@ public class FlockMembershipSystems { assert uuidComponent != null; UUID flockId = uuidComponent.getUuid(); + FlockMembershipSystems.unregisterFlockDebugListener(ref, membershipComponent, flockComponent, store); entityGroupComponent.remove(ref); if (flockComponent.isTrace()) { FlockPlugin.get() diff --git a/src/com/hypixel/hytale/server/flock/FlockPlugin.java b/src/com/hypixel/hytale/server/flock/FlockPlugin.java index 0687a148..fc616833 100644 --- a/src/com/hypixel/hytale/server/flock/FlockPlugin.java +++ b/src/com/hypixel/hytale/server/flock/FlockPlugin.java @@ -100,6 +100,7 @@ public class FlockPlugin extends JavaPlugin { }); entityStoreRegistry.registerSystem(new FlockSystems.EntityRemoved(this.flockComponentType)); entityStoreRegistry.registerSystem(new FlockSystems.Ticking(this.flockComponentType)); + entityStoreRegistry.registerSystem(new FlockSystems.FlockDebugSystem(this.flockComponentType)); entityStoreRegistry.registerSystem(new FlockSystems.PlayerChangeGameModeEventSystem()); this.flockMembershipComponentType = entityStoreRegistry.registerComponent(FlockMembership.class, "FlockMembership", FlockMembership.CODEC); this.persistentFlockDataComponentType = entityStoreRegistry.registerComponent(PersistentFlockData.class, "FlockData", PersistentFlockData.CODEC); @@ -108,6 +109,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 +179,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/FlockSystems.java b/src/com/hypixel/hytale/server/flock/FlockSystems.java index 7b7fae7c..4f659ad0 100644 --- a/src/com/hypixel/hytale/server/flock/FlockSystems.java +++ b/src/com/hypixel/hytale/server/flock/FlockSystems.java @@ -12,11 +12,17 @@ import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.EntityEventSystem; import com.hypixel.hytale.component.system.RefSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; +import com.hypixel.hytale.math.shape.Box; +import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.math.vector.Vector3f; import com.hypixel.hytale.protocol.GameMode; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.entity.group.EntityGroup; import com.hypixel.hytale.server.core.event.events.ecs.ChangeGameModeEvent; +import com.hypixel.hytale.server.core.modules.debug.DebugUtils; +import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox; 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 java.util.UUID; import java.util.logging.Level; @@ -82,6 +88,148 @@ public class FlockSystems { } } + public static class FlockDebugSystem extends EntityTickingSystem { + private static final float DEBUG_SHAPE_TIME = 0.1F; + private static final float FLOCK_VIS_RING_OUTER_RADIUS_OFFSET = 0.3F; + private static final float FLOCK_VIS_RING_THICKNESS = 0.08F; + private static final float FLOCK_VIS_LINE_THICKNESS = 0.04F; + private static final int FLOCK_VIS_RING_SEGMENTS = 8; + private static final float FLOCK_VIS_LEADER_EXTRA_RING_OFFSET = 0.15F; + private final ComponentType flockComponentType; + private final ComponentType entityGroupComponentType; + private final ComponentType uuidComponentType; + private final ComponentType transformComponentType; + private final ComponentType boundingBoxComponentType; + @Nonnull + private final Query query; + + public FlockDebugSystem(@Nonnull ComponentType flockComponentType) { + this.flockComponentType = flockComponentType; + this.entityGroupComponentType = EntityGroup.getComponentType(); + this.uuidComponentType = UUIDComponent.getComponentType(); + this.transformComponentType = TransformComponent.getComponentType(); + this.boundingBoxComponentType = BoundingBox.getComponentType(); + this.query = Query.and(flockComponentType, this.entityGroupComponentType, this.uuidComponentType); + } + + @Nonnull + @Override + public Query getQuery() { + return this.query; + } + + @Override + public boolean isParallel(int archetypeChunkSize, int taskCount) { + return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount); + } + + @Override + public void tick( + float dt, + int index, + @Nonnull ArchetypeChunk archetypeChunk, + @Nonnull Store store, + @Nonnull CommandBuffer commandBuffer + ) { + Flock flock = archetypeChunk.getComponent(index, this.flockComponentType); + + assert flock != null; + + if (flock.hasVisFlockMember()) { + EntityGroup entityGroup = archetypeChunk.getComponent(index, this.entityGroupComponentType); + + assert entityGroup != null; + + if (!entityGroup.isDissolved() && entityGroup.size() >= 2) { + UUIDComponent uuidComponent = archetypeChunk.getComponent(index, this.uuidComponentType); + + assert uuidComponent != null; + + World world = store.getExternalData().getWorld(); + int colorIndex = Math.abs(uuidComponent.getUuid().hashCode()) % DebugUtils.INDEXED_COLORS.length; + Vector3f color = DebugUtils.INDEXED_COLORS[colorIndex]; + Ref leaderRef = entityGroup.getLeaderRef(); + if (leaderRef != null && leaderRef.isValid()) { + TransformComponent leaderTransform = store.getComponent(leaderRef, this.transformComponentType); + BoundingBox leaderBoundingBox = store.getComponent(leaderRef, this.boundingBoxComponentType); + if (leaderTransform != null && leaderBoundingBox != null) { + Vector3d leaderPos = leaderTransform.getPosition(); + Box leaderBox = leaderBoundingBox.getBoundingBox(); + double leaderMidY = leaderPos.y + leaderBox.max.y / 2.0; + double leaderWidth = Math.max(leaderBox.max.x - leaderBox.min.x, leaderBox.max.z - leaderBox.min.z); + double leaderRingOuterRadius = leaderWidth / 2.0 + 0.3F; + double leaderRingInnerRadius = leaderRingOuterRadius - 0.08F; + double leaderOuterRingRadius = leaderRingOuterRadius + 0.15F; + double leaderOuterRingInnerRadius = leaderOuterRingRadius - 0.08F; + DebugUtils.addDisc(world, leaderPos.x, leaderMidY, leaderPos.z, leaderRingOuterRadius, leaderRingInnerRadius, color, 0.8F, 8, 0.1F, false); + DebugUtils.addDisc( + world, leaderPos.x, leaderMidY, leaderPos.z, leaderOuterRingRadius, leaderOuterRingInnerRadius, color, 0.8F, 8, 0.1F, false + ); + + for (Ref memberRef : entityGroup.getMemberList()) { + if (memberRef.isValid() && !memberRef.equals(leaderRef)) { + TransformComponent memberTransform = store.getComponent(memberRef, this.transformComponentType); + BoundingBox memberBoundingBox = store.getComponent(memberRef, this.boundingBoxComponentType); + if (memberTransform != null && memberBoundingBox != null) { + Vector3d memberPos = memberTransform.getPosition(); + Box memberBox = memberBoundingBox.getBoundingBox(); + double memberMidY = memberPos.y + memberBox.max.y / 2.0; + double memberWidth = Math.max(memberBox.max.x - memberBox.min.x, memberBox.max.z - memberBox.min.z); + double memberRingOuterRadius = memberWidth / 2.0 + 0.3F; + double memberRingInnerRadius = memberRingOuterRadius - 0.08F; + DebugUtils.addDisc( + world, memberPos.x, memberMidY, memberPos.z, memberRingOuterRadius, memberRingInnerRadius, color, 0.8F, 8, 0.1F, false + ); + renderConnectingLine( + world, + memberPos.x, + memberMidY, + memberPos.z, + memberRingOuterRadius, + leaderPos.x, + leaderMidY, + leaderPos.z, + leaderOuterRingRadius, + color + ); + } + } + } + } + } + } + } + } + + private static void renderConnectingLine( + @Nonnull World world, + double memberX, + double memberY, + double memberZ, + double memberRadius, + double leaderX, + double leaderY, + double leaderZ, + double leaderRadius, + @Nonnull Vector3f color + ) { + double dirX = leaderX - memberX; + double dirZ = leaderZ - memberZ; + double horizontalDist = Math.sqrt(dirX * dirX + dirZ * dirZ); + if (horizontalDist < 0.001) { + DebugUtils.addLine(world, memberX, memberY, memberZ, leaderX, leaderY, leaderZ, color, 0.04F, 0.1F, false); + } else { + double hDirX = dirX / horizontalDist; + double hDirZ = dirZ / horizontalDist; + double startX = memberX + hDirX * memberRadius; + double startZ = memberZ + hDirZ * memberRadius; + double endX = leaderX - hDirX * leaderRadius; + double endZ = leaderZ - hDirZ * leaderRadius; + DebugUtils.addLine(world, startX, memberY, startZ, endX, leaderY, endZ, color, 0.04F, 0.1F, false); + } + } + } + public static class PlayerChangeGameModeEventSystem extends EntityEventSystem { public PlayerChangeGameModeEventSystem() { super(ChangeGameModeEvent.class); 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/blackboard/view/event/EventView.java b/src/com/hypixel/hytale/server/npc/blackboard/view/event/EventView.java index 25820bf7..ce4ff555 100644 --- a/src/com/hypixel/hytale/server/npc/blackboard/view/event/EventView.java +++ b/src/com/hypixel/hytale/server/npc/blackboard/view/event/EventView.java @@ -54,7 +54,7 @@ public abstract class EventView, Even public void onWorldRemoved() { this.shutdown = true; if (this.eventRegistry != null) { - this.eventRegistry.shutdown(); + this.eventRegistry.shutdownAndCleanup(true); this.eventRegistry = null; } } diff --git a/src/com/hypixel/hytale/server/npc/corecomponents/SensorWithEntityFilters.java b/src/com/hypixel/hytale/server/npc/corecomponents/SensorWithEntityFilters.java index 10502147..d686ca40 100644 --- a/src/com/hypixel/hytale/server/npc/corecomponents/SensorWithEntityFilters.java +++ b/src/com/hypixel/hytale/server/npc/corecomponents/SensorWithEntityFilters.java @@ -6,6 +6,7 @@ import com.hypixel.hytale.component.Store; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.corecomponents.builders.BuilderSensorBase; +import com.hypixel.hytale.server.npc.corecomponents.entity.filters.EntityFilterViewSector; import com.hypixel.hytale.server.npc.entities.NPCEntity; import com.hypixel.hytale.server.npc.movement.controllers.MotionController; import com.hypixel.hytale.server.npc.role.Role; @@ -106,4 +107,14 @@ public abstract class SensorWithEntityFilters extends SensorBase implements IAnn return true; } + + protected float findViewAngleFromFilters() { + for (IEntityFilter filter : this.filters) { + if (filter instanceof EntityFilterViewSector viewSector) { + return viewSector.getViewAngle(); + } + } + + return 0.0F; + } } diff --git a/src/com/hypixel/hytale/server/npc/corecomponents/audiovisual/ActionSpawnParticles.java b/src/com/hypixel/hytale/server/npc/corecomponents/audiovisual/ActionSpawnParticles.java index 4468058e..83834aa4 100644 --- a/src/com/hypixel/hytale/server/npc/corecomponents/audiovisual/ActionSpawnParticles.java +++ b/src/com/hypixel/hytale/server/npc/corecomponents/audiovisual/ActionSpawnParticles.java @@ -4,9 +4,13 @@ import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.spatial.SpatialResource; import com.hypixel.hytale.math.vector.Vector3d; +import com.hypixel.hytale.protocol.ModelParticle; +import com.hypixel.hytale.protocol.Vector3f; +import com.hypixel.hytale.protocol.packets.entities.SpawnModelParticles; import com.hypixel.hytale.server.core.modules.entity.EntityModule; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; -import com.hypixel.hytale.server.core.universe.world.ParticleUtil; +import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId; +import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport; import com.hypixel.hytale.server.npc.corecomponents.ActionBase; @@ -20,12 +24,19 @@ public class ActionSpawnParticles extends ActionBase { protected final String particleSystem; protected final double range; protected final Vector3d offset; + protected final ModelParticle[] modelParticlesProtocol; public ActionSpawnParticles(@Nonnull BuilderActionSpawnParticles builder, @Nonnull BuilderSupport support) { super(builder); this.particleSystem = builder.getParticleSystem(support); this.offset = builder.getOffset(support); this.range = builder.getRange(support); + com.hypixel.hytale.server.core.asset.type.model.config.ModelParticle particle = new com.hypixel.hytale.server.core.asset.type.model.config.ModelParticle(); + particle.setSystemId(this.particleSystem); + particle.setPositionOffset(new Vector3f((float)this.offset.x, (float)this.offset.y, (float)this.offset.z)); + particle.setTargetNodeName(builder.getTargetNodeName(support)); + particle.setDetachedFromModel(builder.isDetachedFromModel(support)); + this.modelParticlesProtocol = new ModelParticle[]{particle.toPacket()}; } @Override @@ -39,7 +50,20 @@ public class ActionSpawnParticles extends ActionBase { SpatialResource, EntityStore> playerSpatialResource = store.getResource(EntityModule.get().getPlayerSpatialResourceType()); ObjectList> results = SpatialResource.getThreadLocalReferenceList(); playerSpatialResource.getSpatialStructure().collect(position, this.range, results); - ParticleUtil.spawnParticleEffect(this.particleSystem, position, results, store); - return true; + NetworkId networkIdComponent = store.getComponent(ref, NetworkId.getComponentType()); + if (networkIdComponent == null) { + return true; + } else { + SpawnModelParticles packet = new SpawnModelParticles(networkIdComponent.getId(), this.modelParticlesProtocol); + + for (Ref playerRef : results) { + PlayerRef playerRefComponent = store.getComponent(playerRef, PlayerRef.getComponentType()); + if (playerRefComponent != null) { + playerRefComponent.getPacketHandler().write(packet); + } + } + + return true; + } } } diff --git a/src/com/hypixel/hytale/server/npc/corecomponents/audiovisual/builders/BuilderActionSpawnParticles.java b/src/com/hypixel/hytale/server/npc/corecomponents/audiovisual/builders/BuilderActionSpawnParticles.java index 43f3500a..ec27cc60 100644 --- a/src/com/hypixel/hytale/server/npc/corecomponents/audiovisual/builders/BuilderActionSpawnParticles.java +++ b/src/com/hypixel/hytale/server/npc/corecomponents/audiovisual/builders/BuilderActionSpawnParticles.java @@ -5,8 +5,10 @@ import com.hypixel.hytale.math.vector.Vector3d; import com.hypixel.hytale.server.npc.asset.builder.BuilderDescriptorState; import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport; import com.hypixel.hytale.server.npc.asset.builder.holder.AssetHolder; +import com.hypixel.hytale.server.npc.asset.builder.holder.BooleanHolder; import com.hypixel.hytale.server.npc.asset.builder.holder.DoubleHolder; import com.hypixel.hytale.server.npc.asset.builder.holder.NumberArrayHolder; +import com.hypixel.hytale.server.npc.asset.builder.holder.StringHolder; import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleSingleValidator; import com.hypixel.hytale.server.npc.asset.builder.validators.asset.ParticleSystemExistsValidator; import com.hypixel.hytale.server.npc.corecomponents.audiovisual.ActionSpawnParticles; @@ -17,6 +19,8 @@ public class BuilderActionSpawnParticles extends BuilderActionBase { protected final AssetHolder particleSystem = new AssetHolder(); protected final DoubleHolder range = new DoubleHolder(); protected final NumberArrayHolder offset = new NumberArrayHolder(); + protected final StringHolder targetNodeName = new StringHolder(); + protected final BooleanHolder isDetachedFromModel = new BooleanHolder(); @Nonnull public ActionSpawnParticles build(@Nonnull BuilderSupport builderSupport) { @@ -48,6 +52,10 @@ public class BuilderActionSpawnParticles extends BuilderActionBase { ); this.getDouble(data, "Range", this.range, 75.0, DoubleSingleValidator.greater0(), BuilderDescriptorState.Stable, "Maximum visibility range", null); this.getVector3d(data, "Offset", this.offset, null, null, BuilderDescriptorState.Stable, "Offset relative to footpoint in view direction of NPC", null); + this.getString(data, "TargetNodeName", this.targetNodeName, null, null, BuilderDescriptorState.Stable, "Target node name to position particles at", null); + this.getBoolean( + data, "IsDetachedFromModel", this.isDetachedFromModel, false, BuilderDescriptorState.Stable, "Whether to attach particles to the model", null + ); return this; } @@ -62,4 +70,12 @@ public class BuilderActionSpawnParticles extends BuilderActionBase { public Vector3d getOffset(BuilderSupport support) { return createVector3d(this.offset.get(support.getExecutionContext()), Vector3d.ZERO::clone); } + + public String getTargetNodeName(BuilderSupport support) { + return this.targetNodeName.get(support.getExecutionContext()); + } + + public boolean isDetachedFromModel(BuilderSupport support) { + return this.isDetachedFromModel.get(support.getExecutionContext()); + } } diff --git a/src/com/hypixel/hytale/server/npc/corecomponents/combat/HeadMotionAim.java b/src/com/hypixel/hytale/server/npc/corecomponents/combat/HeadMotionAim.java index 09c7068f..f78efc3a 100644 --- a/src/com/hypixel/hytale/server/npc/corecomponents/combat/HeadMotionAim.java +++ b/src/com/hypixel/hytale/server/npc/corecomponents/combat/HeadMotionAim.java @@ -5,32 +5,38 @@ import com.hypixel.hytale.component.ComponentType; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.math.shape.Box; +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.server.core.entity.entities.ProjectileComponent; +import com.hypixel.hytale.server.core.modules.debug.DebugUtils; import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox; -import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; -import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.physics.component.Velocity; import com.hypixel.hytale.server.core.modules.physics.util.PhysicsMath; import com.hypixel.hytale.server.core.modules.projectile.config.BallisticData; +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.TargetUtil; import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport; import com.hypixel.hytale.server.npc.corecomponents.HeadMotionBase; import com.hypixel.hytale.server.npc.corecomponents.combat.builders.BuilderHeadMotionAim; import com.hypixel.hytale.server.npc.movement.Steering; import com.hypixel.hytale.server.npc.role.Role; +import com.hypixel.hytale.server.npc.role.RoleDebugFlags; +import com.hypixel.hytale.server.npc.role.support.DebugSupport; import com.hypixel.hytale.server.npc.sensorinfo.IPositionProvider; import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider; import com.hypixel.hytale.server.npc.util.AimingData; import com.hypixel.hytale.server.npc.util.NPCPhysicsMath; +import java.util.EnumSet; import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class HeadMotionAim extends HeadMotionBase { +public class HeadMotionAim extends HeadMotionBase implements DebugSupport.DebugFlagsChangeListener { + public static final double MIN_RANGED_AIMING_DISTANCE = 4.0; protected static final ComponentType TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType(); - protected static final ComponentType MODEL_COMPONENT_TYPE = ModelComponent.getComponentType(); protected static final ComponentType BOUNDING_BOX_COMPONENT_TYPE = BoundingBox.getComponentType(); protected final double spread; protected final boolean deflection; @@ -38,9 +44,13 @@ public class HeadMotionAim extends HeadMotionBase { protected final double relativeTurnSpeed; protected final AimingData aimingData = new AimingData(); protected Ref lastTargetReference; - protected double spreadX; - protected double spreadY; - protected double spreadZ; + protected boolean debugAiming; + protected final Vector3d startPosition = new Vector3d(); + protected final Vector3d startOffset = new Vector3d(); + protected final Vector3d targetPosition = new Vector3d(); + protected final Vector3d targetOffset = new Vector3d(); + protected final Vector3d relativeVelocity = new Vector3d(); + protected final Vector3d spreadOffset = new Vector3d(); public HeadMotionAim(@Nonnull BuilderHeadMotionAim builder, @Nonnull BuilderSupport support) { super(builder); @@ -71,115 +81,154 @@ public class HeadMotionAim extends HeadMotionBase { @Nonnull Steering desiredSteering, @Nonnull ComponentAccessor componentAccessor ) { - if (sensorInfo != null && sensorInfo.hasPosition()) { - TransformComponent transformComponent = componentAccessor.getComponent(ref, TRANSFORM_COMPONENT_TYPE); - - assert transformComponent != null; - - ModelComponent modelComponent = componentAccessor.getComponent(ref, MODEL_COMPONENT_TYPE); - - assert modelComponent != null; - - Vector3d position = transformComponent.getPosition(); + if (sensorInfo != null && sensorInfo.hasPosition() && sensorInfo.getPositionProvider() != null) { + Transform lookVec = TargetUtil.getLook(ref, componentAccessor); + Vector3d lookPosition = lookVec.getPosition(); + Vector3f lookRotation = lookVec.getRotation(); IPositionProvider positionProvider = sensorInfo.getPositionProvider(); - double x = positionProvider.getX() - position.getX(); - double y = positionProvider.getY() - position.getY() - modelComponent.getModel().getEyeHeight(); - double z = positionProvider.getZ() - position.getZ(); - double vx = 0.0; - double vy = 0.0; - double vz = 0.0; + positionProvider.providePosition(this.targetPosition); + this.startPosition.assign(lookPosition); + this.relativeVelocity.assign(Vector3d.ZERO); Ref targetRef = positionProvider.getTarget(); + BallisticData ballisticData = this.aimingData.getBallisticData(); + Box boundingBox = Box.ZERO; if (targetRef != null) { Velocity targetVelocityComponent = componentAccessor.getComponent(targetRef, Velocity.getComponentType()); assert targetVelocityComponent != null; - BoundingBox boundingBoxComponent = componentAccessor.getComponent(ref, BOUNDING_BOX_COMPONENT_TYPE); - Box boundingBox = boundingBoxComponent != null ? boundingBoxComponent.getBoundingBox() : null; - if (this.aimingData.isBallistic()) { - if (boundingBox != null) { - x += (boundingBox.getMax().getX() + boundingBox.getMin().getX()) / 2.0; - y += (boundingBox.getMax().getY() + boundingBox.getMin().getY()) / 2.0; - z += (boundingBox.getMax().getZ() + boundingBox.getMin().getZ()) / 2.0; - } + BoundingBox boundingBoxComponent = componentAccessor.getComponent(targetRef, BOUNDING_BOX_COMPONENT_TYPE); + if (boundingBoxComponent != null) { + boundingBox = boundingBoxComponent.getBoundingBox(); + } + if (ballisticData != null) { if (this.deflection) { - Vector3d steeringVelocity = targetVelocityComponent.getVelocity(); - vx = steeringVelocity.getX(); - vy = steeringVelocity.getY(); - vz = steeringVelocity.getZ(); + this.relativeVelocity.assign(targetVelocityComponent.getVelocity()); } - } else if (boundingBox != null) { - double minY = y + boundingBox.getMin().y; - double maxY = y + boundingBox.getMax().y; - if (minY > 0.0) { - y = minY; - } else if (maxY < 0.0) { - y = maxY; + } else { + double targetY = this.targetPosition.getY(); + double startY = this.startPosition.getY(); + double minY = targetY + boundingBox.getMin().y; + double maxY = targetY + boundingBox.getMax().y; + if (minY > startY) { + this.targetPosition.setY(minY); + } else if (maxY < startY) { + this.targetPosition.setY(maxY); } else { - y = 0.0; + this.targetPosition.setY(startY); } } } - if (this.aimingData.isBallistic()) { - BallisticData ballisticData = this.aimingData.getBallisticData(); - if (ballisticData != null) { - y += ballisticData.getVerticalCenterShot(); - this.aimingData.setDepthOffset(ballisticData.getDepthShot(), ballisticData.isPitchAdjustShot()); + boolean isNearTarget = this.startPosition.distanceSquaredTo(this.targetPosition) <= 16.0; + if (ballisticData != null) { + this.aimingData.setDepthOffset(ballisticData.getDepthShot(), ballisticData.isPitchAdjustShot()); + if (!isNearTarget) { + ProjectileComponent.computeStartOffset( + ballisticData.isPitchAdjustShot(), + ballisticData.getVerticalCenterShot(), + ballisticData.getHorizontalCenterShot(), + ballisticData.getDepthShot(), + lookRotation.getYaw(), + lookRotation.getPitch(), + this.startOffset + ); } else { - this.aimingData.setDepthOffset(0.0, false); + this.startOffset.assign(Vector3d.ZERO); } - if (targetRef != null && (this.lastTargetReference == null || !this.lastTargetReference.equals(targetRef))) { + if (targetRef != null && !targetRef.equals(this.lastTargetReference)) { this.lastTargetReference = targetRef; this.aimingData.setHaveAttacked(true); } if (this.aimingData.isHaveAttacked()) { ThreadLocalRandom random = ThreadLocalRandom.current(); + this.spreadOffset.assign(Vector3d.ZERO); + this.targetOffset.assign(Vector3d.ZERO); if (this.spread > 0.0 && random.nextDouble() > this.hitProbability) { - double spread2 = 2.0 * this.spread * Math.sqrt(NPCPhysicsMath.dotProduct(x, y, z)) / 10.0; - this.spreadX = this.spreadX + spread2 * (random.nextDouble() - 0.5); - this.spreadY = this.spreadY + spread2 * (random.nextDouble() - 0.5); - this.spreadZ = this.spreadZ + spread2 * (random.nextDouble() - 0.5); + double spread2 = 2.0 * this.spread * this.startPosition.distanceTo(this.targetPosition) / 10.0; + this.spreadOffset.assign(random.nextDouble() - 0.5, random.nextDouble() - 0.5, random.nextDouble() - 0.5).scale(spread2); } else { - this.spreadX = 0.0; - this.spreadY = 0.0; - this.spreadZ = 0.0; + double start = 0.1; + double end = 0.9; + this.targetOffset + .assign( + NPCPhysicsMath.lerp(boundingBox.getMin().x, boundingBox.getMax().x, random.nextDouble(0.1, 0.9)), + NPCPhysicsMath.lerp(boundingBox.getMin().y, boundingBox.getMax().y, random.nextDouble(0.1, 0.9)), + NPCPhysicsMath.lerp(boundingBox.getMin().z, boundingBox.getMax().z, random.nextDouble(0.1, 0.9)) + ); } this.aimingData.setHaveAttacked(false); } - x += this.spreadX; - y += this.spreadY; - z += this.spreadZ; + this.targetPosition.add(this.spreadOffset); + this.targetPosition.add(this.targetOffset); + this.startPosition.add(this.startOffset); + } else { + this.aimingData.setDepthOffset(0.0, false); } - float pitch; - float yaw; - if (this.aimingData.computeSolution(x, y, z, vx, vy, vz)) { - yaw = this.aimingData.getYaw(); - pitch = this.aimingData.getPitch(); + double x = this.targetPosition.getX() - this.startPosition.getX(); + double y = this.targetPosition.getY() - this.startPosition.getY(); + double z = this.targetPosition.getZ() - this.startPosition.getZ(); + if (isNearTarget && ballisticData != null) { + float yaw = lookRotation.getYaw(); + float pitch = lookRotation.getPitch(); + double dotXZ = x * x + z * z; + if (dotXZ >= 1.0E-4) { + yaw = PhysicsMath.normalizeTurnAngle(PhysicsMath.headingFromDirection(x, z)); + double invLen = 1.0 / Math.sqrt(dotXZ); + double hOffset = ballisticData.getHorizontalCenterShot(); + if (ballisticData.getDepthShot() != 0.0 && !ballisticData.isPitchAdjustShot()) { + hOffset += ballisticData.getDepthShot(); + } + + double dx = hOffset * x * invLen; + double dy = -ballisticData.getVerticalCenterShot(); + double dz = -(hOffset * z * invLen); + this.startPosition.add(dx, dy, dz); + x -= dx; + y -= dy; + z -= dz; + } + + double dotXYZ = dotXZ + y * y; + if (dotXYZ >= 1.0E-4) { + pitch = PhysicsMath.pitchFromDirection(x, y, z); + } + + this.aimingData.setOrientation(yaw, pitch); + this.aimingData.setTarget(targetRef); + } else if (this.aimingData.computeSolution(x, y, z, this.relativeVelocity.getX(), this.relativeVelocity.getY(), this.relativeVelocity.getZ())) { this.aimingData.setTarget(targetRef); } else { - HeadRotation headRotationComponent = componentAccessor.getComponent(ref, HeadRotation.getComponentType()); - - assert headRotationComponent != null; - - double xxzz = x * x + z * z; - double xxyyzz = xxzz + y * y; - Vector3f headRotation = headRotationComponent.getRotation(); - yaw = xxzz >= 1.0E-4 ? PhysicsMath.normalizeTurnAngle(PhysicsMath.headingFromDirection(x, z)) : headRotation.getYaw(); - pitch = xxyyzz >= 1.0E-4 ? PhysicsMath.pitchFromDirection(x, y, z) : headRotation.getPitch(); - this.aimingData.setOrientation(yaw, pitch); + double dotXZx = x * x + z * z; + double dotXYZ = dotXZx + y * y; + float yawx = dotXZx >= 1.0E-4 ? PhysicsMath.normalizeTurnAngle(PhysicsMath.headingFromDirection(x, z)) : lookRotation.getYaw(); + float pitchx = dotXYZ >= 1.0E-4 ? PhysicsMath.pitchFromDirection(x, y, z) : lookRotation.getPitch(); + this.aimingData.setOrientation(yawx, pitchx); this.aimingData.setTarget(null); } + if (this.debugAiming) { + Vector3f color = DebugUtils.COLOR_WHITE; + if (this.aimingData.haveOrientation()) { + color = DebugUtils.COLOR_GREEN; + } + + World world = ref.getStore().getExternalData().getWorld(); + DebugUtils.addSphere(world, this.targetPosition, color, 0.5, 0.1F); + if (this.startPosition.distanceTo(this.targetPosition) > 1.0E-4) { + DebugUtils.addArrow(world, this.startPosition, this.targetPosition.clone().subtract(this.startPosition).setLength(1.0), color, 0.1F, true); + } + } + desiredSteering.clearTranslation(); - desiredSteering.setYaw(yaw); - desiredSteering.setPitch(pitch); + desiredSteering.setYaw(this.aimingData.getYaw()); + desiredSteering.setPitch(this.aimingData.getPitch()); desiredSteering.setRelativeTurnSpeed(this.relativeTurnSpeed); return true; } else { @@ -187,4 +236,15 @@ public class HeadMotionAim extends HeadMotionBase { return true; } } + + @Override + public void registerWithSupport(Role role) { + super.registerWithSupport(role); + role.getDebugSupport().registerDebugFlagsListener(this); + } + + @Override + public void onDebugFlagsChanged(EnumSet newFlags) { + this.debugAiming = newFlags.contains(RoleDebugFlags.VisAiming); + } } diff --git a/src/com/hypixel/hytale/server/npc/corecomponents/entity/SensorEntityBase.java b/src/com/hypixel/hytale/server/npc/corecomponents/entity/SensorEntityBase.java index 5b228774..afb8fdc5 100644 --- a/src/com/hypixel/hytale/server/npc/corecomponents/entity/SensorEntityBase.java +++ b/src/com/hypixel/hytale/server/npc/corecomponents/entity/SensorEntityBase.java @@ -22,6 +22,7 @@ import com.hypixel.hytale.server.npc.corecomponents.entity.builders.BuilderSenso import com.hypixel.hytale.server.npc.entities.NPCEntity; import com.hypixel.hytale.server.npc.movement.controllers.MotionController; import com.hypixel.hytale.server.npc.role.Role; +import com.hypixel.hytale.server.npc.role.support.DebugSupport; import com.hypixel.hytale.server.npc.sensorinfo.EntityPositionProvider; import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider; import com.hypixel.hytale.server.npc.util.IEntityByPriorityFilter; @@ -50,6 +51,8 @@ public abstract class SensorEntityBase extends SensorWithEntityFilters { protected final ISensorEntityCollector collector; protected int ownRole; protected final EntityPositionProvider positionProvider = new EntityPositionProvider(); + protected int currentVisSensorColorIndex = -1; + protected final float visViewAngle; public SensorEntityBase(@Nonnull BuilderSensorEntityBase builder, ISensorEntityPrioritiser prioritiser, @Nonnull BuilderSupport builderSupport) { super(builder, builder.getFilters(builderSupport, prioritiser, ComponentContext.SensorEntity)); @@ -63,12 +66,14 @@ public abstract class SensorEntityBase extends SensorWithEntityFilters { this.ignoredTargetSlot = builder.getIgnoredTargetSlot(builderSupport); this.prioritiser = prioritiser; this.collector = builder.getCollector(builderSupport); + this.visViewAngle = this.findViewAngleFromFilters(); } @Override public boolean matches(@Nonnull Ref ref, @Nonnull Role role, double dt, @Nonnull Store store) { if (!super.matches(ref, role, dt, store)) { this.positionProvider.clear(); + this.currentVisSensorColorIndex = -1; return false; } else { TransformComponent transformComponent = store.getComponent(ref, TRANSFORM_COMPONENT_TYPE); @@ -77,6 +82,13 @@ public abstract class SensorEntityBase extends SensorWithEntityFilters { Vector3d position = transformComponent.getPosition(); this.ownRole = role.getRoleIndex(); + DebugSupport debugSupport = role.getDebugSupport(); + if (debugSupport.isVisSensorRanges()) { + this.currentVisSensorColorIndex = debugSupport.recordSensorRange(this.range, this.minRange, this.visViewAngle); + } else { + this.currentVisSensorColorIndex = -1; + } + if (this.ignoredTargetSlot == Integer.MIN_VALUE || this.ignoredTargetSlot != this.lockedTargetSlot) { Ref targetRef = this.filterLockedEntity(ref, position, role, store); if (targetRef != null) { @@ -281,23 +293,32 @@ public abstract class SensorEntityBase extends SensorWithEntityFilters { @Nonnull Ref targetRef, @Nonnull Role role, @Nonnull Store store, - @Nonnull IEntityByPriorityFilter playerPrioritiser + @Nonnull IEntityByPriorityFilter entityPrioritiser ) { - if (!this.filterEntity(ref, targetRef, role, store)) { + boolean filterMatch = this.filterEntity(ref, targetRef, role, store); + if (!filterMatch) { this.collector.collectNonMatching(targetRef, store); + this.recordEntityVisData(targetRef, role, false); return false; } else { - boolean match = playerPrioritiser.test(ref, targetRef, store); + boolean match = entityPrioritiser.test(ref, targetRef, store); if (match) { this.collector.collectMatching(ref, targetRef, store); } else { this.collector.collectNonMatching(targetRef, store); } + this.recordEntityVisData(targetRef, role, match); return this.collector.terminateOnFirstMatch() && match; } } + private void recordEntityVisData(@Nonnull Ref targetRef, @Nonnull Role role, boolean matched) { + if (this.currentVisSensorColorIndex >= 0) { + role.getDebugSupport().recordEntityCheck(targetRef, this.currentVisSensorColorIndex, matched); + } + } + @Nullable protected Ref findPlayerOrEntity( @Nonnull Ref ref, @Nonnull Vector3d position, @Nonnull Role role, @Nonnull Store store diff --git a/src/com/hypixel/hytale/server/npc/corecomponents/entity/filters/EntityFilterViewSector.java b/src/com/hypixel/hytale/server/npc/corecomponents/entity/filters/EntityFilterViewSector.java index 9ea73764..af3af7e3 100644 --- a/src/com/hypixel/hytale/server/npc/corecomponents/entity/filters/EntityFilterViewSector.java +++ b/src/com/hypixel/hytale/server/npc/corecomponents/entity/filters/EntityFilterViewSector.java @@ -48,4 +48,8 @@ public class EntityFilterViewSector extends EntityFilterBase { public int cost() { return 300; } + + public float getViewAngle() { + return this.viewCone; + } } diff --git a/src/com/hypixel/hytale/server/npc/decisionmaker/core/conditions/base/Condition.java b/src/com/hypixel/hytale/server/npc/decisionmaker/core/conditions/base/Condition.java index 93d3272c..534f86d4 100644 --- a/src/com/hypixel/hytale/server/npc/decisionmaker/core/conditions/base/Condition.java +++ b/src/com/hypixel/hytale/server/npc/decisionmaker/core/conditions/base/Condition.java @@ -42,20 +42,26 @@ public abstract class Condition implements JsonAssetWithMap CODEC = new AssetCodecMapCodec<>( Codec.STRING, (t, k) -> t.id = k, t -> t.id, (t, data) -> t.data = data, t -> t.data ); + @Nonnull public static final BuilderCodec BASE_CODEC = BuilderCodec.abstractBuilder(Condition.class) .afterDecode(condition -> condition.reference = new WeakReference<>(condition)) .build(); + @Nonnull public static final Codec CHILD_ASSET_CODEC = new ContainedAssetCodec<>(Condition.class, CODEC); + @Nonnull public static final Codec CHILD_ASSET_CODEC_ARRAY = new ArrayCodec<>(CHILD_ASSET_CODEC, String[]::new); + @Nonnull public static final ValidatorCache VALIDATOR_CACHE = new ValidatorCache<>(new AssetKeyValidator<>(Condition::getAssetStore)); private static AssetStore> ASSET_STORE; protected AssetExtraInfo.Data data; protected String id; protected WeakReference reference; + @Nonnull public static AssetStore> getAssetStore() { if (ASSET_STORE == null) { ASSET_STORE = AssetRegistry.getAssetStore(Condition.class); diff --git a/src/com/hypixel/hytale/server/npc/decisionmaker/core/conditions/base/ScaledCurveCondition.java b/src/com/hypixel/hytale/server/npc/decisionmaker/core/conditions/base/ScaledCurveCondition.java index c7cdd435..8884712f 100644 --- a/src/com/hypixel/hytale/server/npc/decisionmaker/core/conditions/base/ScaledCurveCondition.java +++ b/src/com/hypixel/hytale/server/npc/decisionmaker/core/conditions/base/ScaledCurveCondition.java @@ -12,6 +12,7 @@ import com.hypixel.hytale.server.npc.decisionmaker.core.EvaluationContext; import javax.annotation.Nonnull; public abstract class ScaledCurveCondition extends Condition { + @Nonnull public static final BuilderCodec ABSTRACT_CODEC = BuilderCodec.abstractBuilder(ScaledCurveCondition.class, BASE_CODEC) .appendInherited( new KeyedCodec<>("Curve", ScaledResponseCurve.CODEC), diff --git a/src/com/hypixel/hytale/server/npc/instructions/Instruction.java b/src/com/hypixel/hytale/server/npc/instructions/Instruction.java index 56198a0d..c75171a3 100644 --- a/src/com/hypixel/hytale/server/npc/instructions/Instruction.java +++ b/src/com/hypixel/hytale/server/npc/instructions/Instruction.java @@ -321,7 +321,7 @@ public class Instruction implements RoleStateChange, IAnnotatedComponentCollecti } if (this.sensor.matches(ref, role, dt, store)) { - if (!this.treeMode && !this.continueAfter) { + if (!this.treeMode && !this.continueAfter && !this.invertTreeModeResult) { role.notifySensorMatch(); } @@ -406,14 +406,16 @@ public class Instruction implements RoleStateChange, IAnnotatedComponentCollecti } public void onMatched(@Nonnull Role role) { - if (this.treeMode) { + if (this.treeMode || this.invertTreeModeResult) { this.parentTreeModeStep = role.swapTreeModeSteps(this); - this.continueAfter = true; + if (this.treeMode) { + this.continueAfter = true; + } } } public void onCompleted(@Nonnull Role role) { - if (this.treeMode) { + if (this.treeMode || this.invertTreeModeResult) { role.swapTreeModeSteps(this.parentTreeModeStep); if (this.parentTreeModeStep != null) { if (this.continueAfter == this.invertTreeModeResult) { 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/movement/controllers/MotionController.java b/src/com/hypixel/hytale/server/npc/movement/controllers/MotionController.java index 2e97cece..650287f5 100644 --- a/src/com/hypixel/hytale/server/npc/movement/controllers/MotionController.java +++ b/src/com/hypixel/hytale/server/npc/movement/controllers/MotionController.java @@ -16,10 +16,13 @@ import com.hypixel.hytale.server.npc.movement.MovementState; import com.hypixel.hytale.server.npc.movement.NavState; import com.hypixel.hytale.server.npc.movement.Steering; import com.hypixel.hytale.server.npc.role.Role; +import com.hypixel.hytale.server.npc.role.RoleDebugFlags; +import com.hypixel.hytale.server.npc.role.support.DebugSupport; +import java.util.EnumSet; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public interface MotionController { +public interface MotionController extends DebugSupport.DebugFlagsChangeListener { String getType(); Role getRole(); @@ -216,6 +219,10 @@ public interface MotionController { } } + @Override + default void onDebugFlagsChanged(EnumSet newFlags) { + } + static { if (.$assertionsDisabled) { } diff --git a/src/com/hypixel/hytale/server/npc/movement/controllers/MotionControllerBase.java b/src/com/hypixel/hytale/server/npc/movement/controllers/MotionControllerBase.java index 1cca3a83..2063de61 100644 --- a/src/com/hypixel/hytale/server/npc/movement/controllers/MotionControllerBase.java +++ b/src/com/hypixel/hytale/server/npc/movement/controllers/MotionControllerBase.java @@ -49,6 +49,7 @@ import com.hypixel.hytale.server.npc.role.Role; import com.hypixel.hytale.server.npc.role.RoleDebugFlags; import com.hypixel.hytale.server.npc.util.NPCPhysicsMath; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.util.EnumSet; import java.util.List; import java.util.Objects; import java.util.function.BiPredicate; @@ -1040,10 +1041,6 @@ public abstract class MotionControllerBase implements MotionController { } } - protected boolean isDebugMode(RoleDebugFlags mode) { - return this.getRole() != null && this.getRole().getDebugSupport().getDebugFlags().contains(mode); - } - public boolean isProcessTriggersHasMoved() { return this.processTriggersHasMoved; } @@ -1052,16 +1049,21 @@ public abstract class MotionControllerBase implements MotionController { return !componentAccessor.getArchetype(ref).contains(DeathComponent.getComponentType()); } + @Override + public void onDebugFlagsChanged(EnumSet newFlags) { + MotionController.super.onDebugFlagsChanged(newFlags); + this.debugModeSteer = newFlags.contains(RoleDebugFlags.MotionControllerSteer); + this.debugModeMove = newFlags.contains(RoleDebugFlags.MotionControllerMove); + this.debugModeCollisions = newFlags.contains(RoleDebugFlags.Collisions); + this.debugModeBlockCollisions = newFlags.contains(RoleDebugFlags.BlockCollisions); + this.debugModeProbeBlockCollisions = newFlags.contains(RoleDebugFlags.ProbeBlockCollisions); + this.debugModeValidatePositions = newFlags.contains(RoleDebugFlags.ValidatePositions); + this.debugModeOverlaps = newFlags.contains(RoleDebugFlags.Overlaps); + this.debugModeValidateMath = newFlags.contains(RoleDebugFlags.ValidateMath); + } + @Override public void activate() { - this.debugModeSteer = this.isDebugMode(RoleDebugFlags.MotionControllerSteer); - this.debugModeMove = this.isDebugMode(RoleDebugFlags.MotionControllerMove); - this.debugModeCollisions = this.isDebugMode(RoleDebugFlags.Collisions); - this.debugModeBlockCollisions = this.isDebugMode(RoleDebugFlags.BlockCollisions); - this.debugModeProbeBlockCollisions = this.isDebugMode(RoleDebugFlags.ProbeBlockCollisions); - this.debugModeValidatePositions = this.isDebugMode(RoleDebugFlags.ValidatePositions); - this.debugModeOverlaps = this.isDebugMode(RoleDebugFlags.Overlaps); - this.debugModeValidateMath = this.isDebugMode(RoleDebugFlags.ValidateMath); this.resetObstructedFlags(); this.resetNavState(); } diff --git a/src/com/hypixel/hytale/server/npc/role/Role.java b/src/com/hypixel/hytale/server/npc/role/Role.java index 2f984449..dc07df82 100644 --- a/src/com/hypixel/hytale/server/npc/role/Role.java +++ b/src/com/hypixel/hytale/server/npc/role/Role.java @@ -54,6 +54,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Map.Entry; import java.util.function.Supplier; import java.util.logging.Level; import javax.annotation.Nonnull; @@ -209,11 +210,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); @@ -562,6 +563,11 @@ public class Role implements IAnnotatedComponentCollection { @Nonnull NPCEntity npcComponent, @Nonnull Map motionControllers, @Nullable String initialMotionController ) { this.motionControllers = motionControllers; + + for (Entry entry : this.motionControllers.entrySet()) { + this.debugSupport.registerDebugFlagsListener(entry.getValue()); + } + this.updateMotionControllers(null, null, null, null); if (!this.motionControllers.isEmpty()) { if (initialMotionController != null && this.setActiveMotionController(null, npcComponent, initialMotionController, null)) { @@ -620,6 +626,10 @@ public class Role implements IAnnotatedComponentCollection { protected void computeActionsAndSteering( @Nonnull Ref ref, double tickTime, @Nonnull Steering bodySteering, @Nonnull Steering headSteering, @Nonnull Store store ) { + if (this.debugSupport.isVisSensorRanges()) { + this.debugSupport.beginSensorVisualization(); + } + boolean isDead = store.getArchetype(ref).contains(DeathComponent.getComponentType()); if (isDead) { if (this.deathInstruction != null) { diff --git a/src/com/hypixel/hytale/server/npc/role/RoleDebugDisplay.java b/src/com/hypixel/hytale/server/npc/role/RoleDebugDisplay.java index 81e80a8f..fa35da9b 100644 --- a/src/com/hypixel/hytale/server/npc/role/RoleDebugDisplay.java +++ b/src/com/hypixel/hytale/server/npc/role/RoleDebugDisplay.java @@ -11,6 +11,7 @@ import com.hypixel.hytale.protocol.MovementStates; import com.hypixel.hytale.server.core.entity.movement.MovementStatesComponent; import com.hypixel.hytale.server.core.entity.nameplate.Nameplate; import com.hypixel.hytale.server.core.inventory.Inventory; +import com.hypixel.hytale.server.core.modules.debug.DebugUtils; import com.hypixel.hytale.server.core.modules.entity.component.ActiveAnimationComponent; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap; @@ -48,6 +49,7 @@ public class RoleDebugDisplay { protected boolean debugDisplaySpeed; protected boolean debugDisplayInternalId; protected boolean debugDisplayName; + protected boolean debugVisMarkedTargets; @Nonnull protected StringBuilder debugDisplay = new StringBuilder(20); @@ -233,6 +235,24 @@ public class RoleDebugDisplay { this.debugDisplay.append(" SPD:").append(MathUtil.round(velocityComponent.getSpeed(), 1)); } + if (this.debugVisMarkedTargets) { + MarkedEntitySupport markedEntitySupport = role.getMarkedEntitySupport(); + Ref[] entityTargets = markedEntitySupport.getEntityTargets(); + + for (int slotIndex = 0; slotIndex < entityTargets.length; slotIndex++) { + Ref targetRef = entityTargets[slotIndex]; + if (targetRef != null && targetRef.isValid()) { + String colorName = DebugUtils.INDEXED_COLOR_NAMES[slotIndex % DebugUtils.INDEXED_COLOR_NAMES.length]; + String slotName = markedEntitySupport.getSlotName(slotIndex); + if (!this.debugDisplay.isEmpty()) { + this.debugDisplay.append(' '); + } + + this.debugDisplay.append(colorName).append('(').append(slotName).append(')'); + } + } + } + if (!this.debugDisplay.isEmpty()) { Nameplate nameplateComponent = archetypeChunk.getComponent(index, Nameplate.getComponentType()); if (nameplateComponent != null) { @@ -247,7 +267,7 @@ public class RoleDebugDisplay { } @Nullable - public static RoleDebugDisplay create(@Nonnull EnumSet debugFlags) { + public static RoleDebugDisplay create(@Nonnull EnumSet debugFlags, @Nullable RoleDebugDisplay existingDisplay) { boolean debugDisplayState = debugFlags.contains(RoleDebugFlags.DisplayState); boolean debugDisplayTime = debugFlags.contains(RoleDebugFlags.DisplayTime); boolean debugDisplayFlock = debugFlags.contains(RoleDebugFlags.DisplayFlock); @@ -262,6 +282,7 @@ public class RoleDebugDisplay { boolean debugDisplaySpeed = debugFlags.contains(RoleDebugFlags.DisplaySpeed); boolean debugDisplayName = debugFlags.contains(RoleDebugFlags.DisplayName); boolean debugDisplayInternalId = debugFlags.contains(RoleDebugFlags.DisplayInternalId); + boolean debugVisMarkedTargets = debugFlags.contains(RoleDebugFlags.VisMarkedTargets); if (!debugDisplayInternalId && !debugDisplayState && !debugDisplayFlock @@ -275,10 +296,11 @@ public class RoleDebugDisplay { && !debugDisplayHP && !debugDisplaySpeed && !debugDisplayName - && !debugDisplayStamina) { + && !debugDisplayStamina + && !debugVisMarkedTargets) { return null; } else { - RoleDebugDisplay debugDisplay = new RoleDebugDisplay(); + RoleDebugDisplay debugDisplay = existingDisplay != null ? existingDisplay : new RoleDebugDisplay(); debugDisplay.debugDisplayState = debugDisplayState; debugDisplay.debugDisplayTime = debugDisplayTime; debugDisplay.debugDisplayFlock = debugDisplayFlock; @@ -293,6 +315,7 @@ public class RoleDebugDisplay { debugDisplay.debugDisplaySpeed = debugDisplaySpeed; debugDisplay.debugDisplayInternalId = debugDisplayInternalId; debugDisplay.debugDisplayName = debugDisplayName; + debugDisplay.debugVisMarkedTargets = debugVisMarkedTargets; return debugDisplay; } } diff --git a/src/com/hypixel/hytale/server/npc/role/RoleDebugFlags.java b/src/com/hypixel/hytale/server/npc/role/RoleDebugFlags.java index 49469684..64e07737 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"), @@ -37,6 +37,11 @@ public enum RoleDebugFlags implements Supplier { ValidateMath("Validate (some) math computations in movement"), VisAvoidance("Visualize avoidance vectors"), VisSeparation("Visualize separation vector"), + VisAiming("Visualize aiming"), + VisMarkedTargets("Visualize arrows to marked targets"), + VisSensorRanges("Visualize entity sensor detection ranges"), + VisLeashPosition("Visualize NPC leash position"), + VisFlock("Visualize flock member connections"), BeaconMessages("Enable debugging of beacon message sending and receiving"); private static final RoleDebugFlags.RoleDebugPreset[] presets = new RoleDebugFlags.RoleDebugPreset[]{ @@ -47,6 +52,7 @@ public enum RoleDebugFlags implements Supplier { new RoleDebugFlags.RoleDebugPreset("valid", EnumSet.of(MotionControllerMove, MotionControllerSteer, Collisions, ValidatePositions)), new RoleDebugFlags.RoleDebugPreset("block", EnumSet.of(MotionControllerMove, MotionControllerSteer, Collisions, BlockCollisions)), new RoleDebugFlags.RoleDebugPreset("visDist", EnumSet.of(VisAvoidance, VisSeparation)), + new RoleDebugFlags.RoleDebugPreset("visSensorInfo", EnumSet.of(VisMarkedTargets, VisSensorRanges)), new RoleDebugFlags.RoleDebugPreset( "display", EnumSet.of( 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/role/support/DebugSupport.java b/src/com/hypixel/hytale/server/npc/role/support/DebugSupport.java index 20d7ee02..a753b451 100644 --- a/src/com/hypixel/hytale/server/npc/role/support/DebugSupport.java +++ b/src/com/hypixel/hytale/server/npc/role/support/DebugSupport.java @@ -1,11 +1,17 @@ package com.hypixel.hytale.server.npc.role.support; +import com.hypixel.hytale.component.Ref; +import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import com.hypixel.hytale.server.npc.entities.NPCEntity; import com.hypixel.hytale.server.npc.instructions.Sensor; import com.hypixel.hytale.server.npc.role.RoleDebugDisplay; import com.hypixel.hytale.server.npc.role.RoleDebugFlags; import com.hypixel.hytale.server.npc.role.builders.BuilderRole; +import java.util.ArrayList; import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -24,6 +30,13 @@ public class DebugSupport { protected boolean traceFail; protected boolean traceSensorFails; protected Sensor lastFailingSensor; + protected List debugFlagsChangeListeners = new ArrayList<>(); + protected boolean visSensorRanges; + protected int currentSensorColorIndex; + @Nullable + protected List sensorVisDataList; + @Nullable + protected Map, List> entityVisDataMap; public DebugSupport(NPCEntity parent, @Nonnull BuilderRole builder) { this.parent = parent; @@ -91,7 +104,8 @@ public class DebugSupport { public void setDebugFlags(EnumSet debugFlags) { this.debugFlags = debugFlags; - this.activate(); + this.onDebugFlagsChanged(); + this.notifyDebugFlagsListeners(debugFlags); } public boolean isDebugFlagSet(RoleDebugFlags flag) { @@ -108,12 +122,92 @@ public class DebugSupport { return false; } - public void activate() { + protected void onDebugFlagsChanged() { this.debugRoleSteering = this.isDebugFlagSet(RoleDebugFlags.SteeringRole); this.debugMotionSteering = this.isDebugFlagSet(RoleDebugFlags.MotionControllerSteer); this.traceFail = this.isDebugFlagSet(RoleDebugFlags.TraceFail); this.traceSuccess = this.isDebugFlagSet(RoleDebugFlags.TraceSuccess); this.traceSensorFails = this.isDebugFlagSet(RoleDebugFlags.TraceSensorFailures); - this.debugDisplay = RoleDebugDisplay.create(this.debugFlags); + this.visSensorRanges = this.isDebugFlagSet(RoleDebugFlags.VisSensorRanges); + this.debugDisplay = RoleDebugDisplay.create(this.debugFlags, this.debugDisplay); + } + + public void registerDebugFlagsListener(DebugSupport.DebugFlagsChangeListener listener) { + this.debugFlagsChangeListeners.add(listener); + } + + public void removeDebugFlagsListener(DebugSupport.DebugFlagsChangeListener listener) { + this.debugFlagsChangeListeners.remove(listener); + } + + public void notifyDebugFlagsListeners(EnumSet flags) { + for (DebugSupport.DebugFlagsChangeListener listener : this.debugFlagsChangeListeners) { + listener.onDebugFlagsChanged(flags); + } + } + + public boolean isVisSensorRanges() { + return this.visSensorRanges; + } + + public void beginSensorVisualization() { + this.currentSensorColorIndex = 0; + if (this.sensorVisDataList != null) { + this.sensorVisDataList.clear(); + } + + if (this.entityVisDataMap != null) { + for (List list : this.entityVisDataMap.values()) { + list.clear(); + } + } + } + + public int recordSensorRange(double range, double minRange, double viewAngle) { + if (this.sensorVisDataList == null) { + this.sensorVisDataList = new ArrayList<>(); + } + + int colorIndex = this.currentSensorColorIndex++; + this.sensorVisDataList.add(new DebugSupport.SensorVisData(range, minRange, colorIndex, viewAngle)); + return colorIndex; + } + + public void recordEntityCheck(@Nonnull Ref entityRef, int sensorColorIndex, boolean matched) { + if (this.entityVisDataMap == null) { + this.entityVisDataMap = new HashMap<>(); + } + + this.entityVisDataMap.computeIfAbsent(entityRef, k -> new ArrayList<>()).add(new DebugSupport.EntityVisData(sensorColorIndex, matched)); + } + + @Nullable + public List getSensorVisData() { + return this.sensorVisDataList; + } + + @Nullable + public Map, List> getEntityVisData() { + return this.entityVisDataMap; + } + + public boolean hasSensorVisData() { + return this.sensorVisDataList != null && !this.sensorVisDataList.isEmpty(); + } + + public void clearSensorVisData() { + if (this.sensorVisDataList != null) { + this.sensorVisDataList.clear(); + } + } + + public interface DebugFlagsChangeListener { + void onDebugFlagsChanged(EnumSet var1); + } + + public record EntityVisData(int sensorColorIndex, boolean matched) { + } + + public record SensorVisData(double range, double minRange, int colorIndex, double viewAngle) { } } diff --git a/src/com/hypixel/hytale/server/npc/role/support/StateSupport.java b/src/com/hypixel/hytale/server/npc/role/support/StateSupport.java index 28b486de..ff0e6870 100644 --- a/src/com/hypixel/hytale/server/npc/role/support/StateSupport.java +++ b/src/com/hypixel/hytale/server/npc/role/support/StateSupport.java @@ -4,9 +4,8 @@ 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.ComponentUpdate; -import com.hypixel.hytale.protocol.ComponentUpdateType; import com.hypixel.hytale.protocol.GameMode; +import com.hypixel.hytale.protocol.InteractableUpdate; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.entity.group.EntityGroup; import com.hypixel.hytale.server.core.modules.entity.component.Interactable; @@ -51,6 +50,7 @@ public class StateSupport { protected Set> interactablePlayers; protected Set> interactedPlayers; protected Map, String> contextualInteractions; + protected String lastHint; @Nullable protected Ref interactionIterationTarget; @Nullable @@ -315,21 +315,24 @@ public class StateSupport { this.interactablePlayers.remove(playerReference); } - if (showPrompt) { - boolean hasComponent = store.getArchetype(entityRef).contains(Interactable.getComponentType()); - if (interactable) { - boolean needsHint = !wasInteractable && hint != null; - if (!hasComponent) { - store.ensureComponent(entityRef, Interactable.getComponentType()); - needsHint = hint != null; - } - - if (needsHint) { - this.sendInteractionHintToPlayer(entityRef, playerReference, hint, store); - } - } else if (hasComponent && this.interactablePlayers.isEmpty()) { - store.removeComponent(entityRef, Interactable.getComponentType()); + boolean hasComponent = store.getArchetype(entityRef).contains(Interactable.getComponentType()); + if (interactable) { + if (!showPrompt) { + hint = ""; } + + boolean needsHint = hint != null && !hint.equals(this.lastHint); + if (!hasComponent) { + store.ensureComponent(entityRef, Interactable.getComponentType()); + needsHint = hint != null && !hint.isEmpty(); + } + + if (needsHint) { + this.sendInteractionHintToPlayer(entityRef, playerReference, hint, store); + this.lastHint = hint; + } + } else if (hasComponent && this.interactablePlayers.isEmpty()) { + store.removeComponent(entityRef, Interactable.getComponentType()); } } @@ -338,9 +341,7 @@ public class StateSupport { ) { EntityTrackerSystems.EntityViewer viewerComponent = store.getComponent(playerReference, EntityTrackerSystems.EntityViewer.getComponentType()); if (viewerComponent != null && viewerComponent.visible.contains(entityRef)) { - ComponentUpdate update = new ComponentUpdate(); - update.type = ComponentUpdateType.Interactable; - update.interactionHint = hint; + InteractableUpdate update = new InteractableUpdate(hint); viewerComponent.queueUpdate(entityRef, update); } } 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/npc/systems/RoleSystems.java b/src/com/hypixel/hytale/server/npc/systems/RoleSystems.java index c25c6bd2..17d44512 100644 --- a/src/com/hypixel/hytale/server/npc/systems/RoleSystems.java +++ b/src/com/hypixel/hytale/server/npc/systems/RoleSystems.java @@ -15,10 +15,17 @@ import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.HolderSystem; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.component.system.tick.TickingSystem; +import com.hypixel.hytale.math.matrix.Matrix4d; +import com.hypixel.hytale.math.shape.Box; +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.protocol.GameMode; import com.hypixel.hytale.server.core.entity.Frozen; import com.hypixel.hytale.server.core.entity.entities.Player; +import com.hypixel.hytale.server.core.modules.debug.DebugUtils; import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox; +import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation; import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent; import com.hypixel.hytale.server.core.modules.entity.component.NewSpawnComponent; import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent; @@ -29,17 +36,22 @@ import com.hypixel.hytale.server.core.modules.entity.system.TransformSystems; import com.hypixel.hytale.server.core.modules.interaction.InteractionModule; 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.TargetUtil; import com.hypixel.hytale.server.npc.NPCPlugin; import com.hypixel.hytale.server.npc.components.StepComponent; import com.hypixel.hytale.server.npc.entities.NPCEntity; import com.hypixel.hytale.server.npc.movement.controllers.MotionController; import com.hypixel.hytale.server.npc.role.Role; import com.hypixel.hytale.server.npc.role.RoleDebugDisplay; +import com.hypixel.hytale.server.npc.role.RoleDebugFlags; +import com.hypixel.hytale.server.npc.role.support.DebugSupport; import com.hypixel.hytale.server.npc.role.support.EntitySupport; import com.hypixel.hytale.server.npc.role.support.MarkedEntitySupport; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.Map.Entry; import java.util.logging.Level; import javax.annotation.Nonnull; @@ -308,7 +320,7 @@ public class RoleSystems { Role role = npcComponent.getRole(); role.getStateSupport().activate(); - role.getDebugSupport().activate(); + role.getDebugSupport().notifyDebugFlagsListeners(role.getDebugSupport().getDebugFlags()); ModelComponent modelComponent = holder.getComponent(this.modelComponentType); assert modelComponent != null; @@ -336,6 +348,15 @@ public class RoleSystems { } public static class RoleDebugSystem extends SteppableTickingSystem { + private static final float DEBUG_SHAPE_TIME = 0.1F; + private static final float SENSOR_VIS_OPACITY = 0.4F; + private static final double FULL_CIRCLE_EPSILON = 0.01; + private static final float LEASH_SPHERE_RADIUS = 0.3F; + private static final float LEASH_RING_OUTER_RADIUS = 0.5F; + private static final float LEASH_RING_INNER_RADIUS = 0.4F; + private static final float NPC_RING_THICKNESS = 0.1F; + private static final float NPC_RING_OFFSET = 0.1F; + private static final float LEASH_LINE_THICKNESS = 0.05F; @Nonnull private final ComponentType npcComponentType; @Nonnull @@ -360,7 +381,7 @@ public class RoleSystems { @Nonnull @Override public Query getQuery() { - return this.npcComponentType; + return Query.and(this.npcComponentType, TransformComponent.getComponentType(), BoundingBox.getComponentType()); } @Override @@ -376,10 +397,235 @@ public class RoleSystems { assert npcComponent != null; Role role = npcComponent.getRole(); - RoleDebugDisplay debugDisplay = role.getDebugSupport().getDebugDisplay(); - if (debugDisplay != null) { - debugDisplay.display(role, index, archetypeChunk, commandBuffer); + if (role != null) { + DebugSupport debugSupport = role.getDebugSupport(); + RoleDebugDisplay debugDisplay = debugSupport.getDebugDisplay(); + if (debugDisplay != null) { + debugDisplay.display(role, index, archetypeChunk, commandBuffer); + } + + if (debugSupport.isDebugFlagSet(RoleDebugFlags.VisMarkedTargets)) { + renderMarkedTargetArrows(role, index, archetypeChunk, commandBuffer); + } + + boolean hasSensorVis = debugSupport.hasSensorVisData(); + boolean hasLeashVis = debugSupport.isDebugFlagSet(RoleDebugFlags.VisLeashPosition); + if (hasSensorVis || hasLeashVis) { + Ref npcRef = archetypeChunk.getReferenceTo(index); + TransformComponent transformComponent = archetypeChunk.getComponent(index, TransformComponent.getComponentType()); + + assert transformComponent != null; + + BoundingBox boundingBoxComponent = archetypeChunk.getComponent(index, BoundingBox.getComponentType()); + + assert boundingBoxComponent != null; + + World world = commandBuffer.getExternalData().getWorld(); + if (hasSensorVis) { + renderSensorVisualization(debugSupport, npcRef, transformComponent, boundingBoxComponent, world, commandBuffer); + } + + if (hasLeashVis) { + renderLeashPositionVisualization(npcComponent, npcRef, transformComponent, boundingBoxComponent, world); + } + } } } + + private static void renderMarkedTargetArrows( + @Nonnull Role role, int index, @Nonnull ArchetypeChunk archetypeChunk, @Nonnull CommandBuffer commandBuffer + ) { + Ref npcRef = archetypeChunk.getReferenceTo(index); + Transform npcLook = TargetUtil.getLook(npcRef, commandBuffer); + Vector3d npcEyePosition = npcLook.getPosition(); + World world = commandBuffer.getExternalData().getWorld(); + MarkedEntitySupport markedEntitySupport = role.getMarkedEntitySupport(); + Ref[] entityTargets = markedEntitySupport.getEntityTargets(); + + for (int slotIndex = 0; slotIndex < entityTargets.length; slotIndex++) { + Ref targetRef = entityTargets[slotIndex]; + if (targetRef != null && targetRef.isValid()) { + Transform targetLook = TargetUtil.getLook(targetRef, commandBuffer); + Vector3d targetEyePosition = targetLook.getPosition(); + Vector3d direction = new Vector3d( + targetEyePosition.x - npcEyePosition.x, targetEyePosition.y - npcEyePosition.y, targetEyePosition.z - npcEyePosition.z + ); + Vector3f color = DebugUtils.INDEXED_COLORS[slotIndex % DebugUtils.INDEXED_COLORS.length]; + DebugUtils.addArrow(world, npcEyePosition, direction, color, 0.1F, false); + } + } + } + + private static void renderSensorVisualization( + @Nonnull DebugSupport debugSupport, + @Nonnull Ref npcRef, + @Nonnull TransformComponent transformComponent, + @Nonnull BoundingBox boundingBoxComponent, + @Nonnull World world, + @Nonnull CommandBuffer commandBuffer + ) { + List sensorDataList = debugSupport.getSensorVisData(); + if (sensorDataList != null) { + Vector3d npcPosition = transformComponent.getPosition(); + double npcMidHeight = boundingBoxComponent.getBoundingBox().max.y / 2.0; + HeadRotation headRotation = commandBuffer.getComponent(npcRef, HeadRotation.getComponentType()); + double heading = headRotation != null ? headRotation.getRotation().getYaw() : transformComponent.getRotation().getYaw(); + sensorDataList.sort((a, b) -> Double.compare(b.range(), a.range())); + double discStackOffset = 0.1; + + for (int i = 0; i < sensorDataList.size(); i++) { + DebugSupport.SensorVisData sensorData = sensorDataList.get(i); + Vector3f color = DebugUtils.INDEXED_COLORS[sensorData.colorIndex() % DebugUtils.INDEXED_COLORS.length]; + double height = npcPosition.y + npcMidHeight + i * 0.1; + if (sensorData.viewAngle() > 0.0 && sensorData.viewAngle() < 6.273185482025147) { + double sectorHeading = -heading + Math.PI; + DebugUtils.addSector( + world, + npcPosition.x, + height, + npcPosition.z, + sectorHeading, + sensorData.range(), + sensorData.viewAngle(), + sensorData.minRange(), + color, + 0.4F, + 0.1F, + false + ); + } else { + DebugUtils.addDisc(world, npcPosition.x, height, npcPosition.z, sensorData.range(), sensorData.minRange(), color, 0.4F, 0.1F, false); + } + } + + Map, List> entityDataMap = debugSupport.getEntityVisData(); + if (entityDataMap != null) { + double markerOffset = 0.3; + double sphereStackOffset = 0.3; + double defaultEntityHeight = 2.0; + + for (Entry, List> entry : entityDataMap.entrySet()) { + Ref entityRef = entry.getKey(); + List checks = entry.getValue(); + if (!checks.isEmpty() && entityRef.isValid()) { + TransformComponent entityTransform = commandBuffer.getComponent(entityRef, TransformComponent.getComponentType()); + if (entityTransform != null) { + Vector3d entityPosition = entityTransform.getPosition(); + BoundingBox entityBoundingBox = commandBuffer.getComponent(entityRef, BoundingBox.getComponentType()); + double entityHeight = entityBoundingBox != null ? entityBoundingBox.getBoundingBox().max.y : 2.0; + double markerBaseHeight = entityHeight + 0.3; + boolean anyMatched = false; + + for (DebugSupport.EntityVisData check : checks) { + if (check.matched()) { + anyMatched = true; + break; + } + } + + int sphereCount = 0; + + for (DebugSupport.EntityVisData checkx : checks) { + if (checkx.matched()) { + Vector3f sensorColor = DebugUtils.INDEXED_COLORS[checkx.sensorColorIndex() % DebugUtils.INDEXED_COLORS.length]; + double sphereHeight = markerBaseHeight + sphereCount * 0.3; + DebugUtils.addSphere(world, entityPosition.x, entityPosition.y + sphereHeight, entityPosition.z, sensorColor, 0.2, 0.1F); + sphereCount++; + } + } + + if (!anyMatched) { + DebugUtils.addCube(world, entityPosition.x, entityPosition.y + markerBaseHeight, entityPosition.z, DebugUtils.COLOR_GRAY, 0.2, 0.1F); + } + + DebugUtils.addLine( + world, + npcPosition.x, + npcPosition.y + npcMidHeight, + npcPosition.z, + entityPosition.x, + entityPosition.y + markerBaseHeight, + entityPosition.z, + DebugUtils.COLOR_GRAY, + 0.03, + 0.1F, + false + ); + } + } + } + } + + debugSupport.clearSensorVisData(); + } + } + + private static void renderLeashPositionVisualization( + @Nonnull NPCEntity npcComponent, + @Nonnull Ref npcRef, + @Nonnull TransformComponent transformComponent, + @Nonnull BoundingBox boundingBoxComponent, + @Nonnull World world + ) { + if (npcComponent.requiresLeashPosition()) { + Box boundingBox = boundingBoxComponent.getBoundingBox(); + double npcWidth = boundingBox.max.x - boundingBox.min.x; + double npcDepth = boundingBox.max.z - boundingBox.min.z; + double npcRingOuterRadius = Math.max(npcWidth, npcDepth) / 2.0 + 0.1F; + double npcRingInnerRadius = npcRingOuterRadius - 0.1F; + int colorIndex = Math.abs(npcRef.getIndex()) % DebugUtils.INDEXED_COLORS.length; + Vector3f color = DebugUtils.INDEXED_COLORS[colorIndex]; + Vector3d leashPoint = npcComponent.getLeashPoint(); + DebugUtils.addSphere(world, leashPoint, color, 0.3F, 0.1F); + Vector3d npcPosition = transformComponent.getPosition(); + double npcMidHeight = boundingBox.max.y / 2.0; + double npcMidY = npcPosition.y + npcMidHeight; + double dirX = npcPosition.x - leashPoint.x; + double dirZ = npcPosition.z - leashPoint.z; + double horizontalDist = Math.sqrt(dirX * dirX + dirZ * dirZ); + if (horizontalDist > 0.001) { + double verticalDist = npcMidY - leashPoint.y; + double pitchAngle = Math.atan2(verticalDist, horizontalDist); + double yawAngle = Math.atan2(dirZ, dirX); + addChainRing(world, leashPoint.x, leashPoint.y, leashPoint.z, 0.5, 0.4F, yawAngle, -pitchAngle, color); + addChainRing(world, npcPosition.x, npcMidY, npcPosition.z, npcRingOuterRadius, npcRingInnerRadius, yawAngle + Math.PI, pitchAngle, color); + double hDirX = dirX / horizontalDist; + double hDirZ = dirZ / horizontalDist; + double cosPitch = Math.cos(pitchAngle); + double sinPitch = Math.sin(pitchAngle); + double leashEdgeX = leashPoint.x + hDirX * 0.5 * cosPitch; + double leashEdgeY = leashPoint.y + sinPitch * 0.5; + double leashEdgeZ = leashPoint.z + hDirZ * 0.5 * cosPitch; + double npcEdgeX = npcPosition.x - hDirX * npcRingOuterRadius * cosPitch; + double npcEdgeY = npcMidY - sinPitch * npcRingOuterRadius; + double npcEdgeZ = npcPosition.z - hDirZ * npcRingOuterRadius * cosPitch; + DebugUtils.addLine(world, leashEdgeX, leashEdgeY, leashEdgeZ, npcEdgeX, npcEdgeY, npcEdgeZ, color, 0.05F, 0.1F, false); + } else { + DebugUtils.addDisc(world, leashPoint.x, leashPoint.y, leashPoint.z, 0.5, 0.4F, color, 0.8F, 0.1F, false); + DebugUtils.addDisc(world, npcPosition.x, npcMidY, npcPosition.z, npcRingOuterRadius, npcRingInnerRadius, color, 0.8F, 0.1F, false); + DebugUtils.addLine(world, leashPoint.x, leashPoint.y, leashPoint.z, npcPosition.x, npcMidY, npcPosition.z, color, 0.05F, 0.1F, false); + } + } + } + + private static void addChainRing( + @Nonnull World world, + double x, + double y, + double z, + double outerRadius, + double innerRadius, + double yawAngle, + double pitchAngle, + @Nonnull Vector3f color + ) { + Matrix4d matrix = new Matrix4d(); + matrix.identity(); + matrix.translate(x, y, z); + Matrix4d tmp = new Matrix4d(); + matrix.rotateAxis(yawAngle, 0.0, 1.0, 0.0, tmp); + matrix.rotateAxis(pitchAngle, 0.0, 0.0, 1.0, tmp); + DebugUtils.addDisc(world, matrix, outerRadius, innerRadius, color, 0.8F, 0.1F, false); + } } } diff --git a/src/com/hypixel/hytale/server/npc/util/AimingData.java b/src/com/hypixel/hytale/server/npc/util/AimingData.java index 03ccb410..b460d804 100644 --- a/src/com/hypixel/hytale/server/npc/util/AimingData.java +++ b/src/com/hypixel/hytale/server/npc/util/AimingData.java @@ -69,10 +69,6 @@ public class AimingData implements ExtraInfoProvider { return this.yaw[flatTrajectory ? 0 : 1]; } - public boolean isBallistic() { - return this.ballisticData != null; - } - @Nullable public BallisticData getBallisticData() { return this.ballisticData; @@ -121,7 +117,7 @@ public class AimingData implements ExtraInfoProvider { } } - public void setTarget(Ref ref) { + public void setTarget(@Nullable Ref ref) { this.target = ref; } @@ -146,7 +142,7 @@ public class AimingData implements ExtraInfoProvider { double d2 = xxzz + y * y; if (d2 < 0.01) { return this.haveSolution = false; - } else if (!this.isBallistic()) { + } else if (this.ballisticData == null) { this.yaw[0] = this.yaw[1] = PhysicsMath.normalizeTurnAngle(PhysicsMath.headingFromDirection(x, z)); this.pitch[0] = this.pitch[1] = PhysicsMath.pitchFromDirection(x, y, z); return this.haveSolution = true; @@ -163,7 +159,10 @@ public class AimingData implements ExtraInfoProvider { double v2 = NPCPhysicsMath.dotProduct(vx, vy, vz); if (v2 < 1.0E-4) { - if (this.haveSolution = this.computeStaticSolution(Math.sqrt(xxzz), y)) { + this.haveSolution = AimingHelper.computePitch( + Math.sqrt(xxzz), y, this.ballisticData.getMuzzleVelocity(), this.ballisticData.getGravity(), this.pitch + ); + if (this.haveSolution) { this.yaw[0] = this.yaw[1] = PhysicsMath.normalizeTurnAngle(PhysicsMath.headingFromDirection(x, z)); } @@ -233,7 +232,7 @@ public class AimingData implements ExtraInfoProvider { return false; } else { double differenceYaw = NPCPhysicsMath.turnAngle(yaw, this.getYaw()); - if (!this.isBallistic()) { + if (this.ballisticData == null) { return -hitAngle <= differenceYaw && differenceYaw <= hitAngle; } else { double differencePitch = NPCPhysicsMath.turnAngle(pitch, this.getPitch()); @@ -265,8 +264,4 @@ public class AimingData implements ExtraInfoProvider { this.pitchAdjustOffset = false; this.haveAttacked = false; } - - protected boolean computeStaticSolution(double dx, double dy) { - return this.haveSolution = AimingHelper.computePitch(dx, dy, this.ballisticData.getMuzzleVelocity(), this.ballisticData.getGravity(), this.pitch); - } } 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/SpawnBeaconsCommand.java b/src/com/hypixel/hytale/server/spawning/commands/SpawnBeaconsCommand.java index 870e2375..6aa628d2 100644 --- a/src/com/hypixel/hytale/server/spawning/commands/SpawnBeaconsCommand.java +++ b/src/com/hypixel/hytale/server/spawning/commands/SpawnBeaconsCommand.java @@ -15,7 +15,7 @@ import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredAr import com.hypixel.hytale.server.core.command.system.arguments.types.AssetArgumentType; import com.hypixel.hytale.server.core.command.system.basecommands.AbstractCommandCollection; import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand; -import com.hypixel.hytale.server.core.command.system.exceptions.GeneralCommandException; +import com.hypixel.hytale.server.core.command.system.basecommands.AbstractTargetEntityCommand; import com.hypixel.hytale.server.core.entity.UUIDComponent; import com.hypixel.hytale.server.core.entity.nameplate.Nameplate; import com.hypixel.hytale.server.core.modules.entity.component.DisplayNameComponent; @@ -31,6 +31,7 @@ import com.hypixel.hytale.server.spawning.beacons.LegacySpawnBeaconEntity; import com.hypixel.hytale.server.spawning.beacons.SpawnBeacon; import com.hypixel.hytale.server.spawning.util.FloodFillPositionSelector; import com.hypixel.hytale.server.spawning.wrappers.BeaconSpawnWrapper; +import it.unimi.dsi.fastutil.objects.ObjectList; import javax.annotation.Nonnull; public class SpawnBeaconsCommand extends AbstractCommandCollection { @@ -103,11 +104,10 @@ public class SpawnBeaconsCommand extends AbstractCommandCollection { } } - private static class ManualTrigger extends AbstractPlayerCommand { - private static final Message MESSAGE_COMMANDS_SPAWNING_BEACONS_TRIGGER_NOT_BEACON = Message.translation( - "server.commands.spawning.beacons.trigger.notBeacon" + private static class ManualTrigger extends AbstractTargetEntityCommand { + private static final Message MESSAGE_COMMANDS_SPAWNING_BEACONS_TRIGGER_NO_BEACONS = Message.translation( + "server.commands.spawning.beacons.trigger.no_beacons" ); - private static final Message MESSAGE_COMMANDS_SPAWNING_BEACONS_TRIGGER_NO_SPOTS = Message.translation("server.commands.spawning.beacons.trigger.no_spots"); public ManualTrigger() { super("trigger", "server.commands.spawning.beacons.trigger.desc"); @@ -115,22 +115,40 @@ public class SpawnBeaconsCommand extends AbstractCommandCollection { @Override protected void execute( - @Nonnull CommandContext context, @Nonnull Store store, @Nonnull Ref ref, @Nonnull PlayerRef playerRef, @Nonnull World world + @Nonnull CommandContext context, @Nonnull ObjectList> entities, @Nonnull World world, @Nonnull Store store ) { - FloodFillPositionSelector positionSelectorComponent = store.getComponent(ref, FloodFillPositionSelector.getComponentType()); - if (positionSelectorComponent == null) { - throw new GeneralCommandException(MESSAGE_COMMANDS_SPAWNING_BEACONS_TRIGGER_NOT_BEACON); + if (entities.isEmpty()) { + context.sendMessage(MESSAGE_COMMANDS_SPAWNING_BEACONS_TRIGGER_NO_BEACONS); } else { - SpawnBeacon spawnBeaconComponent = store.getComponent(ref, SpawnBeacon.getComponentType()); - if (spawnBeaconComponent == null) { - throw new GeneralCommandException(MESSAGE_COMMANDS_SPAWNING_BEACONS_TRIGGER_NOT_BEACON); - } else { - if (!spawnBeaconComponent.manualTrigger(ref, positionSelectorComponent, ref, store)) { - context.sendMessage(MESSAGE_COMMANDS_SPAWNING_BEACONS_TRIGGER_NO_SPOTS); - } else { - context.sendMessage(Message.translation("server.commands.spawning.beacons.trigger.success")); + int count = 0; + + for (Ref ref : entities) { + if (ref != null && ref.isValid()) { + UUIDComponent uuid = store.getComponent(ref, UUIDComponent.getComponentType()); + if (uuid != null) { + FloodFillPositionSelector positionSelectorComponent = store.getComponent(ref, FloodFillPositionSelector.getComponentType()); + if (positionSelectorComponent != null) { + SpawnBeacon spawnBeaconComponent = store.getComponent(ref, SpawnBeacon.getComponentType()); + if (spawnBeaconComponent != null) { + if (!spawnBeaconComponent.manualTrigger(ref, positionSelectorComponent, ref, store)) { + Message message = Message.translation("server.commands.spawning.beacons.trigger.no_spots"); + message.param("id", uuid.getUuid().toString()); + context.sendMessage(message); + } else { + Message message = Message.translation("server.commands.spawning.beacons.trigger.success"); + message.param("id", uuid.getUuid().toString()); + context.sendMessage(message); + count++; + } + } + } + } } } + + if (count == 0) { + context.sendMessage(MESSAGE_COMMANDS_SPAWNING_BEACONS_TRIGGER_NO_BEACONS); + } } } } 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/suppression/system/ChunkSuppressionSystems.java b/src/com/hypixel/hytale/server/spawning/suppression/system/ChunkSuppressionSystems.java index 8ed36fc7..19bfc2ab 100644 --- a/src/com/hypixel/hytale/server/spawning/suppression/system/ChunkSuppressionSystems.java +++ b/src/com/hypixel/hytale/server/spawning/suppression/system/ChunkSuppressionSystems.java @@ -84,8 +84,10 @@ public class ChunkSuppressionSystems { for (int i = 0; i < addQueue.size(); i++) { Entry, ChunkSuppressionEntry> entry = addQueue.get(i); Ref ref = entry.getKey(); - store.putComponent(ref, this.chunkSuppressionEntryComponentType, entry.getValue()); - SpawningPlugin.get().getLogger().at(Level.FINEST).log("Annotated chunk %s from queue", ref); + if (ref.isValid()) { + store.putComponent(ref, this.chunkSuppressionEntryComponentType, entry.getValue()); + SpawningPlugin.get().getLogger().at(Level.FINEST).log("Annotated chunk %s from queue", ref); + } } addQueue.clear(); @@ -93,10 +95,12 @@ public class ChunkSuppressionSystems { List> removeQueue = queue.getToRemove(); if (!removeQueue.isEmpty()) { - for (int i = 0; i < removeQueue.size(); i++) { - Ref ref = removeQueue.get(i); - store.tryRemoveComponent(ref, this.chunkSuppressionEntryComponentType); - SpawningPlugin.get().getLogger().at(Level.FINEST).log("Removed annotation from chunk %s from queue", ref); + for (int ix = 0; ix < removeQueue.size(); ix++) { + Ref ref = removeQueue.get(ix); + if (ref.isValid()) { + store.tryRemoveComponent(ref, this.chunkSuppressionEntryComponentType); + SpawningPlugin.get().getLogger().at(Level.FINEST).log("Removed annotation from chunk %s from queue", ref); + } } removeQueue.clear(); diff --git a/src/com/hypixel/hytale/server/spawning/suppression/system/SpawnSuppressionSystems.java b/src/com/hypixel/hytale/server/spawning/suppression/system/SpawnSuppressionSystems.java index d3096a11..4e72b6cf 100644 --- a/src/com/hypixel/hytale/server/spawning/suppression/system/SpawnSuppressionSystems.java +++ b/src/com/hypixel/hytale/server/spawning/suppression/system/SpawnSuppressionSystems.java @@ -208,7 +208,7 @@ public class SpawnSuppressionSystems { @Override public void onSystemUnregistered() { - this.eventRegistry.shutdown(); + this.eventRegistry.shutdownAndCleanup(true); } private void onSpawnSuppressionsLoaded(@Nonnull LoadedAssetsEvent> event) { 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/spawning/world/system/WorldSpawningSystem.java b/src/com/hypixel/hytale/server/spawning/world/system/WorldSpawningSystem.java index 2514d2c4..f2283af2 100644 --- a/src/com/hypixel/hytale/server/spawning/world/system/WorldSpawningSystem.java +++ b/src/com/hypixel/hytale/server/spawning/world/system/WorldSpawningSystem.java @@ -74,28 +74,27 @@ public class WorldSpawningSystem extends TickingSystem { if (chunkRef != null) { int environmentIndex = entry.getEnvironmentIndex(); ChunkSpawnData chunkSpawnDataComponent = store.getComponent(chunkRef, this.chunkSpawnDataComponentType); - - assert chunkSpawnDataComponent != null; - - ChunkEnvironmentSpawnData environmentSpawnData = chunkSpawnDataComponent.getEnvironmentSpawnData(environmentIndex); - int segmentCount = -environmentSpawnData.getSegmentCount(); - worldSpawnDataResource.adjustSegmentCount(segmentCount); - WorldEnvironmentSpawnData worldEnvironmentSpawnData = worldSpawnDataResource.getWorldEnvironmentSpawnData(environmentIndex); - double expectedNPCs = worldEnvironmentSpawnData.getExpectedNPCs(); - worldEnvironmentSpawnData.adjustSegmentCount(segmentCount); - worldEnvironmentSpawnData.updateExpectedNPCs(worldTimeResource.getMoonPhase()); - environmentSpawnData.markProcessedAsUnspawnable(); - HytaleLogger.Api context = LOGGER.at(Level.FINEST); - if (context.isEnabled()) { - Environment environmentAsset = Environment.getAssetMap().getAsset(environmentIndex); - if (environmentAsset != null) { - String environment = environmentAsset.getId(); - context.log( - "Reducing expected NPC count for %s due to un-spawnable chunk. Was %s, now %s", - environment, - expectedNPCs, - worldEnvironmentSpawnData.getExpectedNPCs() - ); + if (chunkSpawnDataComponent != null) { + ChunkEnvironmentSpawnData environmentSpawnData = chunkSpawnDataComponent.getEnvironmentSpawnData(environmentIndex); + int segmentCount = -environmentSpawnData.getSegmentCount(); + worldSpawnDataResource.adjustSegmentCount(segmentCount); + WorldEnvironmentSpawnData worldEnvironmentSpawnData = worldSpawnDataResource.getWorldEnvironmentSpawnData(environmentIndex); + double expectedNPCs = worldEnvironmentSpawnData.getExpectedNPCs(); + worldEnvironmentSpawnData.adjustSegmentCount(segmentCount); + worldEnvironmentSpawnData.updateExpectedNPCs(worldTimeResource.getMoonPhase()); + environmentSpawnData.markProcessedAsUnspawnable(); + HytaleLogger.Api context = LOGGER.at(Level.FINEST); + if (context.isEnabled()) { + Environment environmentAsset = Environment.getAssetMap().getAsset(environmentIndex); + if (environmentAsset != null) { + String environment = environmentAsset.getId(); + context.log( + "Reducing expected NPC count for %s due to un-spawnable chunk. Was %s, now %s", + environment, + expectedNPCs, + worldEnvironmentSpawnData.getExpectedNPCs() + ); + } } } } 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..c315d0a3 100644 --- a/src/com/hypixel/hytale/server/worldgen/HytaleWorldGenProvider.java +++ b/src/com/hypixel/hytale/server/worldgen/HytaleWorldGenProvider.java @@ -1,8 +1,10 @@ package com.hypixel.hytale.server.worldgen; 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; @@ -11,49 +13,100 @@ import com.hypixel.hytale.server.core.universe.world.worldgen.WorldGenLoadExcept import com.hypixel.hytale.server.core.universe.world.worldgen.provider.IWorldGenProvider; import com.hypixel.hytale.server.worldgen.loader.ChunkGeneratorJsonLoader; import com.hypixel.hytale.server.worldgen.prefab.PrefabStoreRoot; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; 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 HytaleWorldGenProvider.WorldGenBuilderCodec CODEC = new HytaleWorldGenProvider.WorldGenBuilderCodec( + 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 + public Semver getVersion() { + return this.version; + } + @Nonnull @Override public IWorldGen getGenerator() throws WorldGenLoadException { Path worldGenPath; if (this.path != null) { - worldGenPath = PathUtil.get(this.path); + worldGenPath = Path.of(this.path); + if (!PathUtil.isInTrustedRoot(worldGenPath)) { + throw new WorldGenLoadException("World gen path must be within a trusted directory: " + this.path); + } } else { worldGenPath = Universe.getWorldGenPath(); } if (!"Default".equals(this.name) || !Files.exists(worldGenPath.resolve("World.json"))) { - worldGenPath = worldGenPath.resolve(this.name); + Path resolved = PathUtil.resolvePathWithinDir(worldGenPath, this.name); + if (resolved == null) { + throw new WorldGenLoadException("Invalid world gen name: " + this.name); + } + + worldGenPath = resolved; } 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 + "'}"; + } + + public static class WorldGenBuilderCodec extends BuilderCodec { + private final Object lock = new Object(); + private final Map versions = new Object2ObjectOpenHashMap<>(); + + protected WorldGenBuilderCodec(@Nonnull BuilderCodec.BuilderBase builder) { + super(builder); + } + + public HytaleWorldGenProvider getDefaultValue(ExtraInfo extraInfo) { + HytaleWorldGenProvider value = new HytaleWorldGenProvider(); + synchronized (this.lock) { + value.version = this.versions.getOrDefault("Default", HytaleWorldGenProvider.MIN_VERSION); + } + + this.afterDecode(value, extraInfo); + return value; + } + + public void setVersions(@Nonnull Map versions) { + synchronized (this.lock) { + this.versions.clear(); + this.versions.putAll(versions); + } + } } } 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..459e25ce --- /dev/null +++ b/src/com/hypixel/hytale/server/worldgen/loader/AssetFileSystem.java @@ -0,0 +1,133 @@ +package com.hypixel.hytale.server.worldgen.loader; + +import com.hypixel.hytale.assetstore.AssetPack; +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 List packs; + 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.packs = getAssetPacks(config, packRoot -> FileIO.exists(packRoot, assetPath)); + this.packRoots = new FileIOSystem.PathArray(getAssetRoots(this.packs)); + } + + @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 List packs() { + return this.packs; + } + + public static List getAssetPacks(@Nonnull WorldGenConfig config, @Nonnull Predicate filter) { + AssetModule assets = AssetModule.get(); + Path versionsDir = WorldGenPlugin.getVersionsPath(); + List allPacks = assets.getAssetPacks(); + ObjectArrayList packs = new ObjectArrayList<>(allPacks.size()); + + for (int i = allPacks.size() - 1; i >= 1; i--) { + AssetPack pack = allPacks.get(i); + if (!FileIO.startsWith(pack.getRoot(), versionsDir) && filter.test(pack.getRoot())) { + packs.add(allPacks.get(i)); + } + } + + for (int ix = allPacks.size() - 1; ix >= 1; ix--) { + AssetPack pack = allPacks.get(ix); + if (FileIO.startsWith(pack.getRoot(), versionsDir) && pack.getManifest().getVersion().compareTo(config.version()) <= 0 && filter.test(pack.getRoot())) { + packs.add(allPacks.get(ix)); + } + } + + packs.add(allPacks.getFirst()); + return List.copyOf(packs); + } + + public static Path[] getAssetRoots(@Nonnull List packs) { + Path[] roots = new Path[packs.size()]; + + for (int i = 0; i < packs.size(); i++) { + roots[i] = packs.get(i).getRoot(); + } + + return roots; + } + + 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..23a94a14 100644 --- a/src/com/hypixel/hytale/server/worldgen/loader/ChunkGeneratorJsonLoader.java +++ b/src/com/hypixel/hytale/server/worldgen/loader/ChunkGeneratorJsonLoader.java @@ -3,16 +3,21 @@ 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.assetstore.AssetPack; import com.hypixel.hytale.common.map.IWeightedMap; import com.hypixel.hytale.common.map.WeightedMap; +import com.hypixel.hytale.common.semver.Semver; import com.hypixel.hytale.common.util.ArrayUtil; +import com.hypixel.hytale.common.util.PathUtil; +import com.hypixel.hytale.logger.HytaleLogger; 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.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; @@ -20,14 +25,21 @@ import com.hypixel.hytale.server.worldgen.loader.context.FileContextLoader; import com.hypixel.hytale.server.worldgen.loader.context.FileLoadingContext; import com.hypixel.hytale.server.worldgen.loader.zone.ZonePatternProviderJsonLoader; import com.hypixel.hytale.server.worldgen.prefab.PrefabStoreRoot; +import com.hypixel.hytale.server.worldgen.util.LogUtil; import com.hypixel.hytale.server.worldgen.zone.Zone; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; +import java.util.Objects; 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 +51,25 @@ public class ChunkGeneratorJsonLoader extends Loader weightedMap = builder.build(); - Path maskFile = this.dataFolder.resolve(weightedMap.get(new FastRandom(this.seed.hashCode()))); - return (MaskProvider)(maskFile.getFileName().endsWith("Mask.json") - ? new ClimateMaskJsonLoader<>(this.seed, this.dataFolder, maskFile).load() - : new MaskProviderJsonLoader(this.seed, this.dataFolder, worldJson.get("Randomizer"), maskFile, worldSize, worldOffset).load()); + String maskName = weightedMap.get(new FastRandom(this.seed.hashCode())); + Path maskFile = PathUtil.resolvePathWithinDir(this.dataFolder, maskName); + if (maskFile == null) { + throw new Error("Invalid mask file path: " + maskName); + } else { + return (MaskProvider)(maskFile.getFileName().toString().endsWith("Mask.json") + ? new ClimateMaskJsonLoader<>(this.seed, this.dataFolder, maskFile).load() + : new MaskProviderJsonLoader(this.seed, this.dataFolder, worldJson.get("Randomizer"), maskFile, worldSize, worldOffset).load()); + } } @Nonnull @@ -173,15 +192,24 @@ public class ChunkGeneratorJsonLoader extends Loader packs) { + HytaleLogger.Api logger = LogUtil.getLogger().atInfo(); + Semver unversioned = new Semver(0L, 0L, 0L); + logger.log("Loading world-gen with the following asset-packs (highest priority first):"); + + for (int i = 0; i < packs.size(); i++) { + AssetPack pack = packs.get(i); + String name = pack.getName(); + Semver version = Objects.requireNonNullElse(pack.getManifest().getVersion(), unversioned); + Path location = pack.getPackLocation(); + logger.log("- [%3d] %s:%s - [%s]", i, name, version, location); } } diff --git a/src/com/hypixel/hytale/server/worldgen/loader/MaskProviderJsonLoader.java b/src/com/hypixel/hytale/server/worldgen/loader/MaskProviderJsonLoader.java index be36d18f..ad448ede 100644 --- a/src/com/hypixel/hytale/server/worldgen/loader/MaskProviderJsonLoader.java +++ b/src/com/hypixel/hytale/server/worldgen/loader/MaskProviderJsonLoader.java @@ -2,6 +2,8 @@ package com.hypixel.hytale.server.worldgen.loader; import com.google.gson.JsonElement; import com.hypixel.hytale.math.vector.Vector2i; +import com.hypixel.hytale.procedurallib.file.AssetLoader; +import com.hypixel.hytale.procedurallib.file.FileIO; import com.hypixel.hytale.procedurallib.json.CoordinateRandomizerJsonLoader; import com.hypixel.hytale.procedurallib.json.JsonLoader; import com.hypixel.hytale.procedurallib.json.SeedString; @@ -10,13 +12,25 @@ import com.hypixel.hytale.server.worldgen.chunk.MaskProvider; import com.hypixel.hytale.server.worldgen.zoom.FuzzyZoom; import com.hypixel.hytale.server.worldgen.zoom.PixelProvider; import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; import java.io.IOException; -import java.nio.file.Files; +import java.io.InputStream; import java.nio.file.Path; import javax.annotation.Nonnull; import javax.imageio.ImageIO; public class MaskProviderJsonLoader extends JsonLoader { + 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 +46,79 @@ 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); + List packs = AssetFileSystem.getAssetPacks(config, packRoot -> FileIO.exists(packRoot, assetPath)); + Path[] roots = AssetFileSystem.getAssetRoots(packs); + 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