Fix ECS entity id vs player_id confusion across magic, combat, effects - #2
Closed
barrelin-oss wants to merge 5 commits into
Closed
Fix ECS entity id vs player_id confusion across magic, combat, effects#2barrelin-oss wants to merge 5 commits into
barrelin-oss wants to merge 5 commits into
Conversation
Adds a dedicated experience_update server->client message sent whenever a player gains XP (solo/party NPC kill XP, crusade rewards, login reward delivery). Carries experience_gained, new total experience and level; on level-up also levels_gained, new max_hp/max_mp/max_sp and unspent stat_points. Implemented as an experience_gain callback on player_system (fired from add_experience only when XP actually changes; silent at max level), wired in game_handlers so every add_experience call site is covered. Also fixes pre-existing MSVC build breaks: missing NOMINMAX include order in three bridge translation units and unguarded POSIX time functions (timegm/gmtime_r/localtime_r) in auth_system and a crusade test. Documented in docs/protocol/player.md, docs/JSON_PROTOCOL.md and docs/protocol/items.md; PROGRESS.md updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…y, headless bot client - JSON party messages (invite/accept/leave/update) + handlers and docs - Fix loot gold credited to ECS entity id instead of player_id - npc_registry YAML: parse gold_min/gold_max; npcs.yaml exp/gold keys fixed - Perf: O(1) player lookup in find_aggro_target; sees_all counter gates the far-admin scan in get_players_who_can_see - Case-insensitive .amd loading (ARESDEN/ELVINE were silently skipped), lowercase map names; characters start in their nation town - Registration rate limit configurable (auth.max_registration_attempts) - mapdata configs for default/aresden/elvine (spawners, merchants, initial points validated by tools/bot/scan-map.mjs) - tools/bot: headless bot client (hunt/loot/shop/party), gen-bots, scanner - posix_time_compat shim (pre-existing local build fix, included as-is) WIP checkpoint requested by worktree session relaxed-bell-f49dbe for merge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The modernized magic_type enum was missing six values used by the HBX Magic.cfg data (14, 19, 21, 25, 26, 27), so 15 spells were skipped at load as invalid magic_type - including all high-circle attack magic (Blizzard, Meteor-Strike, Lightning-Strike, Bloody-Shock-Wave). - Add create_dynamic(14), damage_linear(19), damage_area_no_center(21), damage_area_sp_down(25), armor_break(26), ice_linear(27) to the enum - Implement line targeting (find_line_targets): Bresenham trace from caster toward target up to 12 tiles, faction and safe-zone filtered - damage_area_sp_down drains SP from player targets (effect2 dice, parsed into new sp_drain field) - armor_break deals pure damage (ignores_defense now honored via deal_pure_damage) - Cancellation becomes an offensive dispel (debuff category, removes the target effects) instead of hitting the utility stub - Fix 4 placeholder rows in magic.yaml copied from Lightning-Strike in the original cfg: Cancellation type 28, Resurrection 32, Illusion-Movement and Mass-Illusion-Movement 16 - create_dynamic spells (Spike-Field, Ice-Storm, Cloud-Kill) stay skipped with an info log until the dynamic ground-object subsystem exists (tracked in PROGRESS.md) - New registry test covering the legacy types; 2522 tests pass Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
loot_tables.yaml and shops.yaml were authored against a different item numbering than items.yaml - 22 referenced IDs did not exist (375+ validation warnings per boot) and several existing IDs pointed at the wrong item entirely (bosses dropping Tomato/Hoe/Garlic/Carrot as placeholders for Ice/Merien gear; potion shops selling a MagicNecklace; blacksmiths selling Dagger variants labeled ShortSword/MainGauche). Audited every reference against items.yaml using the intent recorded in the line comments: - Remapped 16 references whose intended item exists under another ID (BlackShadowSword 926, The_Devastator 923, BarbarianHammer 928, KlonessAxe 929, StormBringer 924, GiantSword 46, Flameberge+1 55, MagicWand(MS20) 256, KnecklaceOfStoneGolem 647, SapphireRing 336 ...) - Removed 32 pool entries whose intended item does not exist in this item set (AncientTablets, CritCandy, SSS/E.S.W/I.M.C manuals, XelimaCap/Hat/Helm, NecklaceOfXelima, DragonWand MS40, HolyBlade, GiantBattleHammer) plus the vegetable placeholders - Rewrote ~50 stale comments to the real item names (no behavior change) - shops.yaml: ShopKeeper-E/W sell RedPotion/BluePotion/GreenPotion (91/93/95); Gandlf/William sell Dagger/ShortSword/MainGauche (1/8/12) All references now resolve; no in-pool duplicates; 2522 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entity ids from the shared entity_manager are not player ids; casting one
to the other made get_player() return nullptr (or the wrong player) and
silently skipped guarded blocks. Standard fix: get_player_by_entity().
- magic_system: 21 lookup sites (mana/HP/SP costs, silenced/level/stat
checks, range and safe-zone checks, damage/heal scaling, SP drain,
resurrection, debuff resist); AOE/line target finders now push the real
p.ecs_entity instead of fabricating entity{player_id.value, 0}
- application: periodic heal/mana_drain/mana_restore effect ticks never
applied to players
- game_handlers_combat: spell-cast broadcast target resolution; respawn
invulnerability was keyed on a fabricated entity and never matched
- player_system::remove_player: effect cleanup used entity{id.value},
leaking active effects on logout
- wave4 legacy handlers: attack/cast fabricated caster entities from
player_id, so spell knowledge/cooldowns could never match the JSON path
- tests: fixtures now resolve the real ecs_entity (old fabricated form
only passed because fixtures spawn no NPCs, keeping counters aligned)
Legitimate uses kept: admin API player_id from the wire, inventory/trade
entity_id{pid.value} keying (consistent), spatial entity_id{index}.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Full
src/sweep for the recurring bug class where an ECS entity id (from theentity_managershared with NPCs) was cast toplayer_id— or the reverse. The two id spaces are not interchangeable:get_player(player_id{entity.id})returns nullptr (or the wrong player) andif (auto* p = ...)-guarded blocks are silently skipped. Standard fix:player_system::get_player_by_entity(entity)(O(1), const overload available).Fixes
magic_system.cpp(21 sites): mana/HP/SP deduction, silenced/level/stat checks, range checks, safe-zone PvP checks, damage/heal scaling, SP drain, resurrection targets, debuff resist rolls.find_aoe_targets/find_line_targetsno longer fabricateentity{player_id.value, 0}for hit players — they push the realp.ecs_entity(fabricated handles broke downstreamcombat_system::deal_damageand the spell broadcast, which resolve via the real ECS index).application.cpp: periodic heal / mana_drain / mana_restore effect ticks never applied to players.game_handlers_combat.cpp:on_spell_castbroadcast resolved caster/targets with the bad cast; respawn invulnerability was keyed on a fabricated entity and never matched the real defender — the 3s respawn protection was silently inert.player_system::remove_player: effect cleanup usedentity{id.value}instead ofecs_entity, leaking active effects on logout.wave4_handlers.cpp(legacy binary path): attack/cast fabricated caster entities fromctx.player.value; now resolve the player's realecs_entity(their spell-knowledge/cooldown lookups could never match the JSON path's keys).Confirmed legitimate (left untouched)
get_player(player_id{req.player_id})— the wire value is a real player id.entity_id{pid.value}keying — consistent at creation and access.entity_id{ecs_entity.index()}.Tests
test_magic.cpp,test_safe_zone.cpp,test_melee_pve.cppupdated to resolve the realecs_entityinstead of fabricatingentity(pid.value)— the old form only passed because test fixtures spawn no NPCs, so the player-id and ECS-index counters coincided.Documented in
docs/PROGRESS.mdunder Recent Changes.🤖 Generated with Claude Code