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.