Skip to content

Entity gameplay

Lesson 7.7

The C++ wrappers make the entity gameplay API short: queries give a std::vector<clight::Entity>, everything that can fail returns Expected<>. This lesson finds entities, changes attributes and effects, sends synced data, hurts with damage types, adds natural spawning and makes entities ride.

Find entities

cl_entity_query q = CL_ENTITY_QUERY_INIT;
q.type = CL_STR("minecraft:zombie");
q.flags = CL_QUERY_NEAREST;
auto zombies = level.entities_in_box({p.x - 16, p.y - 8, p.z - 16}, {p.x + 16, p.y + 8, p.z + 16}, &q);
if (zombies && !zombies->empty()) {
    clight::Entity nearest = zombies->front();
}
auto other = level.nearest_player(p, 32.0);           // Expected<Entity>: an error when nobody is in range
auto again = level.entity_by_uuid(saved_uuid);

Filters: type (id or #tag), tag, category ("monster", …, "player"), exclude, limit, and the CL_QUERY_* flags.

Attributes and effects

double speed = zombie.attribute("minecraft:movement_speed").value_or(0.0);
(void)zombie.add_attribute_modifier("minecraft:movement_speed", "my_mod:haste", 0.5, CL_ATTRIBUTE_ADD_MULTIPLIED_BASE);
cl_effect_opts eo = CL_EFFECT_OPTS_INIT;
eo.amplifier = 1;
bool changed = zombie.add_effect("minecraft:speed", 200, &eo);
auto info = zombie.effect("minecraft:speed");          // Expected<cl_effect_info>

Synced data

(void)boss.set_synced_string("my_mod:mode", "enraged");     // server
std::string mode = boss.synced_string("my_mod:mode").value_or("");   // server or client

Only Celestial clients with CLight receive it (CL_EV_ENTITY_SYNCED fires there).

Hurt and damage types

cl_hurt_opts h = CL_HURT_OPTS_INIT;
h.attacker = boss.raw();
bool hit = target.hurt(6.0F, "my_mod:zap", &h);

Register my_mod:zap with cl_damage_type_register (a cl_damage_type_desc with death_message and death_message_player); CL_EV_ENTITY_KNOCKBACK changes or cancels knockback.

Spawning and riding

cl_spawn_rule_desc r = CL_SPAWN_RULE_DESC_INIT;
r.type = CL_STR("my_mod:golem");
r.category = CL_STR("monster");
r.biomes = CL_STR("minecraft:dark_forest");
cl_spawn_rule_register(&r);                     // in lifecycle.register

(void)horse.set_passenger(zombie, nullptr);    // force by default
auto v = zombie.vehicle();                     // Expected<Entity>
(void)zombie.dismount();

Equipment, new events and emitters

API 1.20 adds equipment, three entity events and particle emitters:

The C functions work as they are in C++ (clight.hpp includes clight.h):

cl_entity_set_equipment(zombie, CL_EQUIP_HEAD, cl_stack_create_by_name(CL_STR("minecraft:diamond_helmet"), 1));
cl_entity_set_drop_chance(zombie, CL_EQUIP_HEAD, 1.0f);
cl_item_stack head = cl_entity_equipment(zombie, CL_EQUIP_HEAD);  /* owned: release it */
cl_stack_release(head);

clight::on<clight::ev::EntitySpawn>([](cl_ev_entity_spawn& e) { cl_event_cancel(&e.header); });  // filter by type in the opts

cl_particle_spawn s = CL_PARTICLE_SPAWN_INIT;
s.pos = cl_vec3{0, 2, 0};  // an offset from the feet
cl_emitter em;
cl_render_emitter_add(zombie, CL_STR("minecraft:flame"), CL_STR(""), &s, 2, &em);

player.interact_entity (right-click on an entity, cancellable) and entity.change_dimension (from, to) work the same way. Details: Entities, Particles.

Try it

Give a function size_t rally(clight::Level level, clight::Entity boss) that gives every monster within 12 blocks of the boss (but not the boss) Resistance I for 5 seconds and returns how many there were.

Show a solution
size_t rally(clight::Level level, clight::Entity boss) {
    const cl_vec3 p = boss.position().value_or(cl_vec3{});
    cl_entity_query q = CL_ENTITY_QUERY_INIT;
    q.category = CL_STR("monster");
    q.exclude = boss.raw();
    auto mobs = level.entities_in_box({p.x - 12, p.y - 6, p.z - 12}, {p.x + 12, p.y + 6, p.z + 12}, &q);
    if (!mobs) return 0;
    for (clight::Entity m : *mobs) m.add_effect("minecraft:resistance", 100, nullptr);
    return mobs->size();
}

Recap: Level::entities_in_box, nearest_player and entity_by_uuid find entities; attribute, add_attribute_modifier, add_effect change them; set_synced_* tells clients; hurt damages; cl_damage_type_register and cl_spawn_rule_register add damage types and natural spawning; set_passenger makes them ride. Guide: Entity Gameplay.