diff --git a/src/main/java/dev/hytalemodding/RitualPlugin.java b/src/main/java/dev/hytalemodding/RitualPlugin.java index fd6a4ed..aa2e4a9 100644 --- a/src/main/java/dev/hytalemodding/RitualPlugin.java +++ b/src/main/java/dev/hytalemodding/RitualPlugin.java @@ -5,7 +5,9 @@ import com.hypixel.hytale.server.core.event.events.player.PlayerReadyEvent; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; import com.hypixel.hytale.server.core.util.Config; +import dev.hytalemodding.config.RitualConfig; import dev.hytalemodding.events.RitualBreakBlockEvent; +import dev.hytalemodding.events.RitualDropItemEvent; import dev.hytalemodding.events.RitualPlaceBlockEvent; import dev.hytalemodding.commands.ExampleCommand; import dev.hytalemodding.config.ExampleConfig; @@ -17,11 +19,11 @@ public class RitualPlugin extends JavaPlugin { public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); - private static Config config = null; + private static Config config = null; public RitualPlugin(@Nonnull JavaPluginInit init) { super(init); - config = this.withConfig("example_config", ExampleConfig.CODEC); + config = this.withConfig("ritual_config", RitualConfig.CODEC); } @Override @@ -32,12 +34,13 @@ public class RitualPlugin extends JavaPlugin { RitualSpawner ritualSpawner = new RitualSpawner(); this.getEntityStoreRegistry().registerSystem(new RitualPlaceBlockEvent(ritualSpawner)); this.getEntityStoreRegistry().registerSystem(new RitualBreakBlockEvent(ritualSpawner)); + this.getEntityStoreRegistry().registerSystem(new RitualDropItemEvent(ritualSpawner)); // Example - this.getCommandRegistry().registerCommand(new ExampleCommand("example", "An example command")); + /*this.getCommandRegistry().registerCommand(new ExampleCommand("example", "An example command")); if (getConfig().get().isEnabledWelcomeMessage()) { this.getEventRegistry().registerGlobal(PlayerReadyEvent.class, ExampleEvent::onPlayerReady); - } + }*/ } @Override @@ -48,7 +51,7 @@ public class RitualPlugin extends JavaPlugin { protected void shutdown() { } - public static Config getConfig() { + public static Config getConfig() { return config; } } \ No newline at end of file diff --git a/src/main/java/dev/hytalemodding/RitualSpawner.java b/src/main/java/dev/hytalemodding/RitualSpawner.java index 380d117..77a311b 100644 --- a/src/main/java/dev/hytalemodding/RitualSpawner.java +++ b/src/main/java/dev/hytalemodding/RitualSpawner.java @@ -1,23 +1,89 @@ package dev.hytalemodding; -import com.hypixel.hytale.math.vector.Rotation3f; +import com.hypixel.hytale.protocol.SoundCategory; +import com.hypixel.hytale.server.core.asset.type.soundevent.config.SoundEvent; +import com.hypixel.hytale.server.core.universe.world.SoundUtil; import com.hypixel.hytale.server.core.universe.world.World; -import com.hypixel.hytale.server.npc.NPCPlugin; +import dev.hytalemodding.definitions.RitualDefinitions; +import dev.hytalemodding.definitions.RitualPattern; +import dev.hytalemodding.definitions.RitualTypes; import org.joml.Vector3d; import org.joml.Vector3i; +import java.util.List; import java.util.Objects; public class RitualSpawner { + RitualDefinitions ritualDefinitions = new RitualDefinitions(); + public void blockChangeEvent(String itemId, Vector3i targetPosition, World world) { String blockId = Objects.requireNonNull(world.getBlockType(targetPosition)).getId(); RitualPlugin.LOGGER.atInfo().log( "a block got placed or removed at the position: %d - %d - %d with the block id: %s and with the item id in hand: %s", targetPosition.x, targetPosition.y, targetPosition.z, blockId, itemId); - if (itemId.compareTo("Soil_Snow") == 0 && blockId.compareTo("Empty") == 0) { + /* if (itemId.compareTo("Soil_Snow") == 0 && blockId.compareTo("Empty") == 0) { RitualPlugin.LOGGER.atInfo().log("Ritual complete"); world.execute(() -> { - NPCPlugin.get().spawnNPC(world.getEntityStore().getStore(), "Yeti", null, new Vector3d(targetPosition), new Rotation3f(0, 0, 0)); + NPCPlugin.get().spawnNPC(world.getEntityStore().getStore(), "Yeti", null, blockPosToEntityPos(targetPosition), new Rotation3f(0, 0, 0)); + }); + } */ + RitualTypes ritualType = checkSetups(ritualDefinitions.containsCenterBlock(itemId), targetPosition, world); + if(!ritualType.equals(RitualTypes.NONE)) { + RitualPlugin.LOGGER.atInfo().log( + "a ritual pattern got completed" + ); + int soundIndex = SoundEvent.getAssetMap().getIndex("SFX_Skeleton_Praetorian_Alerted"); + world.execute(() -> { + // Play sound + SoundUtil.playSoundEvent3d(soundIndex, SoundCategory.SFX, blockToEntityPos(targetPosition), world.getEntityStore().getStore()); }); } } + + public void sacrificeDropEvent(String itemId, Vector3d targetPosition, World world) { + Vector3i blockPosition = entityToBlockPos(targetPosition); + RitualPlugin.LOGGER.atInfo().log( + "an item got thrown at the position: %f - %f - %f with the item id: %s", + blockPosition.x, blockPosition.y, blockPosition.z, itemId); + } + + RitualTypes checkSetups(List ritualSetups, Vector3i centerPosition, World world) { + for (Integer ritualSetup : ritualSetups) { + List ritualPatterns = ritualDefinitions.getPatterns(ritualSetup); + boolean isSetupValid = true; + for (RitualPattern ritualPattern : ritualPatterns) { + if(!checkPattern(ritualPattern, centerPosition, world)) { + isSetupValid = false; + } + } + if (isSetupValid) { + return ritualDefinitions.getRitualType(ritualSetup); + } + } + return RitualTypes.NONE; + } + + boolean checkPattern(RitualPattern ritualPattern, Vector3i centerPosition, World world) { + int countMatches = 0; + int radius = ritualPattern.radius(); + for (int ix = centerPosition.x - radius; ix <= centerPosition.x + radius; ix++) { + for (int iy = centerPosition.y - radius; iy <= centerPosition.y + radius; iy++) { + for (int iz = centerPosition.z - radius; iz <= centerPosition.z + radius; iz++) { + Vector3i samplePosition = new Vector3i(ix, iy, iz); + String blockId = Objects.requireNonNull(world.getBlockType(samplePosition)).getId(); + if (blockId.equals(ritualPattern.blockId())) { + countMatches++; + } + } + } + } + return countMatches >= ritualPattern.amount(); + } + + Vector3d blockToEntityPos(Vector3i blockPosition) { + return new Vector3d(blockPosition).add(new Vector3d(0.5, 1, 0.5)); + } + + Vector3i entityToBlockPos(Vector3d entityPosition) { + return new Vector3i(entityPosition, 0); + } } diff --git a/src/main/java/dev/hytalemodding/config/RitualConfig.java b/src/main/java/dev/hytalemodding/config/RitualConfig.java new file mode 100644 index 0000000..67d9578 --- /dev/null +++ b/src/main/java/dev/hytalemodding/config/RitualConfig.java @@ -0,0 +1,23 @@ +package dev.hytalemodding.config; + +import com.hypixel.hytale.codec.Codec; +import com.hypixel.hytale.codec.KeyedCodec; +import com.hypixel.hytale.codec.builder.BuilderCodec; + +public class RitualConfig { + public static final BuilderCodec CODEC = BuilderCodec.builder(RitualConfig.class, RitualConfig::new) + .append( + new KeyedCodec<>("EnableLogging", Codec.BOOLEAN), + (ritConfig, aBoolean, extraInfo) -> ritConfig.enableLogging = aBoolean, + (ritConfig, extraInfo) -> ritConfig.enableLogging) + .add() + .build(); + + private boolean enableLogging; + + private RitualConfig() {} + + public boolean isLoggingEnabled() { + return enableLogging; + } +} diff --git a/src/main/java/dev/hytalemodding/definitions/RitualDefinitions.java b/src/main/java/dev/hytalemodding/definitions/RitualDefinitions.java new file mode 100644 index 0000000..a61df98 --- /dev/null +++ b/src/main/java/dev/hytalemodding/definitions/RitualDefinitions.java @@ -0,0 +1,41 @@ +package dev.hytalemodding.definitions; + +import java.util.ArrayList; +import java.util.List; + +public class RitualDefinitions { + List ritualSetups = new ArrayList<>(); + + public RitualDefinitions() { + // Crude skeleton ritual + ritualSetups.add(new RitualSetup("Deco_Bone_Skulls", RitualTypes.SKELETON_ARMY) + .addPatern("Furniture_Crude_Torch", 2, 4, true) + .addSacrifice("Ingredient_Life_Essence")); + } + + public List containsCenterBlock(String blockId) { + List possibleSetups = new ArrayList<>(); + for(int i = 0; i < ritualSetups.size(); i++) { + if(ritualSetups.get(i).getCenterBlockId().equals(blockId)) { + possibleSetups.add(i); + } + } + return possibleSetups; + } + + public RitualTypes getRitualType(int index) { + return ritualSetups.get(index).getRitualType(); + } + + public String getCenterBlockId(int index) { + return ritualSetups.get(index).getCenterBlockId(); + } + + public List getPatterns(int setupIndex) { + return ritualSetups.get(setupIndex).getPatterns(); + } + + public String getSacrificeItemId(int setupIndex, int sacrificeIndex) { + return ritualSetups.get(setupIndex).getSacrificeItemId(sacrificeIndex); + } +} diff --git a/src/main/java/dev/hytalemodding/definitions/RitualPattern.java b/src/main/java/dev/hytalemodding/definitions/RitualPattern.java new file mode 100644 index 0000000..a5e68b2 --- /dev/null +++ b/src/main/java/dev/hytalemodding/definitions/RitualPattern.java @@ -0,0 +1,3 @@ +package dev.hytalemodding.definitions; + +public record RitualPattern(String blockId, int radius, int amount, boolean shouldConsume) { } diff --git a/src/main/java/dev/hytalemodding/definitions/RitualSetup.java b/src/main/java/dev/hytalemodding/definitions/RitualSetup.java new file mode 100644 index 0000000..470f69c --- /dev/null +++ b/src/main/java/dev/hytalemodding/definitions/RitualSetup.java @@ -0,0 +1,46 @@ +package dev.hytalemodding.definitions; + +import java.util.ArrayList; +import java.util.List; + +public class RitualSetup { + RitualTypes ritualType; + String centerBlockId; + List patterns = new ArrayList<>(); + List sacrificeItemIds = new ArrayList<>(); + + public RitualSetup(String centerBlockId, RitualTypes ritualType) { + this.ritualType = ritualType; + this.centerBlockId = centerBlockId; + } + + public RitualSetup addPatern(String blockId, int radius, int amount, boolean shouldConsume) { + patterns.add(new RitualPattern(blockId, radius, amount, shouldConsume)); + return this; + } + + public RitualSetup addSacrifice(String sacrifice) { + sacrificeItemIds.add(sacrifice); + return this; + } + + public RitualTypes getRitualType() { + return ritualType; + } + + public String getCenterBlockId() { + return centerBlockId; + } + + public RitualPattern getPattern(int index) { + return patterns.get(index); + } + + public List getPatterns() { + return patterns; + } + + public String getSacrificeItemId(int index) { + return sacrificeItemIds.get(index); + } +} diff --git a/src/main/java/dev/hytalemodding/definitions/RitualTypes.java b/src/main/java/dev/hytalemodding/definitions/RitualTypes.java new file mode 100644 index 0000000..d0e8973 --- /dev/null +++ b/src/main/java/dev/hytalemodding/definitions/RitualTypes.java @@ -0,0 +1,7 @@ +package dev.hytalemodding.definitions; + +public enum RitualTypes { + NONE, + SKELETON_ARMY, + YEDI +} diff --git a/src/main/java/dev/hytalemodding/events/RitualDropItemEvent.java b/src/main/java/dev/hytalemodding/events/RitualDropItemEvent.java new file mode 100644 index 0000000..fd854b8 --- /dev/null +++ b/src/main/java/dev/hytalemodding/events/RitualDropItemEvent.java @@ -0,0 +1,42 @@ +package dev.hytalemodding.events; + +import com.hypixel.hytale.component.*; +import com.hypixel.hytale.component.query.Query; +import com.hypixel.hytale.component.system.EntityEventSystem; +import com.hypixel.hytale.server.core.event.events.ecs.DropItemEvent; +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 dev.hytalemodding.RitualSpawner; +import org.checkerframework.checker.nullness.compatqual.NonNullDecl; +import org.checkerframework.checker.nullness.compatqual.NullableDecl; +import org.joml.Vector3d; + +public class RitualDropItemEvent extends EntityEventSystem { + private final RitualSpawner ritualSpawner; + public RitualDropItemEvent(RitualSpawner ritualSpawner) { + super(DropItemEvent.Drop.class); + this.ritualSpawner = ritualSpawner; + } + + @Override + public void handle(int index, + @NonNullDecl ArchetypeChunk archetypeChunk, + @NonNullDecl Store store, + @NonNullDecl CommandBuffer commandBuffer, + @NonNullDecl DropItemEvent.Drop dropItemEvent) { + String itemId = dropItemEvent.getItemStack().getItemId(); + Ref ref = archetypeChunk.getReferenceTo(index); + TransformComponent transform = store.getComponent(ref, TransformComponent.getComponentType()); + assert transform != null; + Vector3d targetPosition = transform.getPosition(); + World world = store.getExternalData().getWorld(); + ritualSpawner.sacrificeDropEvent(itemId, targetPosition, world); + } + + @NullableDecl + @Override + public Query getQuery() { + return Archetype.empty(); + } +}