Every time I think I conquer this it stumps me again. I’m porting my block protection / economy plugin from Bukkit to Sponge. The protections and individual block prices are all setup in the plugin config file. I need to be able to identify block variants not only for permission error messages (“You can’t break dark prismarine on this plot!”), but also to allow the user to specify different prices for block variants. An example config file section:
"minecraft:prismarine":
type: "prismarine:rough"
name: prismarine
price: 0.75
type: "prismarine:bricks"
name: prismarine brick
price: 1.00
type: "prismarine:dark"
name: dark prismarine
price: 1.50
So for each block id, minecraft:prismarine in this case, I make a BlockPermissionSet. If the id has variants, like prismarine does, I create a BlockPermissionSet for each one, but the variant BlockPermissionSets get stored in an internal arraylist named subtypes. If the block has no variants, like cobblestone, that list is empty. With Bukkit, I used the block data value to identify block variants, so instead of type: “prismarine:dark” i had data: 2. Not elegant, but it worked and it was the only way to do it with Bukkit.
So now we have CatalogTypes to identify the blocks. I made a map of block IDs to CatalogType classes…
typeMap.put("minecraft:carpet", DyeColor.class);
typeMap.put("minecraft:cobblestone_wall", WallType.class);
typeMap.put("minecraft:dirt", DirtType.class);
typeMap.put("minecraft:double_plant", DoublePlantType.class);
typeMap.put("minecraft:double_stone_slab", SlabType.class);
typeMap.put("minecraft:double_stone_slab2", SlabType.class);
...
and a helper method…
public Class<? extends CatalogType> getVariantClass(String id) { return typeMap.get(id); }
So I could get the correct variant types from the config file like this:
private final String id; // The block ID for this permission set
private String variantID; // The variant ID for the block variant
private BlockType blockType; // The BlockType for the ID from the config file
private CatalogType variantType; // The CatalogType for the block variant
private List<BlockPermissionSet> subtypes; // All the other variant types for this block ID
public BlockPermissionSet(ConfigurationNode node) {
id = (load ID string from config file);
variantID = (load variant ID from config file, if applicable);
blockType = Sponge.getRegistry().getType(BlockType.class, id);
variantType = Sponge.getRegistry().getType(typeMap.get(id), variantID);
}
So now variantType is stored in the block permission set. I store it as a CatalogType because we don’t know what type it will be at compile time. When a block break event occurs, this permission set will be retrieved by another class that has a HashMap of IDs and block permission sets, and then passed to the event handler. Since the event handler doesn’t know if this block has a variant or not, the event handler calls this method in BlockPermissionSet:
public BlockPermissionSet getByBlock(BlockSnapshot block) {
if(variantType == null) return this;
if(variantType == [the variant type of the block]) return this;
for(BlockPermissionSet bps : subtypes)
if(bps.getVariantType() == [the variant type of the block])
return bps;
}
So if this permission set has no variant, the method returns itself. If there are variants, it checks itself for equality and returns itself if there is a match. If not, it checks each subtype for equality and returns that BlockPermissionSet if there’s a match.
The problem is the part in brackets. I have the variant type I want to compare to, for example. PrismarineType.DARK. How do I compare this to the type in a BlockSnapshot? I know it’s retrieved usings Keys, like this:
CatalogType variantType = (our stored variant type, for examlple, PrismarineType.DARK)
BlockSnapshot block = (some block);
Key<? extends BaseValue<?>> key = block.get(Keys.PRISMARINE_TYPE); // I know this refers to a specific type, but I could make another map of block IDs and keys and retrieve it that way
[how do I compare my CatalogType to the one contained in this key?]
The problem of course, is that I can’t refer to the type of the key directly, since there are many different types of block variants (PrismarineType, StoneType, BrickType, PlantType, etc.). It would be easy if I could just say
Key<Value<PrismarineType>>
instead of Key<? extends BaseValue<?>>, but at compile time there’s no way to know which type the set will contain. I would include the entire BlockPermissionSet class, but there’s a lot of crap not related to my problem that would just be confusing. Hopefully someone with a better grasp of the data API can help me out here. Thanks in advance!