Potential BlockType system sketch

This is a sketch I drew up for a BlockType system that covers a 1.8-style property/variant system. This would ideally end up in SpongeAPI to replace the temporary @Deprecated data-based methods, but I’m looking for thoughts before I flesh it out too thoroughly.

The most important interface is of course BlockType:

String getId(); // "minecraft:stone"
String getFullId(); // "minecraft:stone[variant=andesite]"
boolean isBaseType(); // true if this == getBaseType()
BlockType getBaseType(); // GameRegistry#getBlock(getId())

// get the available properties - same within one id
Collection<BlockProperty> getProperties();
// get this variant's value for the given property
Object getProperty(BlockProperty prop);
// get another BlockType with this property changed
BlockType withProperty(BlockProperty prop, Object value);

// other methods of things you can do to blocks?

The BlockProperty interface covers what can be examined for a specific block property:

String getName(); // "variant"
Type getType(); // what type this is - kind of iffy
enum Type { BOOLEAN, INTEGER, STRING };

Object getDefault(); // this property's default value
// assert that a value is valid and filter it to its main form
Object validate(Object value) throws IllegalArgumentException;

// child interfaces for knowing more about a property
interface IntegerProperty extends BlockProperty {
    int getMinimum(), getMaximum();
}
interface StringProperty extends BlockProperty {
    Collection<String> getValues();
}

Properties of various types would implement getDefault and validate to ensure a value a plugin wants to set with withProperty is valid. If constructing properties in plugin code is needed (for example, to define custom block types, which I have not yet considered), there could be some methods along the lines of:

BlockProperty ofBoolean(String name); // boolean property, default false
BlockProperty ofRange(String name, int min, int max); // int in range [min,max]
BlockProperty ofStrings(String name, String... values); // string, one of values
BlockProperty ofEnum(String name, Class<? extends Enum> clazz); // from enum values

This is a fairly early draft and I understand it’s kind of lengthy; just looking for thoughts.

4 Likes

Looks good.
If I had a cookie, you would of gained 1 cookie.

I’m also liking the validate() method.

‘Property’ being used to refer to both the ‘kind’ and the ‘value’ of the property seems a bit confusing. getProperties() returns a collection of BlockProperty instances, but getProperty(…) returns the value associated with that BlockProperty.

I’m also a unclear on how one would obtain an instance of of a BlockProperty to use as an argument in getProperty(…) without calling getProperties() first, which feel kind of clumsy.

Otherwise this looks really good IMO. I don’t have any suggestions for addressing either of my concerns right now, but it’s feedback, right? :smile:

It might be reasonable to add parallel methods which take a String (the property name) and look up the BlockProperty internally, but it could also work to expose BlockProperty instances for the properties on vanilla blocks in some manner. I’m not sure which makes the most sense.

Why do you want to use an enum for Type? Why not generics?

interface IntegerProperty extends BlockProperty<Integer>

Perhaps to prevent people from making properties of wrong types e.g. BlockProperty<Server>

If you use generics, you can make your code type-safe. Here’s a generic version of your code:

Type-safe BlockType interface:

String getId(); // "minecraft:stone"
String getFullId(); // "minecraft:stone[variant=andesite]"
boolean isBaseType(); // true if this == getBaseType()
BlockType getBaseType(); // GameRegistry#getBlock(getId())

// get the available properties - same within one id
Collection<BlockProperty<?>> getProperties();
// get this variant's value for the given property
<T> T getProperty(BlockProperty<T> prop);
// get another BlockType with this property changed
<T> BlockType withProperty(BlockProperty<T> prop, T value);

// other methods of things you can do to blocks?

Type-safe version of BlockProperty:

public interface BlockProperty<T> {
    String getName(); // "variant"
    Class<T> getType(); // what type this is - kind of iffy

    T getDefault(); // this property's default value
    // assert that a value is valid and filter it to its main form
    T validate(T value) throws IllegalArgumentException;

    // child interfaces for knowing more about a property
    interface RangeProperty<T> extends BlockProperty<T> {
	T getMinimum();
	T getMaximum();
    }
}

Your StringProperty child interface could be replaced with BlockProperty<Collection<String>>.

I don’t think it will go wrong if there are no wrong implementations for the interfaces.

Exactly. The only problem is that you can’t use primitive data types (you need Boolean instead of boolean). But I still think Generics are better.

That should not be an issue because from Java 1.5 onward automatic boxing/unboxing is performed by the JVM.

1 Like