diff --git a/src/main/java/ladysnake/spawnercontrol/SpawnerEventHandler.java b/src/main/java/ladysnake/spawnercontrol/SpawnerEventHandler.java index 8c0285f..6a4778a 100644 --- a/src/main/java/ladysnake/spawnercontrol/SpawnerEventHandler.java +++ b/src/main/java/ladysnake/spawnercontrol/SpawnerEventHandler.java @@ -11,7 +11,10 @@ import net.minecraft.block.BlockMobSpawner; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.monster.IMob; +import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTBase; @@ -28,6 +31,7 @@ import net.minecraft.world.WorldServer; import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.entity.living.LivingDeathEvent; +import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.event.entity.living.LivingExperienceDropEvent; import net.minecraftforge.event.entity.living.LivingSpawnEvent; import net.minecraftforge.event.world.BlockEvent; @@ -37,6 +41,7 @@ import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.common.registry.ForgeRegistries; import net.minecraftforge.fml.relauncher.Side; import java.util.*; @@ -211,6 +216,57 @@ public static void onLivingExperienceDrop(LivingExperienceDropEvent event) { } } + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onLivingItemDrop(LivingDropsEvent event) { + EntityLivingBase livingBase = event.getEntityLiving(); + SpawnerConfig cfg = SpawnerUtil.getConfig(livingBase.getEntityData().getTag(NBT_TAG_SPAWNER_POS)); + if (cfg != null) { + try { + ResourceLocation rl = EntityList.getKey(event.getEntity()); + if (rl != null) { + SpawnerConfig.MobLoot.MobLootEntry entry = cfg.mobLoot.lootEntries.get(rl); + List drops = event.getDrops(); + if (entry.removeAllItems) { + drops.clear(); + } else { + for (EntityItem drop : drops.toArray(new EntityItem[0])) { + ItemStack stack = drop.getItem(); + for (String s : entry.removedItems) { + String[] split = s.split(":"); + if (stack.getUnlocalizedName().equals(split[0] + ":" + split[1]) + && (split.length < 3 || stack.getMetadata() == Integer.parseInt(split[2]))) { + drops.remove(drop); + } + } + } + } + World world = livingBase.world; + double x = livingBase.posX, y = livingBase.posY, z = livingBase.posZ; + for (String s : entry.addedItems) + { + String[] split = s.split(":"); + if (split.length < 5 || world.rand.nextDouble() < Double.parseDouble(split[4])) { + ResourceLocation itemRL = new ResourceLocation(split[0], split[1]); + Item item = ForgeRegistries.ITEMS.getValue(itemRL); + if (item == null) { + item = Item.getItemFromBlock(ForgeRegistries.BLOCKS.getValue(itemRL)); + } + if (item != Items.AIR) { + int quantity = split.length < 3 ? 1 : Integer.parseInt(split[2]); + int meta = split.length < 4 ? 0 : Integer.parseInt(split[3]); + drops.add(new EntityItem(world, x, y, z, new ItemStack(item, quantity, meta))); + } else { + SpawnerControl.LOGGER.error("Error while handling spawned item drops"); + } + } + } + } + } catch (NumberFormatException | ExecutionException e) { + SpawnerControl.LOGGER.error("Error while handling spawned item drops", e); + } + } + } + /** * Changes the amount of experience dropped by a spawner when broken. * Drops from the mod's spawner are also handled here @@ -256,7 +312,7 @@ else if (block instanceof BlockMobSpawner && MSCConfig.alterVanillaSpawner) int count = split.length >= 3 ? Integer.parseInt(split[2]) : 1; int meta = split.length >= 4 ? Integer.parseInt(split[3]) : 0; // default chance is 1 - if (split.length < 5 || event.getWorld().rand.nextFloat() < Double.parseDouble(split[4])) + if (split.length < 5 || event.getWorld().rand.nextDouble() < Double.parseDouble(split[4])) drops.add(new ItemStack(item, count, meta)); } } catch (NumberFormatException ignored) { diff --git a/src/main/java/ladysnake/spawnercontrol/config/SpawnerConfig.java b/src/main/java/ladysnake/spawnercontrol/config/SpawnerConfig.java index 7cb4d5f..ffe939e 100644 --- a/src/main/java/ladysnake/spawnercontrol/config/SpawnerConfig.java +++ b/src/main/java/ladysnake/spawnercontrol/config/SpawnerConfig.java @@ -7,6 +7,9 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.config.Config; +import java.util.Arrays; +import java.util.List; + public class SpawnerConfig { @Config.Comment("Regroups config options aiming to alter mob spawners spawning conditions") @@ -51,34 +54,75 @@ public static class SpawnConditions { public static class MobLoot { - public MobLootEntry defaultValues = new MobLootEntry(1, 0); + public MobLootEntry defaultValues = new MobLootEntry(1, 0, false, new String[0], new String[0]); @Config.Comment({"Individual xp drop multiplier configuration for mobs spawned by this spawner type", "Format: 'modid:entity:xpMultiplier(:flatXp)' (flatXp is optional)"}) public String[] xpMultipliers = new String[0]; + @Config.Comment({"Individual item drop removal configuration for mobs spawned by this spawner type", "Format: 'modid:entity(,modid:item(:meta))(,modid:item(:meta))...'", "Anything in parenthesis is optional, and you can enter as many items as you want", "If don't enter any items, all item drops are removed from the mob (itemDropAdditions are added afterwards)"}) + public String[] itemDropRemovals = new String[0]; + + @Config.Comment({"Individual item drop addition configuration for mobs spawned by this spawner type", "Format: 'modid:entity,modid:item(:count(:meta(:chance)))(,modid:item(:count(:meta(:chance))))...'", "Anything in parenthesis is optional, and you can enter as many items as you want", "Eg: minecraft:skeleton,minecraft:dye:100:15:0.5,minecraft:bone:1:1:1"}) + public String[] itemDropAdditions = new String[0]; + @Config.Ignore public LoadingCache lootEntries = CacheBuilder.newBuilder().build(CacheLoader.from(rl -> { if (rl == null) return defaultValues; + float xpMultiplier = defaultValues.xpMultiplier; + int flatXpIncrease = defaultValues.flatXpIncrease; + boolean removeAllItems = defaultValues.removeAllItems; + List removedItems = Arrays.asList(defaultValues.removedItems); + List addedItems = Arrays.asList(defaultValues.addedItems); for (String s : xpMultipliers) { String[] split = s.split(":"); if (split[0].equals(rl.getResourcePath()) && split[1].equals(rl.getResourceDomain())) { try { - float xpMultiplier = Float.parseFloat(split[2]); - int flatXpIncrease = split.length > 3 ? Integer.parseInt(split[3]) : defaultValues.flatXpIncrease; - return new MobLootEntry(xpMultiplier, flatXpIncrease); + xpMultiplier = Float.parseFloat(split[2]); + flatXpIncrease = split.length > 3 ? Integer.parseInt(split[3]) : defaultValues.flatXpIncrease; } catch (NumberFormatException e) { SpawnerControl.LOGGER.warn("Bad mob spawner loot config option : {}", s); } + break; + } + } + for (String s : itemDropRemovals) { + String[] split = s.split(","); + String[] mobSplit = split[0].split(":"); + if (mobSplit[0].equals(rl.getResourcePath()) && mobSplit[1].equals(rl.getResourceDomain())) { + try { + removedItems = Arrays.asList(split); + removedItems.remove(0); + removeAllItems = removedItems.size() == 0; + } catch (Exception e) { + SpawnerControl.LOGGER.warn("Bad mob spawner loot config option : {}", s); + } + break; + } + } + for (String s : itemDropAdditions) { + String[] split = s.split(":"); + if (split[0].equals(rl.getResourcePath()) && split[1].equals(rl.getResourceDomain())) { + try { + addedItems = Arrays.asList(split); + addedItems.remove(0); + } catch (Exception e) { + SpawnerControl.LOGGER.warn("Bad mob spawner loot config option : {}", s); + } + break; } } - return defaultValues; + return new MobLootEntry(xpMultiplier, flatXpIncrease, removeAllItems, removedItems.toArray(new String[0]), addedItems.toArray(new String[0])); })); public static class MobLootEntry { - public MobLootEntry(float defaultXpMultiplier, int flatXpIncrease) { + public MobLootEntry(float defaultXpMultiplier, int flatXpIncrease, boolean removeAllItems, String[] removedItems, String[] addedItems) { this.xpMultiplier = defaultXpMultiplier; this.flatXpIncrease = flatXpIncrease; + + this.removeAllItems = removeAllItems; + this.removedItems = removedItems; + this.addedItems = addedItems; } @Config.Comment("xp drop multiplier for mobs spawned by this spawner type") @@ -87,6 +131,14 @@ public MobLootEntry(float defaultXpMultiplier, int flatXpIncrease) { @Config.Comment("Flat xp modifier that will be added to mobs spawned by this spawner type") public int flatXpIncrease; + @Config.Comment({"Remove all existing item drops from the mobs spawned by this spawner", "'Added Items' are added afterwards"}) + public boolean removeAllItems; + + @Config.Comment({"Which items to remove from the drops of the mobs spawned", "Format: 'modid:item(:meta)' (meta is optional)", "If 'Remove All Items' is true, this does nothing"}) + public String[] removedItems; + + @Config.Comment({"Which items to add to the drops of the mobs spawned", "Format: 'modid:item(:count(:meta(:chance)))' (count, meta and chance are optional)"}) + public String[] addedItems; } } }