Skip to content

feat(teleport_items): add table-driven warp routing with strict parser and runtime equip/cooldown checks#4167

Merged
Henrybk merged 23 commits intoOpenKore:masterfrom
boscv:parseTeleportItems
Mar 20, 2026
Merged

feat(teleport_items): add table-driven warp routing with strict parser and runtime equip/cooldown checks#4167
Henrybk merged 23 commits intoOpenKore:masterfrom
boscv:parseTeleportItems

Conversation

@boscv
Copy link
Contributor

@boscv boscv commented Mar 10, 2026

Motivation

  • Provide a data-driven way to describe teleport/warp item behavior and destinations through tables/teleport_items.txt.
  • Support item-level constraints (equipment requirements, level range, cooldown) so route planning and execution reflect real in-game usage conditions.
  • Allow map routing to consider item-based warps when route_warpByItem is enabled.

Description

  • Added tables/teleport_items.txt with documented syntax and examples for random, respawn, warp, and any modes.
  • Implemented and hardened parseTeleportItems in src/FileParsers.pm:
    • strict positional optional syntax: [maxLvl] [timeoutSec] [requiredEquipSlot requiredEquipItemID]
    • descriptive warnings for malformed lines
    • numeric field validation
    • equipment slot validation against %equipSlot_rlut (case-insensitive handling for slot names)
  • Integrated table loading in startup flow via src/functions.pl.
  • Extended route planning in src/Task/CalcMapRoute.pm:
    • warp-item candidate discovery for target map
    • propagation of teleport-item metadata (teleportItemID, timeoutSec, required equip slot/item) into map solution steps
  • Updated route execution in src/Task/MapRoute.pm:
    • runtime revalidation of equipment requirement before sendItemUse
    • cooldown-aware item usage checks using last_teleport_item_use
  • Updated teleport item selection fallback:
    • src/Task/Teleport/Random.pm and src/Task/Teleport/Respawn.pm now consult table rules
    • src/Task/Teleport.pm records cooldown timestamps when a rule-based item is used
  • Added/updated parser tests and fixtures:
    • src/test/teleport_items.txt (valid cases)
    • src/test/teleport_items_invalid.txt (invalid/malformed cases)
    • src/test/FileParsersTest.pm assertions for both valid and invalid scenarios
    • src/test/Distfiles updated to include new fixture

Testing

  • Ran parser unit tests:
    • perl -I src src/test/FileParsersTest.pm
  • Verified parsing behavior for:
    • valid entries (including maxLevel, timeoutSec, equip requirements)
    • invalid entries (non-numeric fields, invalid slot name, malformed optional token layouts), ensuring invalid lines are ignored and valid control lines are preserved
  • Performed route-candidate simulations confirming expected selection behavior for warp items by target map, cooldown, level constraints, and equip requirements:
    • prt_q -> 22849
    • pvp_n_room -> 14528
    • un_bk_q -> 22691
    • verus04 -> 22611 only when equip requirement is satisfied
    • cooldown-gated suppression confirmed for 22508 (moc_para01)

boscv added 4 commits March 9, 2026 16:06
Introduce support for a teleport_items table and use teleport/warp items in routing and teleport tasks. Adds tables/teleport_items.txt and a parseTeleportItems loader with a new %teleport_items global, plus unit tests. Implements Misc::getTeleportItemFromTable and integrates warp-by-item logic into Task::CalcMapRoute and Task::MapRoute (populateOpenListWithWarpByItems, candidate selection, per-map forbids and retry handling). Tracks per-item cooldowns (last_teleport_item_use) when sending item-use packets and exposes a config flag route_warpByItem (default 0) in control/config.txt. Also registers the new table in settings and updates test distfiles.
Parse optional equip-requirement fields for teleport items and enforce them when selecting items. FileParsers.pm: accept optional timeoutSec and optional requiredEquipSlot + requiredEquipItemID, validate and store them on each entry (timeout defaults to 0). Misc.pm: add isTeleportItemEquipRequirementSatisfied to verify required slot exists and the required item is equipped in that slot. Use this check in getTeleportItemFromTable and Task/CalcMapRoute.pm when filtering candidate warp items. Tests and fixtures: add teleport_items test fixture and assertions in FileParsersTest, and update tables/teleport_items.txt docs/examples to document the new optional fields.
Parse and enforce an optional max level for teleport/warp items. FileParsers now accepts an extra numeric optional argument (maxLvl) before timeoutSec and stores maxLevel in the entry. Misc and CalcMapRoute skip teleport entries when the character level is above maxLevel. Tests and teleport_items table/docs updated to reflect new syntax and example entries; test fixture updated to assert parsing of maxLevel. This enables items to be limited to characters at or below a specified level (0 disables the check).
Make teleport_items parsing stricter and add equip-requirement support. FileParsers.pm: use Globals equip slot lookup, adopt strict positional optional syntax ([maxLvl] [timeoutSec] [requiredEquipSlot requiredEquipItemID]), validate numeric fields and equip slot names, emit warnings for malformed lines, and skip invalid entries. CalcMapRoute.pm: carry teleportItemRequiredEquipSlot/ItemID through open/close lists. MapRoute.pm: import isTeleportItemEquipRequirementSatisfied and refuse to use teleport items when equip requirement is not satisfied. Tests/fixtures: update teleport_items.txt, add teleport_items_invalid.txt, and adjust FileParsersTest expectations to cover new parsing/validation behavior. tables/teleport_items.txt: document positional optional values and note how to specify only timeout by using maxLvl=0 first.
@boscv
Copy link
Contributor Author

boscv commented Mar 10, 2026

Still need some real testing, but pulling here for any suggestions

boscv added 4 commits March 10, 2026 00:28
Add isTeleportItemEquipRequirementSatisfied to Misc exports, switch MapRoute to call it as Misc::isTeleportItemEquipRequirementSatisfied (remove from import list), and clean up/reorder teleport_items.txt entries and formatting. These changes expose the equip-check function for external use and tidy the teleport item table.
Detect when a Task::Route error (CANNOT_CALCULATE_ROUTE or STUCK) is caused by a same-map warp that changed the map. If the map was changed and the first mapSolution entry refers to the same map (map == dest_map), treat the route as stale: advance to the next portal step (shift mapSolution), clear mapChanged and teleport-related flags (teleport, sentTeleport, teleportTime), and return. Adds a debug log for this case to avoid re-calculating a route invalidated by a same-map warp.
Add _isSameMapPortalStep helper to robustly detect same-map portal steps (prefer map==dest_map, fall back to parsing portal strings). Use this in Task::MapRoute to select the first inter-map portal, mark Route subtasks with stopWhenMapChanged for same-map starts, and advance mapSolution entries when a same-map warp finishes. Update Task::Route to honor stopWhenMapChanged by finishing the current segment on map change instead of recalculating the route. Include a Python runtime simulation test (maproute_same_map_runtime_sim.py) that verifies detection and expected step progression for a moc_para0b -> moc_para0b -> moc_para0b -> prontera -> payon sequence.
@boscv
Copy link
Contributor Author

boscv commented Mar 10, 2026

For some reason, intra-map portals where having calc erros on mapChange (?).
Don't know if it's from the last pull requests i did handling route retries..
Just randomly stumbled onto it doing some route tests using the new teleport_items table.
ANYWAY.. Seems to be fixed!

@boscv boscv marked this pull request as ready for review March 10, 2026 19:20
@Henrybk
Copy link
Contributor

Henrybk commented Mar 10, 2026

ow cool, I'll give it a try

@Henrybk
Copy link
Contributor

Henrybk commented Mar 17, 2026

Found a bug.
Say I am in prontera and I have sp_cor teleport wing (ID 100903) if I type move sp_cor it works, kore uses the wing > GREAT
Say I am in sp_cor and I have a prontera badge (22847) if I type move prontera it works > GREAT
Say I am in sp_cor and I have a prontera badge (22847) if I type move payon it fails > BAD

Input: move payon
Calculating route to: Payon Town(payon)
You on route to: Payon Town(payon): ,
CalcMapRoute - initialized with '0' options.
CalcMapRoute failed.
Cannot calculate a route from sp_cor (152,158) to payon

But If I am in sp_cor and I have a butterfly wing (602) with savemap saved to prontera and I type move payon it works> GREAT, boa teleports with 602 to prontera and goes from there.

It seems this version is not adding children whose parents were added by teleportItems

@boscv
Copy link
Contributor Author

boscv commented Mar 17, 2026

nice! couldn't set the server for testing yet, thanks for lending your time running them.
i'll patch it.

Replace target-scoped warp-item selection with a general candidate enumerator and explicit destination validation. getWarpItemCandidatesForTarget was renamed to getWarpItemCandidates and no longer requires a target; it checks inventory readiness and filters entries via the new isWarpItemRoutingDestinationValid helper (rejecting empty, '*', 'any', 'save' destinations). populateOpenListWithWarpByItems now iterates all candidates, skips warps to the same node, and uses the centralized validation. This simplifies routing logic and prevents invalid or no-op warp entries from being considered.
@Henrybk
Copy link
Contributor

Henrybk commented Mar 17, 2026

What do you think about adding a table file that restricts item teleports in a few obsviously prohibited maps? We could get that from https://github.com/rathena/rathena/tree/master/npc/mapflag

@Henrybk
Copy link
Contributor

Henrybk commented Mar 17, 2026

Input: move payon
Calculating route to: Payon Town(payon)
You on route to: Payon Town(payon): ,
CalcMapRoute - initialized with '2' options.
[CalcMapRoute - searchStep - Loop] sp_cor 152 158=moc_para01 171 115, 80
[CalcMapRoute - searchStep - Loop] sp_cor 152 158=prontera 159 192, 80
[CalcMapRoute - searchStep - Loop] prontera 159 192=sp_cor 152 158, 160
[CalcMapRoute - searchStep - Loop] prontera 159 192=moc_para01 171 115, 160
[CalcMapRoute - searchStep - Loop] moc_para01 171 115=sp_cor 152 158, 160
[CalcMapRoute - searchStep - Loop] moc_para01 171 115=prontera 159 192, 160
CalcMapRoute failed.
Cannot calculate a route from sp_cor (152,158) to payon
AI:  | 1

@boscv boscv marked this pull request as draft March 17, 2026 20:11
@Henrybk
Copy link
Contributor

Henrybk commented Mar 17, 2026

Should be working now

Map Solution Ready for traversal.
sp_cor -> prontera -> payon
MapRoute - Using teleport item 22847 (1th time)
Sent packet    : 0439    [ 8 bytes]  [Item Use]
Item Use: 17
<< Received packet:      01C8 - Inventory Used [15 bytes]
Received packet: 01C8 Handler: item_used
You used Item: Prontera Badge (13) x 1 - 7 left
Inventory Item Removed: Prontera Badge (13) x 1
<< Received packet:      00B0 - Your Status Info [ 8 bytes]
Received packet: 00B0 Handler: stat_info
Stat: 24 => 16913
<< Received packet:      0196 - Actor Effect (Skill, Weight, ...) [ 9 bytes]
Received packet: 0196 Handler: actor_status_active
You are no longer: Sitting
<< Received packet:      08C8 - Actor Item take / attack damage / sit / stand [34 bytes]
Received packet: 08C8 Handler: actor_action
You are standing.
<< Received packet:      0196 - Actor Effect (Skill, Weight, ...) [ 9 bytes]
Received packet: 0196 Handler: actor_status_active
<< Received packet:      0091 - Map Changed [22 bytes]
Received packet: 0091 Handler: map_change
Map Change: prontera.gat (159, 192)
You AI suspended by clientSuspend for 1 seconds
Client network buffer flushed out
Received packet: 007D Handler: map_loaded
Map loaded

@Henrybk
Copy link
Contributor

Henrybk commented Mar 17, 2026

Items without the need to equip and without timeout are working well.
Items with timeout are working but there needs to be a few more checks, my bot was trying to use the eden mark while sitting down so it failed

  • Make bot stand up before sending use item
  • Only set the item as used when we receive confirmation it was used (don't fill $char->{last_teleport_item_use} if it failed)
  • Add the timer to the item when we receive Received packet: 02C1 Handler: npc_chat - Item Failed. [Eden Group Mark] is cooling down. Wait 16.5 minutes.
  • Make bot check if has item and can equip item in calcmaproute
  • Make bot if has item, can equip item in maproute, and then actually equip item before using

In this example the first fails happen bc we are sitting, the later ones because of timeout
c0378d21a4fd1e231b5fc0f0c5348200

@Henrybk
Copy link
Contributor

Henrybk commented Mar 17, 2026

Also, isTeleportItemEquipRequirementSatisfied only checks if you have the requirement to use the item, it won't actually equip said item to teleport

@alisonrag
Copy link
Contributor

there is a error on teleport_items parse, can u check it?
https://github.com/OpenKore/openkore/actions/runs/23220268491/job/67491114889?pr=4167

boscv added 5 commits March 18, 2026 13:42
Add robust handling for teleport items: Misc::canUseTeleport now checks item equip requirements and active cooldowns before allowing use. Task::Teleport gains hooks for item-use ACK and NPC chat, tracks pending teleport item uses, and parses NPC messages to set item cooldown timeouts. New helper methods (canEquipTeleportItem, equipTeleportItem, isTeleportItemEquipRequirementSatisfied, isTeleportItemOnCooldown, onItemUseAck, onNpcChat) manage equip logic, prevent spamming items on cooldown, and update last_teleport_item_use state. Also adjust iterate flow to equip items when required and bail/retry appropriately; import warning log level for cooldown notices.
Add comprehensive teleport-item state management and routing checks.

- Misc.pm: add helpers to register/clear pending teleport-item use, mark usage, set cooldown from remaining seconds, check/try equipping required items, and compute item timeout.
- Network/Receive.pm: parse NPC cooldown messages to set item cooldowns, mark/clear pending uses on item_used, and clear pending uses on map load/change.
- Task/CalcMapRoute.pm: filter warp candidates by whether equip requirements can be satisfied, skip self-destinations, and add destination validation helper.
- Task/MapRoute.pm: ensure required equip state before using teleport items (try equipping or stand up first), register pending use when sending item, and avoid using expired items.
- Task/Teleport.pm: register pending use when initiating teleport item use.
- test/teleport_items.txt: remove an invalid trailing-argument test entry.

These changes improve handling of teleport items across equip requirements, pending-use tracking, and cooldown synchronization.
Multiple fixes across modules:

- src/Commands.pm: Correct string comparison for guild master check (use ne instead of negated eq) to properly validate guildmaster.
- src/FileParsers.pm: Initialize teleport item list, normalize required equip slot to lowercase, use a lowercase lookup for equip slots, and ensure entries are pushed into the list. These changes make teleport item parsing robust and case-insensitive.
- src/InventoryList.pm: Harden DESTROY to avoid exceptions during teardown by checking hook types and wrapping hook removal, clear, and SUPER::DESTROY calls in eval blocks.
- src/Task/CalcMapRoute.pm: Improve warp-to-save-map handling by short-circuiting when there are no warp candidates, renaming variables for clarity, and using return instead of next to avoid unintended control-flow.

Overall these changes fix bugs and improve stability during parsing, cleanup, and routing tasks.
Replace key-based iteration of %teleport_items with iteration over teleport_items{list} and add validation checks. compilePortals now skips entries that aren't HASH refs. getTeleportItemFromTable and getWarpItemCandidates now verify teleport_items{list} is present/non-empty and iterate @{$teleport_items{list}} instead of keys %teleport_items, simplifying entry access and avoiding errors from non-hash or missing entries.
Normalize equip slot names and improve warp-item handling across route calculation and map routing tasks.

- Add _normalizeEquipSlotName in Misc.pm and use it when checking/equipping teleport-item requirements to tolerate case/alias differences in slot names.
- Harden getWarpItemCandidates (CalcMapRoute.pm): validate teleport item entries, skip configured noWarpItemIDs, compute elapsed cooldown and emit a single warning per item while suppressing repeated messages, and avoid candidates still under cooldown.
- Add noWarpItemIDs tracking to Task::CalcMapRoute and Task::MapRoute, propagate it into the map calculator, and mark specific itemIDs as unavailable when a warp item can't be used (to force recalculation). Also include noWarpItemIDs in prunePerMapBlocks so entries are pruned.
- Small cleanup: use elapsed/remaining calculation for cooldown logic and reset substage/timeouts when a warp item becomes unusable.

These changes prevent case-sensitive equip slot bugs, reduce spammy cooldown warnings, and avoid repeatedly attempting to use warp items that are temporarily unavailable.
boscv added 4 commits March 19, 2026 14:31
Simplify and harden teleport_items handling: parseTeleportItems now stores entries only in a list (no per-destination keyed structure), preserves requiredEquipSlot casing from table, validates equip slots case-insensitively, and warns+defaults on unrecognized modes. Moved portal population to iterate teleport_items{list} in compilePortals. Extracted and reused equip-requirement logic (_getTeleportItemEquipRequirementContext, _normalizeEquipSlotName) and added helpers for cooldown and level checks (getTeleportItemCooldownRemainingSec, isTeleportItemEntryWithinLevelRange). Updated getTeleportItemFromTable and CalcMapRoute to use the new helpers and centralize cooldown/level logic. Adjusted tests to reflect the new list-only structure and slot-case preservation.
Make CalcMapRoute more robust and performant: handle missing character/inventory when reading teleport tickets; add suppressDebug option and gate debug output. Replace linear openlist selection with a binary-heap-backed min-heap (push/shift/rebuild) and add automatic heap rebuild heuristics. Introduce canUseTeleportInRouteContext helper. Improve warp-item handling: avoid default chaining of item-warps, add optional route-cost probing and heuristics to prefer beneficial warp items, implement caching for warp-item candidates and warp-route-costs, and warn about cooldown items. Add helper utilities (getSourceRouteCostToTargetNoWarp, getWarpItemRouteCostToTarget, mapHasPortalLOS, getTargetMapsCacheKey, formatting helpers). Add unit smoke tests for openlist heap behavior.
Normalize last_teleport_item_use to a hash ({time, timeout}) and add helper APIs for it.

Added Misc::getTeleportItemCooldownTimeoutSec and Misc::setTeleportItemCooldownEntry, and updated callers in Misc, Task/MapRoute and Task/Teleport to check for hash refs and read/write the time and timeout fields instead of using raw timestamps. This unifies the data shape, prevents type errors, and centralizes cooldown handling (including safe retrieval of timeout values and computing remaining seconds). Also removed preemptive timestamp writes in MapRoute so the entry is set consistently via the helper (e.g. on ack or explicit setter).
@boscv boscv marked this pull request as ready for review March 20, 2026 03:22
@boscv boscv marked this pull request as draft March 20, 2026 03:23
Add a new config option (route_warpByItem_minDistance) and guard warp-by-item usage unless route distance is high enough. Enhance NPC chat parsing to detect teleport item cooldowns with item name and unit (minutes/seconds), set cooldowns accordingly, and show a clearer warning message. In routing, use itemNameSimple and timeConvert, conditionally enable route-cost probing via route_warpItem_routeCostProbe_maxPerTick, and tidy heuristic probing logic. Improve warp-item label formatting and cooldown warnings. Remove a duplicate cooldown warning in Teleport.pm.
@boscv boscv marked this pull request as ready for review March 20, 2026 04:27
@Henrybk Henrybk merged commit 68cabbe into OpenKore:master Mar 20, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants