Skip to content

Fixes bundle 3 + new things#4212

Merged
Henrybk merged 7 commits into
masterfrom
FixBundle3
Jul 4, 2026
Merged

Fixes bundle 3 + new things#4212
Henrybk merged 7 commits into
masterfrom
FixBundle3

Conversation

@Henrybk

@Henrybk Henrybk commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR is a follow-up fixes bundle for the previous routing, attack, eventMacro, teleport, and automation updates.

It now includes a broader set of stability and correctness fixes around:

  • portal recording and portal coordinate updates;
  • cast-aware config conditions;
  • teleport fallback behavior when skill teleport is unavailable;
  • attack target switching and target filtering;
  • slave predictive attack waiting;
  • route/debug output improvements;
  • eventMacro hook lifecycle cleanup;
  • UI/hook memory-safety cleanup;
  • logging overhead reduction;
  • corrupted portalsLOS.txt recovery;
  • safer socket/resource cleanup in XS/C++ code;
  • additional unit tests.

Main changes

Portal recording and portal coordinate updates

Adds:

portalUpdatePosition 1

When enabled, OpenKore can update existing portal coordinates in portals.txt instead of blindly appending duplicate portal records.

This helps when a known portal is slightly wrong, for example:

prontera 100 100 izlude 50 50

but the real observed transition is:

prontera 101 100 izlude 51 50

Instead of appending a second near-duplicate line, OpenKore can replace the old canonical entry.

New/updated helpers:

_tryUpdateKnownPortalPositions
_tryUpdateNearbyPortalRecordSibling
_findNearbyPortalRecordSibling
recompilePortals
replacePortalLUT

replacePortalLUT can:

  • replace old portal records;
  • avoid duplicate appends;
  • preserve comments and blank lines;
  • preserve trailing portal step data when appropriate;
  • return whether the file changed, was already canonical, or failed to update.

updatePortalLUT and updatePortalLUT2 now use replacePortalLUT instead of direct file append.


Portal update candidate tracking

Task::MapRoute::mapChanged now stores a portal update candidate when a route uses a known simple portal:

$ai_v{portalUpdatePosition_candidate} = {
    oldSourceMap => ...,
    oldSourceX   => ...,
    oldSourceY   => ...,
    oldDestMap   => ...,
    oldDestX     => ...,
    oldDestY     => ...,
    time         => time,
};

After the map change, processPortalRecording compares the expected transition against the real arrival and updates portals.txt if needed.

Nearby sibling correction is also supported with conservative drift thresholds:

source drift <= 2 cells
destination drift <= 6 cells

Corrupted portalsLOS.txt recovery

Adds startup validation for portalsLOS.txt.

If OpenKore detects malformed LOS entries, such as:

  • too few tokens;
  • invalid source coordinates;
  • invalid destination coordinates;
  • invalid LOS distance;
  • destination tuple count not divisible by 4;

it removes the corrupted file and forces a clean portal LOS rebuild.

This prevents route compilation from reusing broken portal LOS data.


Cast-aware condition checks

Adds new condition checks for self/player/monster config blocks.

Self conditions:

notWhileBeingCasted
whileBeingCasted
whenNoNearPartyMemberCasting
whenNearPartyMemberCasting

Player/monster target conditions:

target_notWhileBeingCasted
target_whileBeingCasted

New helpers:

actorIsBeingCastedOn
nearPartyMemberIsCasting
castMatchesAnySkill

These allow configs to detect whether a specific skill is already being cast on an actor, or whether a visible party member is currently casting a specific skill.

Skill matching now supports:

  • skill handle;
  • skill display name;
  • numeric skill ID;
  • Skill->new(auto => ...) resolution.

Example:

partySkill Assumptio {
    lvl 5
    target
    target_hp < 95%
    target_notWhileBeingCasted HP_ASSUMPTIO
    # [checkSelfCondition]
    # [checkPlayerCondition]
}

Example:

attackSkillSlot Decrease Agility {
    lvl 10
    target_notWhileBeingCasted MER_DECAGI
    # [checkSelfCondition]
    # [checkMonsterCondition]
}

Example:

useSelf_skill Magnificat {
    lvl 5
    whenNoNearPartyMemberCasting PR_MAGNIFICAT
    # [checkSelfCondition]
}

eCast self cast-blocking status support

eCast now hooks checkSelfCondition and blocks skill usage when self has statuses that prevent casting.

Examples of blocked statuses include:

EFST_HANDICAPSTATE_DEEPSILENCE
HEALTHSTATE_SILENCE
EFST_HEALTHSTATE_SILENCE
EFST_BODYSTATE_STUN
EFST_BODYSTATE_FREEZING
EFST_BODYSTATE_STONECURSE
EFST_HANDICAPSTATE_LIGHTNINGSTRIKE
EFST_HANDICAPSTATE_CRYSTALLIZATION
EFST_BODYSTATE_SLEEP

This prevents attackSkillSlot, attackComboSlot, useSelf_skill, partySkill, and monsterSkill from attempting casts while the character is unable to cast.


Attack target switching improvements

attackChangeTarget can now switch not only from a passive target to an aggressive target, but also from a lower-priority aggressive target to a higher-priority aggressive target.

New logic compares:

Misc::monsterPriority($target->{name}, $target->{nameID})
Misc::monsterPriority($new_target->{name}, $new_target->{nameID})

This makes priority.txt more meaningful during active combat.

Default priority.txt now includes:

all

Example:

Raydric
Mimic
all

With attackChangeTarget 1, the bot can now prefer a higher-priority aggressive target when one appears.


Target selection safety

getBestTarget now skips monsters that recently failed due to:

attack_failed
attack_failedLOS

through the new helper:

_targetRecentlyFailedAttack

It also skips targets whose distance/path exceeds:

attackRouteMaxPathDistance

This prevents the attack AI from repeatedly selecting targets that are too far, recently unreachable, or recently failed LOS/path checks.


Slave attack predictive wait fix

AI::SlaveAttack now bounds predictive waiting.

If a slave cannot attack right now but prediction says the target will soon enter range/LOS, it waits only up to:

ai_attack_allowed_waitForTarget * 3

If that wait times out, predictive waiting is disabled until the slave hits the target again.

This prevents slaves from getting stuck forever waiting for a future attack window that never actually happens.


Teleport fallback and skill availability fixes

Teleport skill checks now account for:

  • muted state;
  • silence status;
  • insufficient SP;
  • map-level teleport restrictions;
  • item fallback availability.

New shared helpers:

hasEnoughSPForTeleportSkill
isTeleportSkillSuppressedByStatus
_canUseTeleportSkillAtLevel
_isTeleportSkillSuppressedByStatus

Random teleport now requires enough SP for level 1 Teleport.

Respawn teleport now requires enough SP for level 2 Teleport.

If skill teleport is unavailable but a valid item exists, OpenKore can still use the item fallback.

Example behavior:

  • low SP + Fly Wing: random teleport still allowed through item;
  • low SP + no item: random teleport rejected;
  • muted/silenced + Fly Wing/Butterfly Wing: item teleport still allowed;
  • muted/silenced + no item: skill teleport rejected.

Route calculation and route output

Task::CalcMapRoute::getRouteString now includes coordinates and walk cost.

Old format:

payon -> pay_arche -> pay_dun00

New format:

payon (228,329) [walk 30] -> pay_arche (36,131) [walk 55] -> pay_dun00 (21,183)

This improves debugging for route decisions, shop lookup routes, warp-item routes, and portal route choices.

searchStep now logs route expansion with a step counter and openlist size, making route debugging easier.

Route weights now include:

ZENY 0.1
TICKET 100

This makes zeny and ticket costs explicit in route scoring.


MapRoute and Route portal handling

Task::MapRoute now marks portal route subtasks with:

isPortalRoute => 1

Task::Route now accepts isPortalRoute as route metadata.

Missing portal detection is slightly more tolerant:

blockDistance(...) <= 1

instead of requiring exact position match.

Occupied destination handling is also less brittle. If the destination cell is occupied and the actor is already adjacent to it, the route can finish one cell away instead of failing or trying to step into the occupied cell.


Auto-sell handling fix

processAutoSell now uses the global @sellList directly instead of a local @sellItems.

This matches sell_result, which reads @sellList.

sell_result now:

  • reports the correct item count;
  • avoids printing misleading “Sold 0 items” messages;
  • finds the queued sellAuto action by index instead of assuming it is the current AI action.

Network receive fixes

Skill delay statuses now use stable skill handles:

AL_HEAL_DELAY
PR_MAGNIFICAT_DELAY
HP_ASSUMPTIO_DELAY

instead of localized skill names plus “Delay”.

skill_cast now stores:

targetID => $targetID

inside the actor casting state. This is required for the new cast-aware condition checks.

Self job changes now call:

Plugins::callHook('job_changed', {
    old_job => $old_job,
    new_job => $value1,
});

Other player job-change logging remains unchanged.


EventMacro hook lifecycle cleanup

eventMacro::Core now uses weak references for callbacks that capture $self.

This helps avoid reference cycles caused by plugin hooks and log hooks keeping the eventMacro core object alive after reload/unload.

New helper:

_weak_self_sub

Updated areas include:

  • AI_state_change hook;
  • log hook callback;
  • cycle-stage automacro hooks;
  • dynamic event hook callbacks;
  • macro iteration hook.

Unload/cleanup now also deletes stored hook handles and clears hook hashes after unregistering.

Several noisy debug messages were moved from level 2 to level 3.


Tk, Inventory, and XKore2 hook cleanup

Several long-lived objects now use weak hook callbacks and clean up hooks in DESTROY.

Updated components:

src/Interface/Tk.pm
src/InventoryList/Inventory.pm
src/Network/XKore2/MapServer.pm

This reduces the risk of stale hooks keeping UI/network/inventory objects alive after reloads or reconnections.


Logging overhead reduction

Log::processMsg now only calls caller() when hooks exist.

Before, caller information was computed for every log message even when no log hooks needed it.

Log level handling was centralized into:

setLevel

This applies consistent squelchDomains, debugDomains, and default-level behavior to:

message
warning
error
debug

Interface title throttling

Interface title updates are now throttled through:

setTitle 0.2

The title is only updated when the timeout allows it, reducing UI overhead from setting the same title repeatedly every main loop.


Safer dataWaiting

Utils::dataWaiting now safely returns false for:

  • missing handle references;
  • undefined handles;
  • closed sockets;
  • non-handle objects;
  • invalid file descriptors;
  • select() failures.

This prevents runtime errors when socket/file handles become invalid.


XSTools / XS / C++ cleanup

This PR includes several low-level safety fixes.

BufferedOutputStream:

  • avoids throwing from destructor;
  • safely flushes/closes using local old stream/buffer pointers;
  • cleans up references and buffers even when exceptions occur;
  • fixes buffer deletion to use delete[].

Unix and Win32 sockets:

  • initialize in and out to NULL;
  • use a shared construct path;
  • clean up partially constructed streams on exception;
  • avoid dereferencing null streams in destructors;
  • close sockets only if valid.

Win32 socket output close:

shutdown(fd, SD_SEND)

instead of SD_RECEIVE.

Unix/Win32 server sockets:

  • remove unnecessary strdup/free;
  • use inet_addr(address) directly.

PathFinding.xs:

  • validates secondWeightMap before CalcPath_init;
  • initializes pathfinding only after validating custom-weight input;
  • applies custom second-weight map after initialization.

NPC shop table cleanup

tables/npc_shops.txt was updated to normalize and improve several shop entries.

Examples include standardizing tool-shop style entries with expected common items such as:

501
502
503
504
506
601
602
610
611
645
656
657
713
717
1771
23280
23288

This improves searchshop and closest-shop routing quality.


New/updated tests

New tests:

src/test/CastConditionsTest.pm
src/test/TeleportFallbackTest.pm
src/test/Utils/DataWaitingTest.pm

Updated test registration:

src/test/unittests.pl

New test coverage includes:

  • cast-aware self/player/monster conditions;
  • party member casting checks;
  • skill matching by handle/name/ID;
  • random teleport fallback to item when SP is too low;
  • respawn teleport fallback to item when SP is too low;
  • teleport skill rejection while muted or silenced;
  • canUseTeleport behavior with skill-only vs item fallback;
  • dataWaiting behavior with undefined, closed, or invalid handles.

Suggested test command:

perl src/test/unittests.pl

Example configs

Prevent duplicate Assumptio casts

partySkill Assumptio {
    lvl 5
    target
    target_hp < 95%
    target_notWhileBeingCasted HP_ASSUMPTIO
    # [checkSelfCondition]
    # [checkPlayerCondition]
}

Prevent duplicate Magnificat casts in party

useSelf_skill Magnificat {
    lvl 5
    sp > 40%
    whenNoNearPartyMemberCasting PR_MAGNIFICAT
    # [checkSelfCondition]
}

Avoid duplicate monster debuff casts

attackSkillSlot Decrease Agility {
    lvl 10
    target_notWhileBeingCasted MER_DECAGI
    # [checkSelfCondition]
    # [checkMonsterCondition]
}

Portal coordinate updates

portalCompile 1
portalRecord 2
portalRecord_recompileAfter 1
portalUpdatePosition 1

Attack target switching by priority

attackChangeTarget 1
attackAuto 2

Example priority.txt:

Raydric
Mimic
all

Manual test notes

Portal update behavior should be tested by routing through a known portal and confirming that slightly different observed coordinates update the old portals.txt line instead of appending duplicates.

Cast-aware conditions should be tested with self casts, party target casts, monster target casts, and nearby party members casting the same skill.

Teleport fallback should be tested with low SP, muted status, silence status, Fly Wings, Butterfly Wings, and skill-only teleport setups.

Attack target switching should be tested with attackChangeTarget 1, an already aggressive low-priority target, and a higher-priority aggressive monster entering range.

Route output should be checked anywhere getRouteString is displayed, especially searchshop and map-route debug output.

EventMacro reload/unload behavior should be tested to ensure hooks are removed cleanly and automacros continue to trigger normally.


Compatibility notes

  • portalUpdatePosition defaults to 1.
  • Portal recording now updates/canonicalizes existing lines instead of always appending.
  • New cast conditions can use skill handles, names, or numeric IDs, but handles are preferred.
  • Skill delay statuses now use <SKILL_HANDLE>_DELAY.
  • canUseTeleport now rejects skill teleport if the character is muted, silenced, or lacks SP, but still allows valid item fallbacks.
  • priority.txt now contains all, which can affect target switching when attackChangeTarget is enabled.
  • getBestTarget now skips recently failed targets and targets beyond attackRouteMaxPathDistance.
  • Log hooks now receive caller information only when hooks exist.
  • Several hook-owning objects now clean themselves up in DESTROY, which may affect plugins relying on stale hook handles.

Review focus

Please review:

  • replacePortalLUT behavior with comments, blank lines, duplicates, and stepped portals.
  • portalUpdatePosition default behavior.
  • Nearby portal sibling replacement thresholds.
  • Cast matching behavior in castMatchesAnySkill.
  • actorIsBeingCastedOn scanning all visible actor lists.
  • nearPartyMemberIsCasting only considering visible party members.
  • Teleport fallback behavior when skill teleport is unavailable but items exist.
  • getBestTarget filtering after recent failures.
  • Attack target switching to higher-priority aggressive monsters.
  • Slave predictive wait timeout behavior.
  • EventMacro weak hook callback behavior.
  • Tk, Inventory, and XKore2 hook cleanup.
  • dataWaiting behavior on invalid handles.
  • XS socket and buffered stream cleanup changes.

Changed file groups

Config and tables

control/config.txt
control/priority.txt
control/routeweights.txt
control/timeouts.txt
tables/npc_shops.txt

Plugins

plugins/avoidObstacles/avoidObstacles.pl
plugins/eCast/eCast.pl
plugins/eventMacro/eventMacro/Core.pm
plugins/eventMacro/eventMacro/FileParser.pm

Core Perl

src/AI/Attack.pm
src/AI/CoreLogic.pm
src/AI/SlaveAttack.pm
src/Actor.pm
src/Actor/You.pm
src/FileParsers.pm
src/functions.pl
src/Interface/Tk.pm
src/InventoryList/Inventory.pm
src/Log.pm
src/Misc.pm
src/Network/Receive.pm
src/Network/XKore2/MapServer.pm
src/Task/CalcMapRoute.pm
src/Task/MapRoute.pm
src/Task/Route.pm
src/Task/Teleport.pm
src/Task/Teleport/Random.pm
src/Task/Teleport/Respawn.pm
src/Utils.pm

XS / C++

src/auto/XSTools/OSL/IO/BufferedOutputStream.cpp
src/auto/XSTools/OSL/Net/Unix/ServerSocket.cpp
src/auto/XSTools/OSL/Net/Unix/Socket.cpp
src/auto/XSTools/OSL/Net/Win32/ServerSocket.cpp
src/auto/XSTools/OSL/Net/Win32/Socket.cpp
src/auto/XSTools/OSL/Net/Win32/Socket.h
src/auto/XSTools/OSL/Threading/Unix/Thread.cpp
src/auto/XSTools/PathFinding/PathFinding.xs
src/auto/XSTools/Translation/translator.cpp
src/auto/XSTools/Translation/winfilereader.cpp
src/auto/XSTools/utils/perl/Benchmark.xs
src/auto/XSTools/utils/unix/http-reader.cpp
src/auto/XSTools/utils/win32/http-reader.cpp

Tests

src/test/CastConditionsTest.pm
src/test/TeleportFallbackTest.pm
src/test/Utils/DataWaitingTest.pm
src/test/Distfiles
src/test/unittests.pl

Short changelog

  • Added portalUpdatePosition.
  • Added portal record replacement/canonicalization with replacePortalLUT.
  • Added corrupted portalsLOS.txt detection and rebuild.
  • Added cast-aware self/player/monster conditions.
  • Added actorIsBeingCastedOn, nearPartyMemberIsCasting, and castMatchesAnySkill.
  • Added eCast self cast-blocking status checks.
  • Improved attackChangeTarget with higher-priority aggressive target switching.
  • Moved recent failed-target filtering into getBestTarget.
  • Added attackRouteMaxPathDistance filtering in target selection.
  • Added bounded slave predictive attack waiting.
  • Added teleport skill SP/status checks with item fallback.
  • Added handle-based skill delay statuses.
  • Added self job_changed hook.
  • Fixed autosell result/list handling.
  • Improved route string output with coordinates and walk cost.
  • Added isPortalRoute.
  • Improved missing portal and occupied destination handling.
  • Added route weights for zeny and tickets.
  • Added weak hook cleanup for eventMacro, Tk, Inventory, and XKore2 map server.
  • Reduced logging overhead when no hooks are registered.
  • Throttled interface title updates.
  • Hardened dataWaiting.
  • Hardened XS/C++ socket, stream, and pathfinding resource handling.
  • Added cast condition, teleport fallback, and dataWaiting tests.

Henrybk referenced this pull request May 19, 2026
* Added missing keys to config

* bundle

* Update config.txt

* Update Misc.pm

* pot

* Update config.txt
@Henrybk Henrybk merged commit 2bb391e into master Jul 4, 2026
9 checks passed
@Henrybk Henrybk deleted the FixBundle3 branch July 4, 2026 15:01
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.

2 participants