diff --git a/gradle.properties b/gradle.properties index b38c40a..770fb15 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ group = dev.hytalemodding manifest_group = HytaleModding # Human-readable mod name. -mod_name = Replace Me +mod_name = Ritual Mod # Fully-qualified plugin entry point class. main_class = dev.hytalemodding.RitualPlugin diff --git a/src/main/java/dev/hytalemodding/RitualSpawner.java b/src/main/java/dev/hytalemodding/RitualSpawner.java index 77a311b..23be401 100644 --- a/src/main/java/dev/hytalemodding/RitualSpawner.java +++ b/src/main/java/dev/hytalemodding/RitualSpawner.java @@ -1,37 +1,47 @@ package dev.hytalemodding; +import com.hypixel.hytale.math.vector.Rotation3f; import com.hypixel.hytale.protocol.SoundCategory; +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.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.ArrayList; 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(); + public void blockChangeEvent(String blockId, Vector3i targetPosition, World world, boolean gotPlaced) { + String placedRemovedString; + if (gotPlaced) { + placedRemovedString = "placed"; + } else { + placedRemovedString = "removed"; + } 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) { - RitualPlugin.LOGGER.atInfo().log("Ritual complete"); - world.execute(() -> { - NPCPlugin.get().spawnNPC(world.getEntityStore().getStore(), "Yeti", null, blockPosToEntityPos(targetPosition), new Rotation3f(0, 0, 0)); - }); - } */ - RitualTypes ritualType = checkSetups(ritualDefinitions.containsCenterBlock(itemId), targetPosition, world); + "a block got %s at the position: %d, %d, %d with the block id: %s", + placedRemovedString, targetPosition.x, targetPosition.y, targetPosition.z, blockId); + // RitualTypes ritualType = checkPatterns(ritualDefinitions.containsCenterBlock(blockId), targetPosition, world); + RitualTypes ritualType = getRitualTypeFromBlock(blockId, 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"); + String soundId; + if (gotPlaced) { + soundId = "SFX_Skeleton_Praetorian_Alerted"; + } else { + soundId = "SFX_Torch_Off"; + } + int soundIndex = SoundEvent.getAssetMap().getIndex(soundId); world.execute(() -> { // Play sound SoundUtil.playSoundEvent3d(soundIndex, SoundCategory.SFX, blockToEntityPos(targetPosition), world.getEntityStore().getStore()); @@ -42,34 +52,121 @@ public class RitualSpawner { 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", + "an item got thrown at the position: %f, %f, %f with the item id: %s", blockPosition.x, blockPosition.y, blockPosition.z, itemId); + RitualTypes ritualType = getRitualTypeFromSacrifice(blockPosition, world); + if (!ritualType.equals(RitualTypes.NONE)) { + if (ritualType.equals(RitualTypes.SKELETON)) { + RitualPlugin.LOGGER.atInfo().log("Ritual complete"); + world.execute(() -> { + NPCPlugin.get().spawnNPC(world.getEntityStore().getStore(), "Skeleton", null, targetPosition, new Rotation3f(0, 0, 0)); + }); + } + } } - 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; + RitualTypes getRitualTypeFromSacrifice(Vector3i centerPosition, World world) { + int radius = 1; + 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 = getBlockId(samplePosition, world); + List possibleSetups = getFullRitualSetupRange(); + possibleSetups = checkCenterBlock(possibleSetups, blockId); + if (!possibleSetups.isEmpty()) { + possibleSetups = checkPatterns(possibleSetups, samplePosition, world, samplePosition, "Empty"); + if (!possibleSetups.isEmpty()) { + return ritualDefinitions.getRitualType(possibleSetups.getFirst()); + } + } } } - if (isSetupValid) { - return ritualDefinitions.getRitualType(ritualSetup); - } } return RitualTypes.NONE; } - boolean checkPattern(RitualPattern ritualPattern, Vector3i centerPosition, World world) { + RitualTypes getRitualTypeFromBlock(String blockId, Vector3i blockPosition, World world) { + List fullSetupRange = getFullRitualSetupRange(); + List possibleSetups = checkCenterBlock(new ArrayList<>(fullSetupRange), blockId); + if (!possibleSetups.isEmpty()) { + possibleSetups = checkPatterns(possibleSetups, blockPosition, world, blockPosition, "Empty"); + if (!possibleSetups.isEmpty()) { + return ritualDefinitions.getRitualType(possibleSetups.getFirst()); + } + } + possibleSetups = checkPatternPalette(new ArrayList<>(fullSetupRange), blockId); + if (possibleSetups.size() <= 0) { + return RitualTypes.NONE; + } + int radius = getMaxRadius(possibleSetups); + for (int ix = blockPosition.x - radius; ix <= blockPosition.x + radius; ix++) { + for (int iy = blockPosition.y - radius; iy <= blockPosition.y + radius; iy++) { + for (int iz = blockPosition.z - radius; iz <= blockPosition.z + radius; iz++) { + Vector3i samplePosition = new Vector3i(ix, iy, iz); + List setupsAtPosition = checkCenterBlock(new ArrayList<>(possibleSetups), getBlockId(samplePosition, world)); + if (!setupsAtPosition.isEmpty()) { + setupsAtPosition = checkPatterns(setupsAtPosition, samplePosition, world, blockPosition, blockId); + if (!setupsAtPosition.isEmpty()) { + return ritualDefinitions.getRitualType(setupsAtPosition.getFirst()); + } + } + } + } + } + return RitualTypes.NONE; + } + + List checkCenterBlock(List ritualSetups, String blockId) { + ritualSetups.removeIf(ritualSetup -> !ritualDefinitions.getCenterBlockId(ritualSetup).equals(blockId)); + return ritualSetups; + } + + List checkPatternPalette(List ritualSetups, String blockId) { + List possibleSetups = new ArrayList<>(ritualSetups); + for (Integer ritualSetup : ritualSetups) { + boolean isPossibleSetup = false; + List ritualPatterns = ritualDefinitions.getPatterns(ritualSetup); + for (RitualPattern ritualPattern : ritualPatterns) { + if (ritualPattern.blockId().equals(blockId)){ + isPossibleSetup = true; + break; + } + } + if (!isPossibleSetup) { + possibleSetups.remove(ritualSetup); + } + } + return possibleSetups; + } + + List checkPatterns(List ritualSetups, Vector3i centerPosition, World world, Vector3i placedBlockPosition, String placedBlockId) { + List possibleSetups = new ArrayList<>(ritualSetups); + for (Integer ritualSetup : ritualSetups) { + List ritualPatterns = ritualDefinitions.getPatterns(ritualSetup); + //RitualPlugin.LOGGER.atInfo().log("ritualPatterns size in checkPatterns() is %d", ritualPatterns.size()); + for (RitualPattern ritualPattern : ritualPatterns) { + if(!checkPattern(ritualPattern, centerPosition, world, placedBlockPosition, placedBlockId)) { + possibleSetups.remove(ritualSetup); + } + } + } + return possibleSetups; + } + + boolean checkPattern(RitualPattern ritualPattern, Vector3i centerPosition, World world, Vector3i placedBlockPosition, String placedBlockId) { 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(); + String blockId; + if (samplePosition.equals(placedBlockPosition)) { + blockId = placedBlockId; + } else { + blockId = getBlockId(samplePosition, world); + } if (blockId.equals(ritualPattern.blockId())) { countMatches++; } @@ -79,6 +176,36 @@ public class RitualSpawner { return countMatches >= ritualPattern.amount(); } + int getMaxRadius(List ritualSetups) { + int maxRadius = 0; + for (Integer ritualSetup : ritualSetups) { + List ritualPatterns = ritualDefinitions.getPatterns(ritualSetup); + for (RitualPattern ritualPattern : ritualPatterns) { + if (maxRadius < ritualPattern.radius()) { + maxRadius = ritualPattern.radius(); + } + } + } + return maxRadius; + } + + List getFullRitualSetupRange() { + List possibleSetups = new ArrayList<>(); + for (int i = 0; i < ritualDefinitions.getRitualSetupsCount(); i++) { + possibleSetups.add(i); + } + return possibleSetups; + } + + String getBlockId(Vector3i samplePosition, World world) { + BlockType blockType = world.getBlockType(samplePosition); + String blockId = "Empty"; + if (blockType != null) { + blockId = blockType.getId(); + } + return blockId; + } + Vector3d blockToEntityPos(Vector3i blockPosition) { return new Vector3d(blockPosition).add(new Vector3d(0.5, 1, 0.5)); } diff --git a/src/main/java/dev/hytalemodding/definitions/RitualDefinitions.java b/src/main/java/dev/hytalemodding/definitions/RitualDefinitions.java index a61df98..16daa8d 100644 --- a/src/main/java/dev/hytalemodding/definitions/RitualDefinitions.java +++ b/src/main/java/dev/hytalemodding/definitions/RitualDefinitions.java @@ -8,19 +8,13 @@ public class RitualDefinitions { 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")); + ritualSetups.add(new RitualSetup("Deco_Bone_Skulls", RitualTypes.SKELETON) + .addPatern("Furniture_Crude_Torch", 2, 4, false, true) + .addSacrifice("Ingredient_Life_Essence", 1, 1, true)); } - 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 int getRitualSetupsCount() { + return ritualSetups.size(); } public RitualTypes getRitualType(int index) { @@ -35,7 +29,7 @@ public class RitualDefinitions { return ritualSetups.get(setupIndex).getPatterns(); } - public String getSacrificeItemId(int setupIndex, int sacrificeIndex) { + public RitualSacrifice 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 index a5e68b2..394320f 100644 --- a/src/main/java/dev/hytalemodding/definitions/RitualPattern.java +++ b/src/main/java/dev/hytalemodding/definitions/RitualPattern.java @@ -1,3 +1,3 @@ package dev.hytalemodding.definitions; -public record RitualPattern(String blockId, int radius, int amount, boolean shouldConsume) { } +public record RitualPattern(String blockId, int radius, int amount, boolean shouldConsume, boolean shouldInteract) { } diff --git a/src/main/java/dev/hytalemodding/definitions/RitualSacrifice.java b/src/main/java/dev/hytalemodding/definitions/RitualSacrifice.java new file mode 100644 index 0000000..2895e6e --- /dev/null +++ b/src/main/java/dev/hytalemodding/definitions/RitualSacrifice.java @@ -0,0 +1,3 @@ +package dev.hytalemodding.definitions; + +public record RitualSacrifice(String itemId, 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 index 470f69c..aed2dde 100644 --- a/src/main/java/dev/hytalemodding/definitions/RitualSetup.java +++ b/src/main/java/dev/hytalemodding/definitions/RitualSetup.java @@ -7,20 +7,20 @@ public class RitualSetup { RitualTypes ritualType; String centerBlockId; List patterns = new ArrayList<>(); - List sacrificeItemIds = new ArrayList<>(); + List sacrifices = 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)); + public RitualSetup addPatern(String blockId, int radius, int amount, boolean shouldConsume, boolean shouldInteract) { + patterns.add(new RitualPattern(blockId, radius, amount, shouldConsume, shouldInteract)); return this; } - public RitualSetup addSacrifice(String sacrifice) { - sacrificeItemIds.add(sacrifice); + public RitualSetup addSacrifice(String itemId, int radius, int amount, boolean shouldConsume) { + sacrifices.add(new RitualSacrifice(itemId, radius, amount, shouldConsume)); return this; } @@ -40,7 +40,7 @@ public class RitualSetup { return patterns; } - public String getSacrificeItemId(int index) { - return sacrificeItemIds.get(index); + public RitualSacrifice getSacrificeItemId(int index) { + return sacrifices.get(index); } } diff --git a/src/main/java/dev/hytalemodding/definitions/RitualTypes.java b/src/main/java/dev/hytalemodding/definitions/RitualTypes.java index d0e8973..72e3e48 100644 --- a/src/main/java/dev/hytalemodding/definitions/RitualTypes.java +++ b/src/main/java/dev/hytalemodding/definitions/RitualTypes.java @@ -2,6 +2,6 @@ package dev.hytalemodding.definitions; public enum RitualTypes { NONE, - SKELETON_ARMY, + SKELETON, YEDI } diff --git a/src/main/java/dev/hytalemodding/events/RitualBreakBlockEvent.java b/src/main/java/dev/hytalemodding/events/RitualBreakBlockEvent.java index 62d2c5b..180fefd 100644 --- a/src/main/java/dev/hytalemodding/events/RitualBreakBlockEvent.java +++ b/src/main/java/dev/hytalemodding/events/RitualBreakBlockEvent.java @@ -6,8 +6,8 @@ import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.component.query.Query; import com.hypixel.hytale.component.system.EntityEventSystem; +import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType; import com.hypixel.hytale.server.core.event.events.ecs.BreakBlockEvent; -import com.hypixel.hytale.server.core.inventory.ItemStack; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import dev.hytalemodding.RitualSpawner; @@ -28,14 +28,14 @@ public class RitualBreakBlockEvent extends EntityEventSystem store, @NonNullDecl CommandBuffer commandBuffer, @NonNullDecl BreakBlockEvent breakBlockEvent) { - ItemStack itemHolding = breakBlockEvent.getItemInHand(); - String itemId = "Empty"; - if(itemHolding != null) { - itemId = itemHolding.getItemId(); - } - Vector3i blockPosition = breakBlockEvent.getTargetBlock(); World world = store.getExternalData().getWorld(); - ritualSpawner.blockChangeEvent(itemId, blockPosition, world); + Vector3i blockPosition = breakBlockEvent.getTargetBlock(); + BlockType blockType = world.getBlockType(blockPosition); + String blockId = "Empty"; + if(blockType != null) { + blockId = blockType.getId(); + } + ritualSpawner.blockChangeEvent(blockId, blockPosition, world, false); } @NullableDecl diff --git a/src/main/java/dev/hytalemodding/events/RitualPlaceBlockEvent.java b/src/main/java/dev/hytalemodding/events/RitualPlaceBlockEvent.java index 4879019..c0b7ff0 100644 --- a/src/main/java/dev/hytalemodding/events/RitualPlaceBlockEvent.java +++ b/src/main/java/dev/hytalemodding/events/RitualPlaceBlockEvent.java @@ -28,14 +28,14 @@ public class RitualPlaceBlockEvent extends EntityEventSystem store, @NonNullDecl CommandBuffer commandBuffer, @NonNullDecl PlaceBlockEvent placeBlockEvent) { - ItemStack itemHolding = placeBlockEvent.getItemInHand(); - String itemId = "Empty"; - if(itemHolding != null) { - itemId = itemHolding.getItemId(); - } - Vector3i targetPosition = placeBlockEvent.getTargetBlock(); World world = store.getExternalData().getWorld(); - ritualSpawner.blockChangeEvent(itemId, targetPosition, world); + Vector3i targetPosition = placeBlockEvent.getTargetBlock(); + ItemStack itemHolding = placeBlockEvent.getItemInHand(); + String blockId = "Empty"; + if(itemHolding != null) { + blockId = itemHolding.getItemId(); + } + ritualSpawner.blockChangeEvent(blockId, targetPosition, world, true); } @NullableDecl