Add an entity
First decide what kind of entity you are adding. GDCraft has more than one runtime hierarchy, so extending an unrelated base class can leave the new behavior out of world ticking, collision, or persistence.
Choose the runtime path
Section titled “Choose the runtime path”- Autonomous living mob: extend the current
Mobhierarchy. Mob subclasses configure attributes, goals, and species-specific behavior; focused goal classes own individual AI actions. - Living actor on the older Godot body path: inspect the nearest working mob in
src/Entity/and follow its existing initializer and collision setup. The hierarchy migration is not complete, so verify which path its callers actually use. - Projectile or short-lived effect: extend the closest class under
Projectileor the relevant entity base. Trace launch, owner assignment, movement/ticking, hit handling, cleanup, and any item interaction together.
See entity simulation for the current hierarchy and the entity graph for the high-level runtime connections.
Add a scene-backed mob
Section titled “Add a scene-backed mob”- Add a C# class in
src/Entity/with the same namespace and lifecycle conventions as its peers. - Create a scene under
scenes/entities/with the root node type expected by the class. Reuse existing model, collision, and animation helpers where they fit. - Register the class and scene name in
EntityType. Registration checks that the scene exists; entity creation, saved-entity reconstruction, and spawn-egg lookup use this mapping. - Add spawn conditions through the existing spawning owner, when the mob should appear naturally. Keep those rules out of the mob’s per-tick behavior.
- Add or update persistence for any state that must survive a world save. A value held in a node field is not automatically serialized.
The registration list uses a generic class plus the scene file’s name (without .tscn):
Register<ExampleMob>("example_mob", "ExampleMob");To create and attach a registered mob at runtime, keep construction, scene-tree attachment, and world initialization in that order:
LivingMob? mob = EntityType.ByString("minecraft:example_mob")?.Create();if (mob is not null){ mob.Position = spawnPosition; parent.AddChild(mob); EntityType.InitializeInWorld(mob, world, player);}These snippets show the current API shape; replace the example ID, type, and scene with the contribution’s own values.
Keep behavior with its owner
Section titled “Keep behavior with its owner”Mob classes should compose small goals and configure their own attributes. Shared movement, targeting, and goal scheduling belongs in the corresponding base or AI type. World managers coordinate membership and ticks; avoid adding species-specific branches there when a mob or goal owns the rule.
For projectiles, check whether the base already supplies owner filtering, collision queries, gravity, deflection, and lifetime. Override only the behavior that differs, and make entity hits and block hits follow the intended independent paths.
When launching an existing projectile subclass, the helper aims it and sends it through the level’s entity-add path:
var arrow = new ArrowEntity();arrow.SetOwner(shooter);arrow.SetPos(origin.X, origin.Y, origin.Z);
Projectile.SpawnProjectileUsingShoot( arrow, world, direction.X, direction.Y, direction.Z, pow: 1.5f, uncertainty: 0.0f);The base dispatches entity and block hits to separate virtual hooks. See projectile lifecycle for the tick and hit flow.
Finish the contribution
Section titled “Finish the contribution”Check creation from each entry point you support: direct spawn, natural spawn, item use, or load from disk. Confirm collisions and hit behavior, owner cleanup, despawn, effects/drops, and save/load. Add focused coverage to the entity or persistence validation suite, then follow build and validation.