diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index bc05cc572..c99808d75 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -447,6 +447,10 @@ public class Config extends ConfigLoader { public double getMagmaCubeXP() { return config.getDouble("Experience.Combat.Multiplier.Magma_Cube", 2.0); } public double getEnderDragonXP() { return config.getDouble("Experience.Combat.Multiplier.Ender_Dragon", 8.0); } public double getIronGolemXP() { return config.getDouble("Experience.Combat.Multiplier.Iron_Golem", 2.0); } + public double getGiantXP() { return config.getDouble("Experience.Combat.Multiplier.Giant", 4.0); } + public double getWitherXP() { return config.getDouble("Experience.Combat.Multiplier.Wither", 7.0); } + public double getWitherSkeletonXP() { return config.getDouble("Experience.Combat.Multiplier.Wither_Skeleton", 4.0); } + public double getWitchXP() { return config.getDouble("Experience.Combat.Multiplier.Witch", 4.0); } /* XP Formula Multiplier */ public int getFormulaMultiplierCurve() { return config.getInt("Experience.Formula.Curve_Modifier", 20); } diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 189326e5f..f831b4819 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -184,6 +184,8 @@ public class EntityListener implements Listener { entity.setFireTicks(0); BleedTimer.remove(entity); Archery.arrowRetrievalCheck(entity); + mcMMO.p.placeStore.removeSpawnedMob(((Entity) entity)); + mcMMO.p.placeStore.removeSpawnedPet(((Entity) entity)); } /** @@ -196,7 +198,7 @@ public class EntityListener implements Listener { SpawnReason reason = event.getSpawnReason(); if ((reason.equals(SpawnReason.SPAWNER) || reason.equals(SpawnReason.SPAWNER_EGG)) && !Config.getInstance().getExperienceGainsMobspawnersEnabled()) { - event.getEntity().setMetadata("mcmmoFromMobSpawner", new FixedMetadataValue(plugin, true)); + mcMMO.p.placeStore.addSpawnedMob(((Entity) event.getEntity())); } } @@ -397,7 +399,7 @@ public class EntityListener implements Listener { if(player.hasMetadata("NPC")) return; // Check if this player is a Citizens NPC - if (Permissions.getInstance().taming(player) && !event.getEntity().hasMetadata("mcmmoSummoned")) { + if (Permissions.getInstance().taming(player) && !mcMMO.p.placeStore.isSpawnedPet((Entity) event.getEntity())) { PlayerProfile profile = Users.getProfile(player); EntityType type = event.getEntityType(); int xp = 0; diff --git a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java index 92d599a07..d35007f60 100644 --- a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.WorldInitEvent; import org.bukkit.event.world.WorldSaveEvent; @@ -46,4 +47,10 @@ public class WorldListener implements Listener { public void onChunkUnload(ChunkUnloadEvent event) { mcMMO.placeStore.chunkUnloaded(event.getChunk().getX(), event.getChunk().getZ(), event.getWorld()); } + + @EventHandler + public void onChunkLoad(ChunkLoadEvent event) { + if(event.getChunk().getEntities().length > 0) + mcMMO.p.placeStore.loadChunk(event.getChunk().getX(), event.getChunk().getZ(), event.getWorld()); + } } diff --git a/src/main/java/com/gmail/nossr50/skills/taming/CallOfTheWildEventHandler.java b/src/main/java/com/gmail/nossr50/skills/taming/CallOfTheWildEventHandler.java index 84ad5d2a1..7a38fa8cc 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/CallOfTheWildEventHandler.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/CallOfTheWildEventHandler.java @@ -68,7 +68,7 @@ public class CallOfTheWildEventHandler { return; LivingEntity entity = (LivingEntity) player.getWorld().spawnEntity(player.getLocation(), type); - entity.setMetadata("mcmmoSummoned", new FixedMetadataValue(mcMMO.p, true)); + mcMMO.p.placeStore.addSpawnedPet((Entity) entity); ((Tameable) entity).setOwner(player); diff --git a/src/main/java/com/gmail/nossr50/util/Combat.java b/src/main/java/com/gmail/nossr50/util/Combat.java index b5086b742..819967a75 100644 --- a/src/main/java/com/gmail/nossr50/util/Combat.java +++ b/src/main/java/com/gmail/nossr50/util/Combat.java @@ -10,6 +10,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.IronGolem; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; import org.bukkit.entity.Tameable; import org.bukkit.entity.Wolf; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -398,14 +399,18 @@ public class Combat { baseXP = 20 * configInstance.getPlayerVersusPlayerXP(); } } - else if (!target.hasMetadata("mcmmoFromMobSpawner")) { - if (target instanceof Animals && !target.hasMetadata("mcmmoSummoned")) { + else if (!mcMMO.p.placeStore.isSpawnedMob(((Entity) target))) { + if (target instanceof Animals && !mcMMO.p.placeStore.isSpawnedPet((Entity) target)) { baseXP = configInstance.getAnimalsXP(); } else { EntityType type = target.getType(); switch (type) { + case BAT: + baseXP = configInstance.getAnimalsXP(); + break; + case BLAZE: baseXP = configInstance.getBlazeXP(); break; @@ -430,6 +435,10 @@ public class Combat { baseXP = configInstance.getGhastXP(); break; + case GIANT: + baseXP = configInstance.getGiantXP(); + break; + case MAGMA_CUBE: baseXP = configInstance.getMagmaCubeXP(); break; @@ -450,9 +459,14 @@ public class Combat { break; case SKELETON: - baseXP = configInstance.getSkeletonXP(); - break; - + switch(((Skeleton) target).getSkeletonType()) { + case WITHER: + baseXP = configInstance.getWitherSkeletonXP(); + break; + default: + baseXP = configInstance.getSkeletonXP(); + break; + } case SLIME: baseXP = configInstance.getSlimeXP(); break; @@ -461,6 +475,14 @@ public class Combat { baseXP = configInstance.getSpiderXP(); break; + case WITCH: + baseXP = configInstance.getWitchXP(); + break; + + case WITHER: + baseXP = configInstance.getWitherXP(); + break; + case ZOMBIE: baseXP = configInstance.getZombieXP(); break; diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkManager.java index 6937c188e..23b24a8a4 100755 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkManager.java @@ -4,6 +4,7 @@ import java.io.IOException; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Entity; public interface ChunkManager { public void closeAll(); @@ -165,4 +166,11 @@ public interface ChunkManager { * Delete any ChunkletStores that are empty */ public void cleanUp(); + + public boolean isSpawnedMob(Entity entity); + public boolean isSpawnedPet(Entity entity); + public void addSpawnedMob(Entity entity); + public void addSpawnedPet(Entity entity); + public void removeSpawnedMob(Entity entity); + public void removeSpawnedPet(Entity entity); } diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkStore.java b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkStore.java index fbc331231..69ed58485 100755 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkStore.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/ChunkStore.java @@ -1,6 +1,8 @@ package com.gmail.nossr50.util.blockmeta.chunkmeta; import java.io.Serializable; +import java.util.List; +import java.util.UUID; import com.gmail.nossr50.util.blockmeta.ChunkletStore; @@ -71,4 +73,15 @@ public interface ChunkStore extends Serializable { * @param otherStore Another ChunkletStore that this one should copy all data from */ public void copyFrom(ChunkletStore otherStore); + + public boolean isSpawnedMob(UUID id); + public boolean isSpawnedPet(UUID id); + public void addSpawnedMob(UUID id); + public void addSpawnedPet(UUID id); + public void removeSpawnedMob(UUID id); + public void removeSpawnedPet(UUID id); + public void clearSpawnedMobs(); + public void clearSpawnedPets(); + public List getSpawnedMobs(); + public List getSpawnedPets(); } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/HashChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/HashChunkManager.java index e6f5aef37..cc81573ff 100755 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/HashChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/HashChunkManager.java @@ -10,12 +10,16 @@ import java.lang.Integer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.ChunkletUnloader; import com.gmail.nossr50.runnables.blockstoreconversion.BlockStoreConversionZDirectory; @@ -26,6 +30,10 @@ public class HashChunkManager implements ChunkManager { public HashMap store = new HashMap(); public ArrayList converters = new ArrayList(); private HashMap oldData = new HashMap(); + private List spawnedMobs = new ArrayList(); + private List spawnedPets = new ArrayList(); + private List mobsToRemove = new ArrayList(); + private boolean safeToRemoveMobs = true; @Override public synchronized void closeAll() { @@ -159,6 +167,23 @@ public class HashChunkManager implements ChunkManager { if(in != null) { store.put(world.getName() + "," + cx + "," + cz, in); + + List mobs = in.getSpawnedMobs(); + List pets = in.getSpawnedPets(); + + if(mobs.isEmpty() && pets.isEmpty()) + return; + + for(LivingEntity entity : world.getLivingEntities()) { + if(mobs.contains(entity.getUniqueId())) + addSpawnedMob((Entity) entity); + + if(pets.contains(entity.getUniqueId())) + addSpawnedPet((Entity) entity); + } + + in.clearSpawnedMobs(); + in.clearSpawnedPets(); } } @@ -168,6 +193,26 @@ public class HashChunkManager implements ChunkManager { if(store.containsKey(world.getName() + "," + cx + "," + cz)) { store.remove(world.getName() + "," + cx + "," + cz); + + for(Entity entity : spawnedMobs) { + if(!isEntityInChunk(entity, cx, cz, world)) + continue; + + mobsToRemove.add(entity); + } + + for(Entity entity : spawnedPets) { + if(!isEntityInChunk(entity, cx, cz, world)) + continue; + + mobsToRemove.add(entity); + } + + if(safeToRemoveMobs) { + spawnedMobs.remove(mobsToRemove); + spawnedPets.remove(mobsToRemove); + mobsToRemove.clear(); + } } } @@ -176,9 +221,51 @@ public class HashChunkManager implements ChunkManager { if(world == null) return; + boolean unloaded = false; + if(!store.containsKey(world.getName() + "," + cx + "," + cz)) { + for(Entity entity : spawnedMobs) { + if(!isEntityInChunk(entity, cx, cz, world)) + continue; + + loadChunk(cx, cz, world); + unloaded = true; + break; + } + + if(!unloaded) { + for(Entity entity : spawnedPets) { + if(!isEntityInChunk(entity, cx, cz, world)) + continue; + + loadChunk(cx, cz, world); + unloaded = true; + break; + } + } + } + + if(!store.containsKey(world.getName() + "," + cx + "," + cz) && unloaded) { + ChunkStore cStore = ChunkStoreFactory.getChunkStore(world, cx, cz); + store.put(world.getName() + "," + cx + "," + cz, cStore); + } + if(store.containsKey(world.getName() + "," + cx + "," + cz)) { ChunkStore out = store.get(world.getName() + "," + cx + "," + cz); + for(Entity entity : spawnedMobs) { + if(!isEntityInChunk(entity, cx, cz, world)) + continue; + + out.addSpawnedMob(entity.getUniqueId()); + } + + for(Entity entity : spawnedPets) { + if(!isEntityInChunk(entity, cx, cz, world)) + continue; + + out.addSpawnedPet(entity.getUniqueId()); + } + if(!out.isDirty()) return; @@ -186,6 +273,22 @@ public class HashChunkManager implements ChunkManager { } } + private boolean isEntityInChunk(Entity entity, int cx, int cz, World world) { + if(entity == null || world == null) + return false; + + if(entity.getLocation().getChunk().getX() != cx) + return false; + + if(entity.getLocation().getChunk().getZ() != cz) + return false; + + if(entity.getWorld() != world) + return false; + + return true; + } + @Override public synchronized boolean isChunkLoaded(int cx, int cz, World world) { if(world == null) @@ -224,11 +327,35 @@ public class HashChunkManager implements ChunkManager { cz = Integer.parseInt(info[2]); } catch(Exception e) { - return; + continue; } saveChunk(cx, cz, world); } } + + for(Entity entity : spawnedMobs) { + World entityWorld = entity.getWorld(); + + if(world != entityWorld) + continue; + + int cx = entity.getLocation().getChunk().getX(); + int cz = entity.getLocation().getChunk().getZ(); + + saveChunk(cx, cz, world); + } + + for(Entity entity : spawnedPets) { + World entityWorld = entity.getWorld(); + + if(world != entityWorld) + continue; + + int cx = entity.getLocation().getChunk().getX(); + int cz = entity.getLocation().getChunk().getZ(); + + saveChunk(cx, cz, world); + } } @Override @@ -250,11 +377,43 @@ public class HashChunkManager implements ChunkManager { cz = Integer.parseInt(info[2]); } catch(Exception e) { - return; + continue; } unloadChunk(cx, cz, world); } } + + safeToRemoveMobs = false; + + for(Entity entity : spawnedMobs) { + World entityWorld = entity.getWorld(); + + if(world != entityWorld) + continue; + + int cx = entity.getLocation().getChunk().getX(); + int cz = entity.getLocation().getChunk().getZ(); + + unloadChunk(cx, cz, world); + } + + for(Entity entity : spawnedPets) { + World entityWorld = entity.getWorld(); + + if(world != entityWorld) + continue; + + int cx = entity.getLocation().getChunk().getX(); + int cz = entity.getLocation().getChunk().getZ(); + + unloadChunk(cx, cz, world); + } + + safeToRemoveMobs = true; + + spawnedMobs.remove(mobsToRemove); + spawnedPets.remove(mobsToRemove); + mobsToRemove.clear(); } @Override @@ -415,4 +574,32 @@ public class HashChunkManager implements ChunkManager { converters.add(converter); } } + + public boolean isSpawnedMob(Entity entity) { + return spawnedMobs.contains(entity); + } + + public boolean isSpawnedPet(Entity entity) { + return spawnedPets.contains(entity); + } + + public void addSpawnedMob(Entity entity) { + if(!isSpawnedMob(entity)) + spawnedMobs.add(entity); + } + + public void addSpawnedPet(Entity entity) { + if(!isSpawnedPet(entity)) + spawnedPets.add(entity); + } + + public void removeSpawnedMob(Entity entity) { + if(isSpawnedMob(entity)) + spawnedMobs.remove(entity); + } + + public void removeSpawnedPet(Entity entity) { + if(isSpawnedPet(entity)) + spawnedPets.remove(entity); + } } diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/NullChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/NullChunkManager.java index e1cf4b574..12816b9d6 100755 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/NullChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/NullChunkManager.java @@ -4,6 +4,7 @@ import java.io.IOException; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Entity; public class NullChunkManager implements ChunkManager { @@ -86,4 +87,11 @@ public class NullChunkManager implements ChunkManager { @Override public void cleanUp() {} + + public boolean isSpawnedMob(Entity entity) {return false;} + public boolean isSpawnedPet(Entity entity) {return false;} + public void addSpawnedMob(Entity entity) {} + public void addSpawnedPet(Entity entity) {} + public void removeSpawnedMob(Entity entity) {} + public void removeSpawnedPet(Entity entity) {} } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/PrimitiveChunkStore.java b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/PrimitiveChunkStore.java index 284932e26..56ea9af44 100755 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/PrimitiveChunkStore.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/chunkmeta/PrimitiveChunkStore.java @@ -3,6 +3,8 @@ package com.gmail.nossr50.util.blockmeta.chunkmeta; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import org.bukkit.World; @@ -15,11 +17,13 @@ public class PrimitiveChunkStore implements ChunkStore { transient private boolean dirty = false; /** X, Z, Y */ public boolean[][][] store; - private static final int CURRENT_VERSION = 5; + private static final int CURRENT_VERSION = 6; private static final int MAGIC_NUMBER = 0xEA5EDEBB; private int cx; private int cz; private UUID worldUid; + private List spawnedMobs = new ArrayList(); + private List spawnedPets = new ArrayList(); transient private int worldHeight; transient private int xBitShifts; transient private int zBitShifts; @@ -100,6 +104,64 @@ public class PrimitiveChunkStore implements ChunkStore { dirty = true; } + public boolean isSpawnedMob(UUID id) { + return spawnedMobs.contains(id); + } + + public boolean isSpawnedPet(UUID id) { + return spawnedPets.contains(id); + } + + public void addSpawnedMob(UUID id) { + if(!isSpawnedMob(id)) { + spawnedMobs.add(id); + dirty = true; + } + } + + public void addSpawnedPet(UUID id) { + if(!isSpawnedPet(id)) { + spawnedPets.add(id); + dirty = true; + } + } + + public void removeSpawnedMob(UUID id) { + if(isSpawnedMob(id)) { + spawnedMobs.remove(id); + dirty = true; + } + } + + public void removeSpawnedPet(UUID id) { + if(isSpawnedPet(id)) { + spawnedPets.remove(id); + dirty = true; + } + } + + public void clearSpawnedMobs() { + if(!spawnedMobs.isEmpty()) { + spawnedMobs.clear(); + dirty = true; + } + } + + public void clearSpawnedPets() { + if(!spawnedPets.isEmpty()) { + spawnedPets.clear(); + dirty = true; + } + } + + public List getSpawnedMobs() { + return spawnedMobs; + } + + public List getSpawnedPets() { + return spawnedPets; + } + private void writeObject(ObjectOutputStream out) throws IOException { out.writeInt(MAGIC_NUMBER); out.writeInt(CURRENT_VERSION); @@ -110,6 +172,9 @@ public class PrimitiveChunkStore implements ChunkStore { out.writeInt(cz); out.writeObject(store); + out.writeObject(spawnedMobs); + out.writeObject(spawnedPets); + dirty = false; } @@ -139,9 +204,19 @@ public class PrimitiveChunkStore implements ChunkStore { store = (boolean[][][]) in.readObject(); if (fileVersionNumber < CURRENT_VERSION) { - fixArray(); + if(fileVersionNumber < 5) + fixArray(); + if(fileVersionNumber < 6) { + spawnedMobs = new ArrayList(); + spawnedPets = new ArrayList(); + } dirty = true; } + + if(fileVersionNumber >= 6) { + spawnedMobs = (ArrayList) in.readObject(); + spawnedPets = (ArrayList) in.readObject(); + } } private void fixArray() { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 0335674a6..2c704bdb6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -323,6 +323,10 @@ Experience: Slime: 2.0 Ghast: 3.0 Iron_Golem: 2.0 + Giant: 4.0 + Wither: 7.0 + Wither_Skeleton: 4.0 + Witch: 4.0 # # Settings for commands ###