Object MethodTouch and ActionsComing soonv1.0.54

Navigation.writeProfile(profileJson, expectedRevision)

Saves a complete setup JSON document. Use expectedRevision=0 for creation and the read revision for updates. Author map, mini-map, marker, joystick and routes in code. Rejects stale revisions, foreign images and calibration writes. Does not start movement; geometry changes require recalibration.

Documented for app version 1.0.54 (not on Google Play yet)Updated:

Detailed Explanation

This section explains when to use the API, how to call it, and which structures it works best with in production flow.

How To Call It

Navigation is a global table: call its functions with a dot (Navigation.<method>(...)), not a colon. Requires Macro Handler 1.0.54 or later.

When To Use It

On 1.0.54 and later, author a setup without importing a plugin or adding a visual block. Images must be in the current macro’s image library. Replace the sample screen and route measurements with yours; RUN defaults to false, so the example starts no movement.

Parameters and Return

profileJson is the complete setup document. For creation use expectedRevision=0; an omitted id is generated. For an update, JSON.parse the readProfile result, retain id and revision, then write with that revision. Returns ok, code, profileId, revision and profileJson. Re-read after profile_revision_conflict.

Options and Limits

liveMapRegion and miniMap.liveRegion use screen fractions from 0 to 1. Route points use reference-map fractions. joystick.radius is relative to the longer screen edge. marker anchorNorm and headingTipNorm are fractions of the marker crop. Limits: 16 setups, 32 routes per setup, 4 Mi characters of JSON and 4 MiB per stored setup. Rejects wrong types, unknown fields and images from other macros. calibration is not writable; geometry changes require new measurements. Writes and deletes are refused during an active journey.

Best Combined With

It works best together with wait(), Point, SwipeParam, ClickParam, and sometimes a Region result.

Example Usage

The snippet below is a starter pattern that can be applied directly in runtime flow.

local r = Navigation.writeProfile(JSON.stringify({ label = "Coded setup" }), 0)
if r.ok then print(r.profileId, r.revision) else print(r.code) end
-- Fill mapReference, marker, joystick, regions and routes before running.

Copyable Progressive Examples

From foundation to combined usage, each level is provided as a separate code block so you can copy the level you need and adapt it directly.

Foundation

Shows the shortest direct way to call the API.

Foundation
local r = Navigation.writeProfile(JSON.stringify({ label = "Coded setup" }), 0)
if r.ok then print(r.profileId, r.revision) else print(r.code) end
-- Fill mapReference, marker, joystick, regions and routes before running.

Simple

Wraps the base call with minimal flow control.

Simple
local stepOk = true
local r = Navigation.writeProfile(JSON.stringify({ label = "Coded setup" }), 0)
if r.ok then print(r.profileId, r.revision) else print(r.code) end
-- Fill mapReference, marker, joystick, regions and routes before running.
if stepOk then
  wait(200)
end

Practical Flow

A practical pattern for real macros with pcall, logging, and guards.

Practical Flow
local ok, err = pcall(function()
  local r = Navigation.writeProfile(JSON.stringify({ label = "Coded setup" }), 0)
  if r.ok then print(r.profileId, r.revision) else print(r.code) end
  -- Fill mapReference, marker, joystick, regions and routes before running.
end)

if not ok then
  print("API step failed: Navigation.writeProfile: " .. tostring(err))
  requestStop()
end

Detailed

This level packages the API into a reusable helper with error reporting.

Detailed
-- In automation flow, chain actions with short wait() intervals and use requestStop() or controlled retry on failure paths.
local function run_writeprofile_step()
  local r = Navigation.writeProfile(JSON.stringify({ label = "Coded setup" }), 0)
  if r.ok then print(r.profileId, r.revision) else print(r.code) end
  -- Fill mapReference, marker, joystick, regions and routes before running.
end

local ok, err = pcall(run_writeprofile_step)
if not ok then
  toast("Step failed")
  print(err)
end

Combined

Combines the API with related structures to form a more realistic workflow.

Combined
-- Macro Handler 1.0.54+: no .mhblock import or visual block is needed.
-- Save map_image and marker_image in THIS macro's image library first.
-- These example coordinates are placeholders. Measure your own screen/map before enabling RUN.
local RUN = false
local mapResult = Navigation.asset("map_image")
local markerResult = Navigation.asset("marker_image")
assert(mapResult.ok, mapResult.code)
assert(markerResult.ok, markerResult.code)

local marker = {
    mode = "REFERENCE", crop = markerResult.asset,
    taughtSizeMapNormW = 0.04, taughtSizeMapNormH = 0.04,
    anchorNorm = {x = 0.5, y = 0.5}, headingTipNorm = {x = 0.5, y = 0.1}
}
local routeId = "11111111-2222-4333-8444-555555555555"
local profile = {
    label = "My coded navigation",
    mapReference = {image = mapResult.asset},
    frameWidth = 1200, frameHeight = 800,
    liveMapRegion = {left = 0.1, top = 0.1, right = 0.8, bottom = 0.9},
    marker = marker,
    miniMap = {
        liveRegion = {left = 0.80, top = 0.02, right = 0.98, bottom = 0.25},
        shape = "circle", markerPosition = "centered", centerSearchRadius = 0.12,
        marker = marker
    },
    joystick = {center = {x = 0.12, y = 0.80}, radius = 0.08, deadZone = 0.15},
    routes = {{id = routeId, name = "Route A", type = "one_way",
        points = {{x = 0.20, y = 0.30}, {x = 0.25, y = 0.40}, {x = 0.40, y = 0.50}}}}
}

-- Retain the returned profileId. Do not create a fresh profile on every macro iteration.
local profileKey = "my_coded_navigation_profile"
local previousId = KV.get(profileKey, "")
local expectedRevision = 0
if previousId ~= "" then
    local previous = Navigation.readProfile(previousId)
    assert(previous.ok, previous.code) -- Do not silently recreate a deleted/unknown setup.
    profile.id = previous.profileId
    profile.revision = previous.revision
    expectedRevision = previous.revision
end
local saved = Navigation.writeProfile(JSON.stringify(profile), expectedRevision)
assert(saved.ok, saved.code)
KV.set(profileKey, saved.profileId)
print("Setup saved", saved.profileId, saved.revision)

-- An observation group can be an ordinary Lua function; no saved visual group is required.
local monitorId = "coded-monitor"
local function onCheckpoint(event)
    assert(event.groupId == monitorId, "Unknown callback")
    if event.validateOnly then return true end -- Preflight never performs screen actions.
    if event.kind == "observation" then
        print("Position", event.values.playerX, event.values.playerY)
        -- Read-only image/OCR/color checks may be added here.
        -- Before touching the screen, assert(Navigation.stop() == true).
    end
    return true
end

if RUN then
    -- Enable only after reviewing YOUR coordinates, heading and target application.
    local result = Navigation.run({
        profileId = saved.profileId, routeId = routeId, mapSource = "mini_map",
        routeType = "one_way", controlMode = "heading_feedback", timeoutMs = 120000,
        headingFeedback = {fixedCamera = true, joystickUpHeadingDegrees = 0},
        joystickMotion = {enabled = false, amplitudeDegrees = 5, periodMs = 1000},
        observationGroup = {groupId = monitorId, groupName = "Code monitor", intervalMs = 1000,
            executionMode = "observe"}
    }, onCheckpoint)
    print(result.state, result.lastFailure)
end