Skip to content

ModelComponent

Visual model reference for entities. Wraps a Model instance that defines appearance, animations, bounding box, and physics.

ModelComponent modelComponent = store.getComponent(ref, ModelComponent.getComponentType());
Model model = modelComponent.getModel();
Model model = modelComponent.getModel();
// identity
String assetId = model.getModelAssetId(); // e.g. "Player", "Zombie"
// scale
float scale = model.getScale();
// visual paths
String modelPath = model.getModel(); // .blockymodel file
String texturePath = model.getTexture();
// dimensions
Box boundingBox = model.getBoundingBox();
float eyeHeight = model.getEyeHeight();
// physics (used if no PhysicsValues component)
PhysicsValues physics = model.getPhysicsValues();
// attachments (equipment slots, etc.)
ModelAttachment[] attachments = model.getAttachments();
Map<String, String> attachmentIds = model.getRandomAttachmentIds();

Models are created from ModelAsset definitions:

// get asset from registry
ModelAsset asset = ModelAsset.getAssetMap().getAsset("Zombie");
// create model with specific scale
Model model = Model.createScaledModel(asset, 1.5f);
// create with unit scale (1.0)
Model model = Model.createUnitScaleModel(asset);
// create with random scale (within asset's min/max)
Model model = Model.createRandomScaleModel(asset);
// create with attachments
Map<String, String> attachments = new HashMap<>();
attachments.put("head", "knight_helmet");
attachments.put("hand_right", "iron_sword");
Model model = Model.createScaledModel(asset, 1.0f, attachments);
// create new model
ModelAsset asset = ModelAsset.getAssetMap().getAsset("Skeleton");
Model newModel = Model.createScaledModel(asset, 1.0f);
// replace component
store.putComponent(ref, ModelComponent.getComponentType(), new ModelComponent(newModel));

When the model changes, ModelSystems.UpdateBoundingBox automatically updates the entity’s BoundingBox component.

To change equipment/attachments on an existing model:

ModelComponent modelComponent = store.getComponent(ref, ModelComponent.getComponentType());
Model currentModel = modelComponent.getModel();
// get the asset
ModelAsset asset = ModelAsset.getAssetMap().getAsset(currentModel.getModelAssetId());
// copy current attachments and modify
Map<String, String> attachments = new HashMap<>(currentModel.getRandomAttachmentIds());
attachments.put("head", "crown");
// create new model with updated attachments
Model newModel = Model.createScaledModel(asset, currentModel.getScale(), attachments);
store.putComponent(ref, ModelComponent.getComponentType(), new ModelComponent(newModel));

Models can have different bounding boxes for crouching:

Box normalBox = model.getBoundingBox();
Box crouchBox = model.getCrouchBoundingBox();
float crouchOffset = model.getCrouchOffset();
// or get box based on movement state
Box currentBox = model.getBoundingBox(movementStates);

Check if animations exist before playing:

Model model = modelComponent.getModel();
Map<String, ModelAsset.AnimationSet> animations = model.getAnimationSetMap();
// get animation with fallback
String animId = model.getFirstBoundAnimationId("attack_swing", "attack");

See animation system documentation for playing animations.

For models that should persist across save/load, use PersistentModel:

// save model reference
Model.ModelReference modelRef = model.toReference();
store.putComponent(entityRef, PersistentModel.getComponentType(), new PersistentModel(modelRef));
// restore model from reference
PersistentModel persistent = store.getComponent(entityRef, PersistentModel.getComponentType());
Model restoredModel = persistent.getModelReference().toModel();

Model changes are tracked via consumeNetworkOutdated() and synced to clients automatically. The component flags itself as outdated when created, ensuring initial sync.