Last active
August 29, 2015 14:06
-
-
Save dualspiral/a6861a154e2b98ed3828 to your computer and use it in GitHub Desktop.
PoC for an Entity Builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Builds an entity. Usage for a plugin developer: | |
* | |
* EntityBuilder.forEntity("minecraft:creeper").with(healthComponentObject).without(OtherComponent.class).build(); | |
* | |
* An EntityValidator class would have been created prior to use. See the relevant file. | |
*/ | |
public final class EntityBuilder { | |
static { | |
// Register Minecraft entities here, or create an internal method to create them. | |
} | |
/** | |
* The map of Mob IDs to default components/validation. This probably could (should) be elsewhere - implementation detail, | |
* here for context. | |
*/ | |
private static Map<String, EntityValidator> entityMap = new HashMap<String, EntityValidator>(); | |
/** | |
* Registers a entity for use with the EntityBuilder. | |
*/ | |
public static void registerEntity(String id, EntityValidator validator) { | |
if (id.startsWith("minecraft:")) { | |
throw new InvalidStateException("You cannot replace entities in the Minecraft id namespace.") | |
} | |
if (validator == null) { | |
// We could just provide an empty validator instead. | |
throw new InvalidArgumentException("The validator must not be null"); | |
} | |
entityMap.put(id, validator); | |
} | |
/** | |
* Returns a builder for an entity that represents a mob | |
*/ | |
public static EntityBuilder forEntity(String id) { | |
if (!entityMap.containsKey(id)) { | |
// Not registered in Sponge. | |
throw new InvalidArgumentException(); | |
} | |
EntityBuilder builder = new EntityBuilder(id); | |
entityMap.get(id).defaults(builder); | |
return builder; | |
} | |
public static EntityBuilder forEntity(VanillaEntity entity) { | |
return forEntity(entity.getID()); | |
} | |
// Instance | |
private final String id; | |
/** | |
* Stores the components with their types. We use the types to avoid duplication. | |
*/ | |
private final Map<Class<? extends EntityComponent>, EntityComponent> components = new Map<Class<? extends EntityComponent>, EntityComponent>(); | |
public EntityBuilder(String id) { | |
this.id = id; | |
} | |
/** | |
* Gets the currently added component of the specified type, or {@code null} if the component | |
* is not a part of this builder. Mostly used for validation. | |
*/ | |
public EntityComponent get(Class<? extends EntityComponent> clazz) { | |
return components.get(clazz); | |
} | |
/** | |
* Adds the component, replacing any previous component of the same type. | |
* | |
* The builder could just have seperate "withHealth", "withSpeed" etc. methods, but that would | |
* make the Builder less flexible. | |
*/ | |
public EntityBuilder with(EntityComponent component) { | |
components.put(component.getClass(), component); | |
return this; | |
} | |
/** | |
* Removes the component of a specified type from the builder. | |
* Users should note that removing a default component may cause the | |
* builder to be in an invalid state and will throw an exception upon | |
* building. | |
*/ | |
public EntityBuilder without(Class<? extends EntityComponent> type) { | |
// We probably don't want to ever remove a couple of types, such as components | |
// that specify how to render the entity. We might not even want this method, | |
// but the idea is devs can re-use builders to create entities over and over, | |
// and sometimes may need to remove a component. | |
components.remove(type); | |
return this; | |
} | |
/** | |
* Validates the entity that has been built, and if valid, creates the entity. | |
*/ | |
public Entity build() { | |
// Validate that the supplied entity is valid | |
if (!entityMap.get(id).validate(this)) { | |
throw new InvalidStateException("The entity is not valid,"); | |
} | |
// Code here to create the entity from the components and the ID. | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This interface defines the default entity characteristics for the EntityBuilder, | |
* and the allowed configuration of the entity in question. | |
* | |
* I couldn't think of a better name for the interface, but as it does more than "validate" | |
* then the name could be better. | |
*/ | |
public interface EntityValidator { | |
/** | |
* Adds the default components for the entity this represents. | |
*/ | |
void defaults(EntityBuilder builder); | |
/** | |
* Validates that the requested entity can be built in the current configuration. | |
* | |
* An alternative is to have this method start creating the object, and throw an exception | |
* if the builder is in an invalid state. | |
* | |
* @returns {@code true} if the entity is valid, otherwise {@code false}. | |
*/ | |
boolean validate(EntityBuilder builder); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public enum VanillaEntity { | |
CREEPER("minecraft:creeper"), | |
SPIDER("minecraft:spider"), | |
CAVE_SPIDER("minecraft:cave_spider"), | |
... | |
private final String id; | |
private VanillaEntity(String id) { | |
this.id = id; | |
} | |
public String getID() { | |
return this.id; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment