From 1394926e533a8548d8ca9ad9620b82872bbabdc5 Mon Sep 17 00:00:00 2001 From: rmichela Date: Thu, 8 Dec 2011 00:33:59 -0500 Subject: [PATCH] [Bleeding] Implement Metadata framework for Entities, Blocks, and Worlds --- .../org/bukkit/craftbukkit/CraftChunk.java | 4 + .../craftbukkit/CraftOfflinePlayer.java | 19 ++++ .../org/bukkit/craftbukkit/CraftServer.java | 18 ++++ .../org/bukkit/craftbukkit/CraftWorld.java | 23 +++++ .../bukkit/craftbukkit/block/CraftBlock.java | 21 ++++- .../craftbukkit/block/CraftBlockState.java | 20 ++++ .../craftbukkit/entity/CraftEntity.java | 20 +++- .../craftbukkit/entity/CraftPlayer.java | 21 +++++ .../metadata/BlockMetadataStore.java | 94 +++++++++++++++++++ .../metadata/EntityMetadataStore.java | 22 +++++ .../metadata/PlayerMetadataStore.java | 23 +++++ .../metadata/WorldMetadataStore.java | 22 +++++ 12 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/metadata/BlockMetadataStore.java create mode 100644 src/main/java/org/bukkit/craftbukkit/metadata/EntityMetadataStore.java create mode 100644 src/main/java/org/bukkit/craftbukkit/metadata/PlayerMetadataStore.java create mode 100644 src/main/java/org/bukkit/craftbukkit/metadata/WorldMetadataStore.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index 3ec77b3e9c..36cc3a3797 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -35,6 +35,10 @@ public class CraftChunk implements Chunk { return worldServer.getWorld(); } + public CraftWorld getCraftWorld() { + return (CraftWorld) getWorld(); + } + public net.minecraft.server.Chunk getHandle() { net.minecraft.server.Chunk c = weakChunk.get(); if (c == null) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java index 12b173d1ce..fd86834ea0 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java @@ -2,6 +2,7 @@ package org.bukkit.craftbukkit; import java.io.File; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import net.minecraft.server.EntityPlayer; import net.minecraft.server.NBTTagCompound; @@ -13,6 +14,8 @@ import org.bukkit.Server; import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.entity.Player; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; @SerializableAs("Player") public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializable { @@ -198,4 +201,20 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa } return null; } + + public void setMetadata(String metadataKey, MetadataValue metadataValue) { + server.getPlayerMetadata().setMetadata(this, metadataKey, metadataValue); + } + + public List getMetadata(String metadataKey) { + return server.getPlayerMetadata().getMetadata(this, metadataKey); + } + + public boolean hasMetadata(String metadataKey) { + return server.getPlayerMetadata().hasMetadata(this, metadataKey); + } + + public void removeMetadata(String metadataKey, Plugin plugin) { + server.getPlayerMetadata().removeMetadata(this, metadataKey, plugin); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0e46b36438..94204e40fa 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -64,6 +64,9 @@ import org.bukkit.craftbukkit.inventory.CraftShapedRecipe; import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe; import org.bukkit.craftbukkit.inventory.RecipeIterator; import org.bukkit.craftbukkit.map.CraftMapView; +import org.bukkit.craftbukkit.metadata.EntityMetadataStore; +import org.bukkit.craftbukkit.metadata.PlayerMetadataStore; +import org.bukkit.craftbukkit.metadata.WorldMetadataStore; import org.bukkit.craftbukkit.potion.CraftPotionBrewer; import org.bukkit.craftbukkit.scheduler.CraftScheduler; import org.bukkit.craftbukkit.updater.AutoUpdater; @@ -127,6 +130,9 @@ public final class CraftServer implements Server { private final Yaml yaml = new Yaml(new SafeConstructor()); private final Map offlinePlayers = new MapMaker().softValues().makeMap(); private AutoUpdater updater; + private final EntityMetadataStore entityMetadata = new EntityMetadataStore(); + private final PlayerMetadataStore playerMetadata = new PlayerMetadataStore(); + private final WorldMetadataStore worldMetadata = new WorldMetadataStore(); static { ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); @@ -1015,6 +1021,18 @@ public final class CraftServer implements Server { return console.console; } + public EntityMetadataStore getEntityMetadata() { + return entityMetadata; + } + + public PlayerMetadataStore getPlayerMetadata() { + return playerMetadata; + } + + public WorldMetadataStore getWorldMetadata() { + return worldMetadata; + } + public void detectListNameConflict(EntityPlayer entityPlayer) { // Collisions will make for invisible people for (int i = 0; i < getHandle().players.size(); ++i) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0b434f32cf..f5d565348b 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -6,6 +6,7 @@ import java.util.Set; import org.apache.commons.lang.Validate; import org.bukkit.craftbukkit.entity.*; +import org.bukkit.craftbukkit.metadata.BlockMetadataStore; import org.bukkit.entity.*; import org.bukkit.entity.Entity; @@ -30,6 +31,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.entity.Boat; import org.bukkit.Chunk; import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; import org.bukkit.BlockChangeDelegate; @@ -53,6 +55,7 @@ public class CraftWorld implements World { private ConcurrentMap unloadedChunks = new MapMaker().weakValues().makeMap(); private final ChunkGenerator generator; private final List populators = new ArrayList(); + private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this); private static final Random rand = new Random(); @@ -631,6 +634,10 @@ public class CraftWorld implements World { return Difficulty.getByValue(this.getHandle().difficulty); } + public BlockMetadataStore getBlockMetadata() { + return blockMetadata; + } + public boolean hasStorm() { return world.worldData.hasStorm(); } @@ -1031,4 +1038,20 @@ public class CraftWorld implements World { public void setTicksPerMonsterSpawns(int ticksPerMonsterSpawns) { world.ticksPerMonsterSpawns = ticksPerMonsterSpawns; } + + public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { + server.getWorldMetadata().setMetadata(this, metadataKey, newMetadataValue); + } + + public List getMetadata(String metadataKey) { + return server.getWorldMetadata().getMetadata(this, metadataKey); + } + + public boolean hasMetadata(String metadataKey) { + return server.getWorldMetadata().hasMetadata(this, metadataKey); + } + + public void removeMetadata(String metadataKey, Plugin owningPlugin) { + server.getWorldMetadata().removeMetadata(this, metadataKey, owningPlugin); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java index 0eb8820ef6..3179e2efe8 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -3,7 +3,6 @@ package org.bukkit.craftbukkit.block; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.List; import net.minecraft.server.BiomeBase; import net.minecraft.server.BlockRedstoneWire; @@ -20,8 +19,12 @@ import org.bukkit.block.BlockState; import org.bukkit.block.PistonMoveReaction; import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; import org.bukkit.util.BlockVector; +import java.util.List; + public class CraftBlock implements Block { private final CraftChunk chunk; private final int x; @@ -404,4 +407,20 @@ public class CraftBlock implements Block { } } } + + public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { + chunk.getCraftWorld().getBlockMetadata().setMetadata(this, metadataKey, newMetadataValue); + } + + public List getMetadata(String metadataKey) { + return chunk.getCraftWorld().getBlockMetadata().getMetadata(this, metadataKey); + } + + public boolean hasMetadata(String metadataKey) { + return chunk.getCraftWorld().getBlockMetadata().hasMetadata(this, metadataKey); + } + + public void removeMetadata(String metadataKey, Plugin owningPlugin) { + chunk.getCraftWorld().getBlockMetadata().removeMetadata(this, metadataKey, owningPlugin); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java index 34d8290f4f..8164d7dd1b 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java @@ -9,6 +9,10 @@ import org.bukkit.block.BlockState; import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.material.MaterialData; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; + +import java.util.List; public class CraftBlockState implements BlockState { private final CraftWorld world; @@ -189,4 +193,20 @@ public class CraftBlockState implements BlockState { hash = 73 * hash + (this.data != null ? this.data.hashCode() : 0); return hash; } + + public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { + chunk.getCraftWorld().getBlockMetadata().setMetadata(getBlock(), metadataKey, newMetadataValue); + } + + public List getMetadata(String metadataKey) { + return chunk.getCraftWorld().getBlockMetadata().getMetadata(getBlock(), metadataKey); + } + + public boolean hasMetadata(String metadataKey) { + return chunk.getCraftWorld().getBlockMetadata().hasMetadata(getBlock(), metadataKey); + } + + public void removeMetadata(String metadataKey, Plugin owningPlugin) { + chunk.getCraftWorld().getBlockMetadata().removeMetadata(getBlock(), metadataKey, owningPlugin); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 47854ae817..6252884ab9 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -10,6 +10,8 @@ import org.bukkit.World; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; import java.util.List; @@ -130,7 +132,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { } else if (entity instanceof EntityPainting) { return new CraftPainting(server, (EntityPainting) entity); } else if (entity instanceof EntityTNTPrimed) { return new CraftTNTPrimed(server, (EntityTNTPrimed) entity); } - + throw new IllegalArgumentException("Unknown entity"); } @@ -324,4 +326,20 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { hash = 29 * hash + this.getEntityId(); return hash; } + + public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { + server.getEntityMetadata().setMetadata(this, metadataKey, newMetadataValue); + } + + public List getMetadata(String metadataKey) { + return server.getEntityMetadata().getMetadata(this, metadataKey); + } + + public boolean hasMetadata(String metadataKey) { + return server.getEntityMetadata().hasMetadata(this, metadataKey); + } + + public void removeMetadata(String metadataKey, Plugin owningPlugin) { + server.getEntityMetadata().removeMetadata(this, metadataKey, owningPlugin); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 97d04d91e0..03c75d64bc 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -8,6 +8,7 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; @@ -29,6 +30,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.map.MapView; +import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.messaging.StandardMessenger; @@ -705,4 +707,23 @@ public class CraftPlayer extends CraftHumanEntity implements Player { public EntityType getType() { return EntityType.PLAYER; } + + public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { + server.getPlayerMetadata().setMetadata(this, metadataKey, newMetadataValue); + } + + @Override + public List getMetadata(String metadataKey) { + return server.getPlayerMetadata().getMetadata(this, metadataKey); + } + + @Override + public boolean hasMetadata(String metadataKey) { + return server.getPlayerMetadata().hasMetadata(this, metadataKey); + } + + @Override + public void removeMetadata(String metadataKey, Plugin owningPlugin) { + server.getPlayerMetadata().removeMetadata(this, metadataKey, owningPlugin); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/metadata/BlockMetadataStore.java b/src/main/java/org/bukkit/craftbukkit/metadata/BlockMetadataStore.java new file mode 100644 index 0000000000..5b484d0d56 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/metadata/BlockMetadataStore.java @@ -0,0 +1,94 @@ +package org.bukkit.craftbukkit.metadata; + +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.metadata.MetadataStore; +import org.bukkit.metadata.MetadataStoreBase; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; + +import java.util.List; + +/** + * A BlockMetadataStore stores metadata values for {@link Block} objects. + */ +public class BlockMetadataStore extends MetadataStoreBase implements MetadataStore { + + private World owningWorld; + + /** + * Initializes a BlockMetadataStore. + * @param owningWorld The world to which this BlockMetadataStore belongs. + */ + public BlockMetadataStore(World owningWorld) { + this.owningWorld = owningWorld; + } + + /** + * Generates a unique metadata key for a {@link Block} object based on its coordinates in the world. + * @see MetadataStoreBase#disambiguate(Object, String) + * @param block the block + * @param metadataKey The name identifying the metadata value + * @return a unique metadata key + */ + @Override + protected String disambiguate(Block block, String metadataKey) { + return Integer.toString(block.getX()) + ":" + Integer.toString(block.getY()) + ":" + Integer.toString(block.getZ()) + ":" + metadataKey; + } + + /** + * Retrieves the metadata for a {@link Block}, ensuring the block being asked for actually belongs to this BlockMetadataStore's + * owning world. + * @see MetadataStoreBase#getMetadata(Object, String) + */ + @Override + public List getMetadata(Block block, String metadataKey) { + if(block.getWorld() == owningWorld) { + return super.getMetadata(block, metadataKey); + } else { + throw new IllegalArgumentException("Block does not belong to world " + owningWorld.getName()); + } + } + + /** + * Tests to see if a metadata value has been added to a {@link Block}, ensuring the block being interrogated belongs + * to this BlockMetadataStore's owning world. + * @see MetadataStoreBase#hasMetadata(Object, String) + */ + @Override + public boolean hasMetadata(Block block, String metadataKey) { + if(block.getWorld() == owningWorld) { + return super.hasMetadata(block, metadataKey); + } else { + throw new IllegalArgumentException("Block does not belong to world " + owningWorld.getName()); + } + } + + /** + * Removes metadata from from a {@link Block} belonging to a given {@link Plugin}, ensuring the block being deleted from belongs + * to this BlockMetadataStore's owning world. + * @see MetadataStoreBase#removeMetadata(Object, String, org.bukkit.plugin.Plugin) + */ + @Override + public void removeMetadata(Block block, String metadataKey, Plugin owningPlugin) { + if(block.getWorld() == owningWorld) { + super.removeMetadata(block, metadataKey, owningPlugin); + } else { + throw new IllegalArgumentException("Block does not belong to world " + owningWorld.getName()); + } + } + + /** + * Sets or overwrites a metadata value on a {@link Block} from a given {@link Plugin}, ensuring the target block belongs + * to this BlockMetadataStore's owning world. + * @see MetadataStoreBase#setMetadata(Object, String, org.bukkit.metadata.MetadataValue) + */ + @Override + public void setMetadata(Block block, String metadataKey, MetadataValue newMetadataValue) { + if(block.getWorld() == owningWorld) { + super.setMetadata(block, metadataKey, newMetadataValue); + } else { + throw new IllegalArgumentException("Block does not belong to world " + owningWorld.getName()); + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/metadata/EntityMetadataStore.java b/src/main/java/org/bukkit/craftbukkit/metadata/EntityMetadataStore.java new file mode 100644 index 0000000000..d592b9a531 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/metadata/EntityMetadataStore.java @@ -0,0 +1,22 @@ +package org.bukkit.craftbukkit.metadata; + +import org.bukkit.entity.Entity; +import org.bukkit.metadata.MetadataStore; +import org.bukkit.metadata.MetadataStoreBase; + +/** + * An EntityMetadataStore stores metadata values for all {@link Entity} classes an their descendants. + */ +public class EntityMetadataStore extends MetadataStoreBase implements MetadataStore { + /** + * Generates a unique metadata key for an {@link Entity} entity ID. + * @see MetadataStoreBase#disambiguate(Object, String) + * @param entity the entity + * @param metadataKey The name identifying the metadata value + * @return a unique metadata key + */ + @Override + protected String disambiguate(Entity entity, String metadataKey) { + return Integer.toString(entity.getEntityId()) + ":" + metadataKey; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/metadata/PlayerMetadataStore.java b/src/main/java/org/bukkit/craftbukkit/metadata/PlayerMetadataStore.java new file mode 100644 index 0000000000..d4d7f38b13 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/metadata/PlayerMetadataStore.java @@ -0,0 +1,23 @@ +package org.bukkit.craftbukkit.metadata; + +import org.bukkit.OfflinePlayer; +import org.bukkit.metadata.MetadataStore; +import org.bukkit.metadata.MetadataStoreBase; + +/** + * A PlayerMetadataStore stores metadata for {@link org.bukkit.entity.Player} and {@link OfflinePlayer} objects. + */ +public class PlayerMetadataStore extends MetadataStoreBase implements MetadataStore { + /** + * Generates a unique metadata key for {@link org.bukkit.entity.Player} and {@link OfflinePlayer} using the player + * name. + * @see MetadataStoreBase#disambiguate(Object, String) + * @param player the player + * @param metadataKey The name identifying the metadata value + * @return a unique metadata key + */ + @Override + protected String disambiguate(OfflinePlayer player, String metadataKey) { + return player.getName().toLowerCase() + ":" + metadataKey; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/metadata/WorldMetadataStore.java b/src/main/java/org/bukkit/craftbukkit/metadata/WorldMetadataStore.java new file mode 100644 index 0000000000..dd37ed2949 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/metadata/WorldMetadataStore.java @@ -0,0 +1,22 @@ +package org.bukkit.craftbukkit.metadata; + +import org.bukkit.World; +import org.bukkit.metadata.MetadataStore; +import org.bukkit.metadata.MetadataStoreBase; + +/** + * An WorldMetadataStore stores metadata values for {@link World} objects. + */ +public class WorldMetadataStore extends MetadataStoreBase implements MetadataStore { + /** + * Generates a unique metadata key for a {@link World} object based on the world UID. + * @see WorldMetadataStore#disambiguate(Object, String) + * @param world the world + * @param metadataKey The name identifying the metadata value + * @return a unique metadata key + */ + @Override + protected String disambiguate(World world, String metadataKey) { + return world.getUID().toString() + ":" + metadataKey; + } +}