Custom movement stack

VersusAI pathing.

A cleaner reference for the current client executor, mainframe routes, sandbox planner, learned route reporting, and planned AutoFarm extensions.

VersusPathing.luaClient movement executor
mainframe.jsAgents, coaching, and run records
sandboxRunner.jsPlanning and viewer routes
sandboxEngine.jsOffline personal-best engine
Normal movement flow

The server plans. The client executes.

The current public client entry point remains PathFramework:MoveTo(target). The client derives a target key, fetches agents, requests a route, follows nodes, handles jump prompts, and reports the result.

  • Custom route planning instead of Roblox PathfindingService.
  • Map snapshots and target keys support route reuse.
  • Run reports feed coaching and personal-best data.
Current high-level flow
MoveTo(target)
  -> derive target key
  -> fetch agents
  -> request sandbox plan
  -> report run start
  -> follow returned nodes
  -> report run finish
  -> save successful recording
28 sections

Quick Start Current

Create the framework once, pass your backend settings, then call MoveTo with a Vector3, CFrame, or table containing position data.

local PathFramework = require(path.To.VersusPathing)

local AI = PathFramework:new({
    BackendUrl = "https://test.versusairlines.top",
    BackendSecret = "YOUR_SECRET",
    GameId = tostring(game.GameId),
    Mode = "live", -- live = mainframe + sandbox, sandbox = sandbox only
    ShowStatusGui = true,
})

AI:MoveTo(Vector3.new(125, 12, -84))
Public method: MoveTo
Client-driven execution, server-driven planning
Supports live HTTP and Studio remotes

What the Client Actually Does Current

The client collects a target key, fetches agents from mainframe, requests a path from sandboxRunner, follows the returned nodes, executes jump prompts where needed, then reports the run back to mainframe.

MoveTo(target)
  -> _deriveTargetKey(...)
  -> _fetchAgents(...)
  -> _requestPlan(...)
  -> _reportRunStart(...)
  -> _followNodes(...)
  -> _reportRunFinish(...)
  -> /path/save-recording (only if successful)
The server decides the path. The client mainly acts as the executor and telemetry sender.

Accepted Target Input Current

tbl_to_v3 lets the client accept several target formats, which makes the public API flexible.

AI:MoveTo(Vector3.new(10, 5, 20))
AI:MoveTo(CFrame.new(10, 5, 20))
AI:MoveTo({ x = 10, y = 5, z = 20 })
AI:MoveTo({ X = 10, Y = 5, Z = 20 })
AI:MoveTo({ key = "spawn_gate", x = 10, y = 5, z = 20 })
Explicit target keys are preferred
Fallback key = quantized goal position

Planned AutoFarm API Planned

Planned target and route options for a future AutoFarm request. The interface is not final yet.

MoveTo({
    IsAutoFarm = true,
    ContinueUntilStop = true,
    AreaName = "BanditCamp",
    RouteKey = "DefaultBanditLoop",
    LoopStartPosition = Vector3.new(0, 5, 0),
    SearchRadius = 120,

    TargetDetectRange = 80,
    AttackRange = 18,
    PreferredRange = 14,
    MinSafeRange = 10,

    Targets = {
        { Id = "bandit_1", Position = Target1.Position, HasHumanoid = true, HasHumanoidRootPart = true },
        { Id = "bandit_2", Position = Target2.Position, HasHumanoid = true, HasHumanoidRootPart = true },
    },

    PrecomputeCount = 4,
})
Planned behaviour: the server solves the first few target legs up front, the client executes them one-by-one, and the next batch is prepared in the background so the player does not have to pause after every kill.
  • IsAutoFarm tells the backend this belongs to a repeatable farming loop, not a one-off player move.
  • ContinueUntilStop keeps the farm area active until the player disables it.
  • AreaName, RouteKey, and LoopStartPosition give the server a stable area anchor instead of tying the loop to a dead mob's last position.
  • Targets should accept mixed target tables and carry extra target metadata such as humanoid checks, health, and IDs where available.
  • PrecomputeCount lets the server solve only the first few legs now, then continue filling the buffer in the background.
  • AttackRange, PreferredRange, and MinSafeRange tell the planner to stop at a better stand-off point instead of pathing directly into the mob.

Planned AutoFarm Client Loop Planned

The client should treat auto-farm as a long-lived area mode with batches rather than one huge path or one fresh solve per kill.

Area farm enabled
  -> request first batch
  -> follow leg for target 1
  -> kill target 1
  -> continue into target 2
  -> continue into target 3
  -> batch exhausted
  -> local scan for more valid targets in the same area
  -> if none found, return to loop anchor
  -> only ask server again when current batch is exhausted and no more valid targets can be found
Batch-based execution
Local refill scan
Loop anchor return
  • Do not ask the server after every kill.
  • Only refresh when the current batch is resolved and the area looks empty.
  • Keep the farm area state separate from the current batch state.
  • Use final target results like killed, missing, despawned, and unreachable so the client can decide when a refresh is really needed.

Viewer + Target Snapshot Plan Planned

Because the client already sends map data, the same sandbox viewer can also render visible farm targets and the chosen attack points. This turns the viewer into a real debugging tool for auto-farm logic.

{
  Id = "bandit_1",
  Name = "Bandit",
  Position = Vector3.new(...),
  Alive = true,
  Health = 100,
  MaxHealth = 100,
  HasHumanoid = true,
  HasHumanoidRootPart = true,
  ModelKey = "BanditModel"
}
Planned viewer upgrades: show target markers, highlight the selected batch, show the chosen stand-off point, and use humanoid checks to separate real mobs from props or decorations.
  • If target positions line up with the uploaded map, the viewer can mark those positions as likely mobs.
  • Humanoid and HumanoidRootPart checks can increase target confidence for auto-farm.
  • The viewer can also render the chosen attack point and the rough attack radius around the mob.

Key Config Options Current

These are the config values that actually shape behaviour in normal use.

BackendUrl               -- base API URL
BackendSecret            -- secret sent in body/header flows
Mode                     -- "live" or "sandbox"
GameId                   -- override for game.GameId
MapRegionPadding         -- map capture padding
MapMaxParts              -- max parts snapshot count
NodeReachRadius          -- proximity required for node completion
NodeTimeoutMin/Max/Scale -- per-node timeout logic
JumpPromptEnabled        -- on-screen jump prompt
JumpWindowSeconds        -- jump retry window
JumpRetryHz              -- retry rate during jump execution
ShowStatusGui            -- lightweight status UI
IdleThinkEnabled         -- idle loop on client

Map Capture and Upload Current

The client builds a collider and hazard snapshot from the world, hashes it, and uses that as the map key. If the server still needs a full map, the client can upload it in chunks.

_getMapHashAndMaybeParts(...)
  -> collectMapParts(...)
  -> hash parts snapshot
  -> send map hash + parts to /ai/sandbox/path/solve

Fallback if server still needs map:
  -> captureExecutorByteMap(...)
  -> /map/upload/init
  -> /map/upload/chunk
  -> /map/upload/commit
Parts snapshot includes colliders
Also includes likely hazards
Chunked upload is preferred

Jump Execution Current

Jumping is safer than the old spammy approach. The client only tries to jump while grounded, retries briefly, and can wait until the humanoid is actually airborne.

_executeJumpInstruction(humanoid, prompt)
  -> show status prompt
  -> only jump while grounded
  -> retry inside JumpWindowSeconds
  -> optionally require airborne confirmation

Action payload examples:
{ type = "jump", nodeIndex = 7, jt = 1, prompt = "Jump" }
{ type = "jump", nodeIndex = 15, jt = 2, prompt = "Clear gap" }
{ type = "jump", nodeIndex = 23, jt = 3, prompt = "Jump over kill brick" }

Client -> Server Routes Used in Normal Flow Current

These are the routes the client script appears to use directly during normal movement.

Mainframe:
POST /ai/path/get-agents
POST /ai/path/report-run-start
POST /ai/path/report-run
POST /ai/path/save-recording

Sandbox:
POST /ai/sandbox/path/solve
POST /ai/sandbox/map/upload/init
POST /ai/sandbox/map/upload/chunk
POST /ai/sandbox/map/upload/commit
POST /ai/sandbox/map/upsert  -- legacy fallback

Status GUI Current

The built-in UI is intentionally minimal. It shows preparing, agent fetch, plan request, running, jump prompts, success, failure, and idle strategy messages.

VersusAI
VersusAI - Running
VersusAI - JUMP
VersusAI - Done
VersusAI - Stopped
VersusAI - Strategising
Good for debugging without a full UI
Tweened emphasis on warnings/jumps

Likely Unused / Outdated Client Parts Outdated

These parts do not look like they are doing anything useful right now, or they rely on behaviour that has already been disabled server-side.

  • UseServerDrivenPlans exists in the default config but does not appear to be read anywhere else.
  • _idleThinkOnce() still posts to /ai/path/idle-think, but the transport layer now treats that endpoint as a no-op.
  • Studio support still references an optional VersusAI_IdleThink remote, which makes it look legacy rather than part of the active flow.
  • /ai/sandbox/map/upsert is only a fallback if chunk upload fails, so it looks legacy rather than preferred.
Recommendation: either fully remove the idle-think endpoint concept from the client, or reintroduce a real backend route so the feature is not half-alive.

Mainframe Responsibilities Current

Mainframe is the higher-level AI layer. It does not calculate the actual nav path itself for the client run. Instead, it prepares agents, tracks performance, stores memory, accepts coaching, and evolves agent params.

mainframe.js handles:
- target knowledge
- path recordings
- agent serving
- run start announcements
- run finish learning
- coach hints
- inspection / admin summaries
- personality, mood, and call-sign progression

Mainframe Routes Current

These are the active mainframe endpoints visible in the file.

POST /ai/path/save-recording
POST /ai/path/get-agents
POST /ai/path/report-run-start
POST /ai/path/report-run
POST /ai/path/admin/coach
POST /ai/path/admin/inspect
Agent pool + support agents
Coaching profile support
Run telemetry + learning

How Mainframe Chooses Agents Current

Agent selection prefers target-specific active agents. If none exist, it falls back to a per-game global pool, and if that is empty it seeds a new batch of agents.

Target-specific agents
   -> fallback to "__global__" agents
      -> seed fresh agents if none exist
         -> decorate with personas / mood / call-signs
            -> attach success/stuck/improve probabilities
Support agents are cross-target helpers with enough prior runs, so the cluster can borrow stronger experience from elsewhere.

What report-run Updates Current

On run finish, mainframe updates both the chosen agent and the target memory. It stores path outcomes, stuck positions, environment snapshots, recordings, and then triggers possible evolution.

report-run stores / updates:
- aiPathRun
- aiPathAgent
- aiTargetKnowledge
- aiEnvironmentSnapshot
- aiPathRecording (via save-recording)
- agent mood / stats / params
- dialogue history
- probabilities inputs
- maybeEvolveAgents(...)

Coaching System Current

Manual creator hints are classified into intent buckets and attached either globally to a target or to a more specific stuck location key.

POST /ai/path/admin/coach

Current built-in coach intents:
- entrance_forward
- jumpable
- parkour_right_wall
string-similarity classification
location-aware hint scoping
agent discussion / logging output

Sandbox Responsibilities Current

Sandbox is the low-level planner and tooling layer. It stores maps, solves paths, builds previews, exposes the viewer, and gives you cleanup/admin tools.

sandboxRunner.js handles:
- map storage and lazy loading
- chunked map upload
- path solving
- hazard-aware / collider-aware A*
- viewer + SSE events
- leaderboard, runs, PBs
- admin delete / wipe routes
- waypoint directives
- hooks into sandboxEngine.js

Sandbox Routes Current

These are the visible routes in the sandbox runner file.

GET  /ai/sandbox/events
GET  /ai/sandbox/viewer
GET  /ai/sandbox/leaderboard
GET  /ai/sandbox/engine/runs
GET  /ai/sandbox/engine/bests
GET  /ai/sandbox/engine/run/:id
DELETE /ai/sandbox/engine/run/:id

POST /ai/sandbox/admin/delete-map
POST /ai/sandbox/admin/delete-runs
POST /ai/sandbox/admin/wipe-all
POST /ai/sandbox/admin/coach-waypoint

GET  /ai/sandbox/maps
GET  /ai/sandbox/map/preview
GET  /ai/sandbox/map/exists
POST /ai/sandbox/map/upload/init
POST /ai/sandbox/map/upload/chunk
POST /ai/sandbox/map/upload/commit
POST /ai/sandbox/map/upsert
POST /ai/sandbox/path/solve
GET  /ai/sandbox/status

Planned AutoFarm Server Flow Planned

The full auto-farm plan changes the solve flow from single-goal movement into area-based batched routing. The server should choose the first few targets, solve their legs now, and keep preparing the rest in the background while the client is already moving.

Client sends:
- IsAutoFarm = true
- ContinueUntilStop = true/false
- AreaName / RouteKey / LoopStartPosition
- Targets = { visible target snapshot }
- AttackRange / PreferredRange / MinSafeRange
- PrecomputeCount

Server returns:
- farmSessionId / batchId / version
- target order for the current batch
- path legs for the first few targets
- attack point for each target
- enough metadata for the client to continue without pausing after every kill
  • When IsAutoFarm is true, do not save the initial player-to-first-target path as the main reusable farming path.
  • Save target-to-target legs and area-level loop knowledge instead, so the memory is tied to the farming route rather than wherever the player started.
  • Use AreaName, RouteKey, and the loop anchor so all targets in the same area can be grouped under a stable farm identity.
  • Keep the current batch alive until all targets in it are resolved. Only refresh when the batch is exhausted and the area cannot find more valid targets locally.
  • Prepare the next batch in the background before the client fully runs out of targets, so the player rarely has to stand still waiting on a solve.
Best fit for the current architecture: keep sandboxRunner.js as the path solver for each leg, while mainframe.js stores area memory, target confidence, target-to-target route reuse, and session state.

Attack Range-Aware Pathing Planned

For some games the player can hit from far enough away that pathing directly into the mob is actually worse. The solver should aim for a good attack point around the target instead of the target centre itself.

Attack inputs:
- TargetDetectRange = 80
- AttackRange = 18
- PreferredRange = 14
- MinSafeRange = 10

Planner target:
- player -> best attack point around mob
- not player -> mob center
Best model: treat the target like an attack donut. Too close is dangerous, too far cannot hit, and the ideal solve endpoint sits in the preferred band if a safe walkable point exists.
  • Sample candidate attack points around the target instead of only solving to the centre.
  • Prefer reachable points with probable line of sight and enough distance from the mob's danger-close zone.
  • Store attack profiles per game or per area later if different games need different stand-off behaviour.

Viewer / Mob Recognition Plan Planned

The sandbox viewer can become the auto-farm debugger by rendering not just geometry but also visible combat targets and their chosen attack points.

Viewer can show:
- map geometry
- visible target markers
- selected batch targets
- chosen attack stand-off points
- rough attack radius circles
- humanoid-confirmed targets vs low-confidence props
  • Use target snapshots from the client to mark likely mobs if their positions line up with the uploaded map.
  • Use HasHumanoid and HasHumanoidRootPart to raise target confidence.
  • Show which mobs were selected by the batch planner so route quality is easier to debug.

Path Solve Output Current

The solve route can return nodes, jump actions, and meta/debug information. The client then follows that plan.

{
  version: "plan_v3",
  nodes: [...],
  actions: [
    { type: "jump", nodeIndex: 7, jt: 1, prompt: "Jump" },
    { type: "jump", nodeIndex: 15, jt: 2, prompt: "Clear gap" },
    { type: "jump", nodeIndex: 23, jt: 3, prompt: "Jump over kill brick" }
  ],
  meta: {
    expanded,
    verticalAbs,
    jumpEdges,
    hopJumpEdges,
    gapMomentumEdges,
    killHopEdges
  }
}
Collider-aware blocking
Hazard mask for red neon kill parts
Gap momentum + jump hop support

Offline PB Engine Current

sandboxEngine.js is the offline optimiser. It refreshes sandbox agents, targets, evaluates solutions, smooths/mutates paths, computes times, records PBs, and emits engine events.

SandboxEngine core jobs:
- refresh agents
- refresh targets
- solve baseline path
- smoothPath(...)
- mutateShortcuts(...)
- computeTimeMs(...)
- record bests and attempts
- emit PB / failure events

Red / Orange Audit Review

These are the pieces that most strongly look like they need updating.

Red
Likely broken if used
  • lruEvictIfNeeded() uses MapMem.entries() and SolMem.entries() even though those caches are plain objects.
  • trainerPickMap() uses MapMem.values() even though MapMem is a plain object.
  • startIdleTrainer() loops Trainer.agents.values() even though Trainer.agents is also a plain object.
Orange
Legacy / partial / manual
  • //startIdleTrainer(); is commented out, so the whole trainer path looks inactive right now.
  • /map/upsert looks like legacy compatibility beside the chunked upload pipeline.
  • /path/idle-think is treated as a no-op on the client, so the old idle endpoint flow looks retired.
  • /admin/coach-waypoint looks manual/server-side only and not part of the normal client path flow.

Likely Unused or Low-Use Items Likely Unused

These are not guaranteed dead, but they do not look like normal production flow from the files you provided.

  • UseServerDrivenPlans config on the client appears unused.
  • /ai/path/admin/inspect is an admin inspection route and does not appear to be called by the client.
  • /ai/sandbox/status is a debug route rather than a normal runtime dependency.
  • /ai/sandbox/viewer, /events, /leaderboard, and engine run routes are tooling / monitoring routes, not movement routes.
  • /ai/path/save-recording is only called after successful runs with enough points, so it is conditional rather than always-on.

Cleanup Notes Later

The same cleanup candidates are still noted here, but this section is now written as general cleanup notes instead of a hard priority ladder.

  • Fix the plain-object cache iteration bugs in sandboxRunner.js.
  • Decide whether the sandbox idle trainer should be re-enabled or removed fully.
  • Remove or properly revive the old idle-think flow so it is not half-retired.
  • Decide whether /map/upsert still deserves to exist beside the chunked upload flow.
  • Clean out low-use config values and manual-only routes after the auto-farm flow settles.
CURRENT

17 documented current areas

Existing client and server responsibilities supported by the supplied AI documentation.

PLANNED

7 planned extensions

AutoFarm, target awareness, attack range handling, and viewer recognition remain future work.

REVIEW

4 audit or cleanup areas

Outdated, low-use, and cleanup notes remain visible instead of being silently removed.