From 2b4efec6c8e7fc42901b1725262a0a836e96ee55 Mon Sep 17 00:00:00 2001 From: James-P-Bennett Date: Thu, 30 Jan 2025 22:43:06 -0600 Subject: [PATCH 1/5] Implemented Toggle Mob AI Function Added a new feature to Electric Spawners that allows control over whether or not mobs have AI. - Added config options to force-disable AI globally or set default state - Added an in-game toggle button in the spawner GUI (unless force-disabled) - Mobs spawned will respect these AI settings --- .../electricspawners/ElectricSpawner.java | 53 ++++++++++++++----- .../electricspawners/ElectricSpawners.java | 22 ++++++-- src/main/resources/config.yml | 3 ++ 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java index 69f91ac..1f6df1b 100644 --- a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java +++ b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java @@ -5,6 +5,7 @@ import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; +import org.bukkit.entity.Mob; import org.bukkit.entity.Player; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; @@ -34,23 +35,26 @@ public class ElectricSpawner extends SimpleSlimefunItem implements private static int lifetime = 0; private final EntityType entity; + private final boolean forceDisableAI; + private final boolean defaultDisabledAI; - public ElectricSpawner(ItemGroup category, String mob, EntityType type, Research research) { - // @formatter:off + public ElectricSpawner(ItemGroup category, String mob, EntityType type, Research research, boolean forceDisableAI, boolean defaultDisabledAI) { super(category, new SlimefunItemStack("ELECTRIC_SPAWNER_" + mob, "db6bd9727abb55d5415265789d4f2984781a343c68dcaf57f554a5e9aa1cd", "&ePowered Spawner &7(" + ChatUtils.humanize(mob) + ")", "", "&8\u21E8 &e\u26A1 &7Max Entity Cap: 6", "&8\u21E8 &e\u26A1 &7512 J Buffer", - "&8\u21E8 &e\u26A1 &7240 J/Mob" + "&8\u21E8 &e\u26A1 &7240 J/Mob", + forceDisableAI ? "&8\u21E8 &c&lAI Forcefully Disabled" : "" ), RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] { - null, SlimefunItems.PLUTONIUM, null, + null, SlimefunItems.PLUTONIUM, null, SlimefunItems.ELECTRIC_MOTOR, new CustomItemStack(Material.SPAWNER, "&bReinforced Spawner", "&7Type: &b" + ChatUtils.humanize(type.toString())), SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.LARGE_CAPACITOR, SlimefunItems.BLISTERING_INGOT_3 }); - // @formatter:on this.entity = type; + this.forceDisableAI = forceDisableAI; + this.defaultDisabledAI = defaultDisabledAI; addItemHandler(onBlockPlace()); @@ -59,7 +63,7 @@ SlimefunItems.ELECTRIC_MOTOR, new CustomItemStack(Material.SPAWNER, "&bReinforce @Override public void init() { for (int i = 0; i < 9; i++) { - if (i != 4) { + if (i != 4 && (!forceDisableAI && i != 7)) { addItem(i, new CustomItemStack(Material.LIGHT_GRAY_STAINED_GLASS_PANE, " "), (p, slot, item, action) -> false); } } @@ -82,6 +86,25 @@ public void newInstance(BlockMenu menu, Block b) { return false; }); } + + if (!forceDisableAI) { + boolean disableAI = BlockStorage.getLocationInfo(b.getLocation(), "disable_ai") == null ? + defaultDisabledAI : + BlockStorage.getLocationInfo(b.getLocation(), "disable_ai").equals("true"); + + menu.replaceExistingItem(7, new CustomItemStack( + disableAI ? Material.ZOMBIE_HEAD : Material.PLAYER_HEAD, + "&7Mob AI: " + (disableAI ? "&4Disabled" : "&2Enabled"), + "", + "&e> Click to toggle Mob AI" + )); + + menu.addMenuClickHandler(7, (p, slot, item, action) -> { + BlockStorage.addBlockInfo(b, "disable_ai", String.valueOf(!disableAI)); + newInstance(menu, b); + return false; + }); + } } @Override @@ -100,13 +123,13 @@ public int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow) { private BlockPlaceHandler onBlockPlace() { return new BlockPlaceHandler(false) { - @Override public void onPlayerPlace(BlockPlaceEvent e) { Block b = e.getBlock(); Player p = e.getPlayer(); BlockStorage.addBlockInfo(b, "enabled", "false"); BlockStorage.addBlockInfo(b, "owner", p.getUniqueId().toString()); + BlockStorage.addBlockInfo(b, "disable_ai", String.valueOf(forceDisableAI || defaultDisabledAI)); } }; } @@ -132,7 +155,6 @@ protected void tick(Block b) { for (Entity n : b.getWorld().getNearbyEntities(b.getLocation(), 4.0, 4.0, 4.0)) { if (n.getType().equals(this.entity)) { count++; - if (count > 6) { return; } @@ -140,13 +162,20 @@ protected void tick(Block b) { } removeCharge(b.getLocation(), getEnergyConsumption()); - b.getWorld().spawnEntity(new Location(b.getWorld(), b.getX() + 0.5D, b.getY() + 1.5D, b.getZ() + 0.5D), this.entity); + Location spawnLoc = new Location(b.getWorld(), b.getX() + 0.5D, b.getY() + 1.5D, b.getZ() + 0.5D); + Entity spawned = b.getWorld().spawnEntity(spawnLoc, this.entity); + + if (spawned instanceof Mob) { + Mob mob = (Mob) spawned; + boolean disableAI = forceDisableAI || + BlockStorage.getLocationInfo(b.getLocation(), "disable_ai").equals("true"); + mob.setAware(!disableAI); + } } @Override public BlockTicker getItemHandler() { return new BlockTicker() { - @Override public void tick(Block b, SlimefunItem sf, Config data) { ElectricSpawner.this.tick(b); @@ -161,7 +190,6 @@ public void uniqueTick() { public boolean isSynchronized() { return true; } - }; } @@ -174,5 +202,4 @@ public int getCapacity() { public EnergyNetComponentType getEnergyComponentType() { return EnergyNetComponentType.CONSUMER; } - -} +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java index e9a379a..385234c 100644 --- a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java +++ b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java @@ -30,21 +30,35 @@ public void onEnable() { new GitHubBuildsUpdater(this, getFile(), "TheBusyBiscuit/ElectricSpawners/master").start(); } - ItemGroup itemGroup = new ItemGroup(new NamespacedKey(this, "electric_spawners"), new CustomItemStack(PlayerHead.getItemStack(PlayerSkin.fromHashCode("db6bd9727abb55d5415265789d4f2984781a343c68dcaf57f554a5e9aa1cd")), "&9Electric Spawners")); + boolean forceDisableAI = false; + boolean defaultDisabledAI = false; + + if (cfg.contains("options.mob-ai.force-disable")) { + forceDisableAI = cfg.getBoolean("options.mob-ai.force-disable"); + } + if (cfg.contains("options.mob-ai.default-disabled")) { + defaultDisabledAI = cfg.getBoolean("options.mob-ai.default-disabled"); + } + + ItemGroup itemGroup = new ItemGroup(new NamespacedKey(this, "electric_spawners"), + new CustomItemStack(PlayerHead.getItemStack(PlayerSkin.fromHashCode("db6bd9727abb55d5415265789d4f2984781a343c68dcaf57f554a5e9aa1cd")), + "&9Electric Spawners")); Research research = new Research(new NamespacedKey(this, "electric_spawners"), 4820, "Powered Spawners", 30); for (String mob : cfg.getStringList("mobs")) { try { EntityType type = EntityType.valueOf(mob); - new ElectricSpawner(itemGroup, mob, type, research).register(this); + new ElectricSpawner(itemGroup, mob, type, research, forceDisableAI, defaultDisabledAI).register(this); } catch (IllegalArgumentException x) { - getLogger().log(Level.WARNING, "An Error has occured while adding an Electric Spawner for the (posibly outdated or invalid) EntityType \"{0}\"", mob); + getLogger().log(Level.WARNING, "An Error has occurred while adding an Electric Spawner for the (possibly outdated or invalid) EntityType \"{0}\"", mob); } catch (Exception x) { - getLogger().log(Level.SEVERE, x, () -> "An Error has occured while adding an Electric Spawner for the EntityType \"" + mob + "\""); + getLogger().log(Level.SEVERE, x, () -> "An Error has occurred while adding an Electric Spawner for the EntityType \"" + mob + "\""); } } research.register(); + + saveDefaultConfig(); } @Override diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 0a32596..48ec96d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,8 @@ options: auto-update: true +mob-ai: + force-disable: false # If true, all spawned mobs will have AI disabled and players cannot toggle + default-disabled: false # Default state for new spawners if force-disable is false mobs: - BLAZE - CAVE_SPIDER From 3b65b5bebd0ed373832f5232ad3438f31863224c Mon Sep 17 00:00:00 2001 From: James-P-Bennett Date: Fri, 31 Jan 2025 22:57:43 -0600 Subject: [PATCH 2/5] Fixed config path for mob AI setting --- .../thebusybiscuit/electricspawners/ElectricSpawners.java | 8 ++++---- src/main/resources/config.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java index 385234c..3fc6d5b 100644 --- a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java +++ b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java @@ -33,11 +33,11 @@ public void onEnable() { boolean forceDisableAI = false; boolean defaultDisabledAI = false; - if (cfg.contains("options.mob-ai.force-disable")) { - forceDisableAI = cfg.getBoolean("options.mob-ai.force-disable"); + if (cfg.contains("mob-ai.force-disable")) { + forceDisableAI = cfg.getBoolean("mob-ai.force-disable"); } - if (cfg.contains("options.mob-ai.default-disabled")) { - defaultDisabledAI = cfg.getBoolean("options.mob-ai.default-disabled"); + if (cfg.contains("mob-ai.default-disabled")) { + defaultDisabledAI = cfg.getBoolean("mob-ai.default-disabled"); } ItemGroup itemGroup = new ItemGroup(new NamespacedKey(this, "electric_spawners"), diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 48ec96d..27bc1dd 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,7 +1,7 @@ options: auto-update: true mob-ai: - force-disable: false # If true, all spawned mobs will have AI disabled and players cannot toggle + force-disable: false # If true, all spawned mobs will have AI disabled and players cannot toggle default-disabled: false # Default state for new spawners if force-disable is false mobs: - BLAZE From be9969638140119de90c68f72e488254a91acf35 Mon Sep 17 00:00:00 2001 From: James-P-Bennett Date: Fri, 31 Jan 2025 22:57:43 -0600 Subject: [PATCH 3/5] Fixed config path for mob AI setting --- .../thebusybiscuit/electricspawners/ElectricSpawners.java | 8 ++++---- src/main/resources/config.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java index 385234c..3fc6d5b 100644 --- a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java +++ b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java @@ -33,11 +33,11 @@ public void onEnable() { boolean forceDisableAI = false; boolean defaultDisabledAI = false; - if (cfg.contains("options.mob-ai.force-disable")) { - forceDisableAI = cfg.getBoolean("options.mob-ai.force-disable"); + if (cfg.contains("mob-ai.force-disable")) { + forceDisableAI = cfg.getBoolean("mob-ai.force-disable"); } - if (cfg.contains("options.mob-ai.default-disabled")) { - defaultDisabledAI = cfg.getBoolean("options.mob-ai.default-disabled"); + if (cfg.contains("mob-ai.default-disabled")) { + defaultDisabledAI = cfg.getBoolean("mob-ai.default-disabled"); } ItemGroup itemGroup = new ItemGroup(new NamespacedKey(this, "electric_spawners"), diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 48ec96d..27bc1dd 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,7 +1,7 @@ options: auto-update: true mob-ai: - force-disable: false # If true, all spawned mobs will have AI disabled and players cannot toggle + force-disable: false # If true, all spawned mobs will have AI disabled and players cannot toggle default-disabled: false # Default state for new spawners if force-disable is false mobs: - BLAZE From 20f4cf91f7b0f006e9078e3aa7020ac41e541121 Mon Sep 17 00:00:00 2001 From: James-P-Bennett Date: Tue, 4 Feb 2025 19:51:09 -0600 Subject: [PATCH 4/5] Timing Fix Replaced the shared lifetime counter with per-spawner timing using world ticks, fixing synchronization issues. Added a 20-tick spawn cooldown to ensure consistent and reliable spawning, preventing Electric Spawners from randomly failing. --- .../electricspawners/ElectricSpawner.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java index 1f6df1b..1bfe125 100644 --- a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java +++ b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java @@ -32,7 +32,6 @@ public class ElectricSpawner extends SimpleSlimefunItem implements EnergyNetComponent { private static final int ENERGY_CONSUMPTION = 240; - private static int lifetime = 0; private final EntityType entity; private final boolean forceDisableAI; @@ -138,8 +137,13 @@ public int getEnergyConsumption() { return ENERGY_CONSUMPTION; } + private static final long SPAWN_COOLDOWN_TICKS = 20L; // 1 second (20 ticks) This too fast? + private long lastSpawnTick = 0L; + protected void tick(Block b) { - if (lifetime % 3 != 0) { + long currentTick = b.getWorld().getFullTime(); + + if (currentTick - lastSpawnTick < SPAWN_COOLDOWN_TICKS) { return; } @@ -171,6 +175,7 @@ protected void tick(Block b) { BlockStorage.getLocationInfo(b.getLocation(), "disable_ai").equals("true"); mob.setAware(!disableAI); } + lastSpawnTick = currentTick; } @Override @@ -183,7 +188,6 @@ public void tick(Block b, SlimefunItem sf, Config data) { @Override public void uniqueTick() { - lifetime++; } @Override From 48a906a809d31d8a33b3ba3dae1b761495960ecb Mon Sep 17 00:00:00 2001 From: James-P-Bennett Date: Thu, 3 Apr 2025 20:53:01 -0500 Subject: [PATCH 5/5] 1.21 Updated to support 1.21 Experimental Slimefun Tested and confirmed working on all versions up to 1.21.4, officially supports 1.21.2 --- .../electricspawners/ElectricSpawner.java | 14 +++++++------- .../electricspawners/ElectricSpawners.java | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java index 1bfe125..84ae1d3 100644 --- a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java +++ b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawner.java @@ -46,9 +46,9 @@ public ElectricSpawner(ItemGroup category, String mob, EntityType type, Research "&8\u21E8 &e\u26A1 &7240 J/Mob", forceDisableAI ? "&8\u21E8 &c&lAI Forcefully Disabled" : "" ), RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] { - null, SlimefunItems.PLUTONIUM, null, - SlimefunItems.ELECTRIC_MOTOR, new CustomItemStack(Material.SPAWNER, "&bReinforced Spawner", "&7Type: &b" + ChatUtils.humanize(type.toString())), SlimefunItems.ELECTRIC_MOTOR, - SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.LARGE_CAPACITOR, SlimefunItems.BLISTERING_INGOT_3 + null, SlimefunItems.PLUTONIUM.item(), null, + SlimefunItems.ELECTRIC_MOTOR.item(), CustomItemStack.create(Material.SPAWNER, "&bReinforced Spawner", "&7Type: &b" + ChatUtils.humanize(type.toString())), SlimefunItems.ELECTRIC_MOTOR.item(), + SlimefunItems.BLISTERING_INGOT_3.item(), SlimefunItems.LARGE_CAPACITOR.item(), SlimefunItems.BLISTERING_INGOT_3.item() }); this.entity = type; @@ -63,7 +63,7 @@ SlimefunItems.ELECTRIC_MOTOR, new CustomItemStack(Material.SPAWNER, "&bReinforce public void init() { for (int i = 0; i < 9; i++) { if (i != 4 && (!forceDisableAI && i != 7)) { - addItem(i, new CustomItemStack(Material.LIGHT_GRAY_STAINED_GLASS_PANE, " "), (p, slot, item, action) -> false); + addItem(i, CustomItemStack.create(Material.LIGHT_GRAY_STAINED_GLASS_PANE, " "), (p, slot, item, action) -> false); } } } @@ -71,14 +71,14 @@ public void init() { @Override public void newInstance(BlockMenu menu, Block b) { if (!BlockStorage.hasBlockInfo(b) || BlockStorage.getLocationInfo(b.getLocation(), "enabled") == null || BlockStorage.getLocationInfo(b.getLocation(), "enabled").equals("false")) { - menu.replaceExistingItem(4, new CustomItemStack(Material.GUNPOWDER, "&7Enabled: &4\u2718", "", "&e> Click to enable this Machine")); + menu.replaceExistingItem(4, CustomItemStack.create(Material.GUNPOWDER, "&7Enabled: &4\u2718", "", "&e> Click to enable this Machine")); menu.addMenuClickHandler(4, (p, slot, item, action) -> { BlockStorage.addBlockInfo(b, "enabled", "true"); newInstance(menu, b); return false; }); } else { - menu.replaceExistingItem(4, new CustomItemStack(Material.REDSTONE, "&7Enabled: &2\u2714", "", "&e> Click to disable this Machine")); + menu.replaceExistingItem(4, CustomItemStack.create(Material.REDSTONE, "&7Enabled: &2\u2714", "", "&e> Click to disable this Machine")); menu.addMenuClickHandler(4, (p, slot, item, action) -> { BlockStorage.addBlockInfo(b, "enabled", "false"); newInstance(menu, b); @@ -91,7 +91,7 @@ public void newInstance(BlockMenu menu, Block b) { defaultDisabledAI : BlockStorage.getLocationInfo(b.getLocation(), "disable_ai").equals("true"); - menu.replaceExistingItem(7, new CustomItemStack( + menu.replaceExistingItem(7, CustomItemStack.create( disableAI ? Material.ZOMBIE_HEAD : Material.PLAYER_HEAD, "&7Mob AI: " + (disableAI ? "&4Disabled" : "&2Enabled"), "", diff --git a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java index 3fc6d5b..59b8243 100644 --- a/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java +++ b/src/main/java/io/github/thebusybiscuit/electricspawners/ElectricSpawners.java @@ -41,7 +41,7 @@ public void onEnable() { } ItemGroup itemGroup = new ItemGroup(new NamespacedKey(this, "electric_spawners"), - new CustomItemStack(PlayerHead.getItemStack(PlayerSkin.fromHashCode("db6bd9727abb55d5415265789d4f2984781a343c68dcaf57f554a5e9aa1cd")), + CustomItemStack.create(PlayerHead.getItemStack(PlayerSkin.fromHashCode("db6bd9727abb55d5415265789d4f2984781a343c68dcaf57f554a5e9aa1cd")), "&9Electric Spawners")); Research research = new Research(new NamespacedKey(this, "electric_spawners"), 4820, "Powered Spawners", 30);