-
Notifications
You must be signed in to change notification settings - Fork 40
Cardinal Components Entity
This module allows mods to attach components to Entity
objects. Those components will be saved automatically with the entity.
Entity components are registered by an EntityComponentInitializer
, exposed as cardinal-components-entity
in the mod json (more information on the component registration page).
Component factories are registered per entity class, thereby attaching components to all instances of that class and of its subclasses. Registering a factory to both a class and its subclass will cause the latter factory to override the former, letting you eg. use a different implementation for players than for entities.
Instead of a specific class, you can also register a component factory with a Predicate<Class<? extends Entity>>
. This lets you use your own criteria like "implements a specific interface".
Entity components can be automatically synchronized from the server to the client by implementing AutoSyncedComponent
- more information is available on the component synchronization page.
Entity components support both server and client ticking. Components get ticked right after the entity they are attached to, provided the latter gets ticked through (Server/Client)World#tickEntity
.
Entity components support loading and unloading events for both server and client.
Mods can choose when and how components are copied when the player respawns. The most straightforward way to do so is by selecting a pre-defined RespawnCopyStrategy
among the following:
-
ALWAYS_COPY
: always copy the component's data, no matter the circumstances of respawn. This is generally helpful for components storing metadata like statistics, or some intrinsic traits. -
INVENTORY
: copy the component's data only if the inventory would be preserved. This is helpful for inventory extensions and experience-like resources. You may still have to listen to the player's death yourself to drop the resources (resources vanishing is not very fun, also do not forget to checkkeepInventory
before dropping stuff). -
LOSSLESS_ONLY
: copy the component's data only if the player is cloned losslessly (eg. return from the End). This should be used for data that resets on death, like health or food. -
NEVER_COPY
: this strategy is not recommended by itself, as it leads to components losing their data for no apparent reason. It can however be used in conjunction with aPlayerCopyCallback
if you have some highly custom logic.
If you want more control, you can pass your own RespawnCopyStrategy
. This is useful if you want partial losses, like losing just a few levels on death. Alternatively, you can implement PlayerComponent
on your component and not set a respawn strategy (a set RespawnCopyStrategy
will take precedence). Your component's shouldCopyForRespawn
and copyForRespawn
methods will then be called instead when performing the copy.
Setting a RespawnCopyStrategy
is done during registration to an EntityComponentFactoryRegistry
.
Instead of components attached to entities, one can use Mixin to implement an interface on the desired entity class and inject into its serialization methods.
+ No dependency required
- More setup, less maintainable
- Needs more mixins to handle player respawns
- Needs more mixins to handle synchronization
public final class MyComponents implements EntityComponentInitializer {
@Override
public void registerEntityComponentFactories(EntityComponentFactoryRegistry registry) {
// Scenario 1:
// Add the component to every ZombieEntity instance, including husks and zombie villagers
registry.registerFor(ZombieEntity.class, INFECTION, ZombieInfection::new);
// Scenario 2:
// Add the component to every instance of PlayerEntity, and ensure the component's data is always copied
registry.registerForPlayers(MAGIK, player -> new RandomIntComponent(), RespawnCopyStrategy.ALWAYS_COPY);
// Scenario 3:
// Add the component to every living entity
registry.registerFor(LivingEntity.class, BLUE, e -> new RandomIntComponent());
// Ensure the component's data is copied when keepInventory is enabled (Optional)
registry.setRespawnCopyStrategy(BLUE, RespawnCopyStrategy.INVENTORY);
// Scenario 4:
// Add the component to every entity with an inventory
registry.registerFor(Inventory.class::isAssignableFrom, RED, e -> new RandomIntComponent());
// Add a specialized component to every instance of PlayerEntity without specifying a strategy
// The attached component can implement PlayerComponent to customize respawn copying
registry.registerForPlayers(RED, PlayerIntComponent::new);
}
}