# Using arclib

This is a guide for downstream developers intending to use arclib to create game-specific integration mods.

## Quick Start

### Installation

Add `arclib` to your mod's dependencies in `mod.conf`:

```toml
depends = arclib
```

### Basic Usage

```lua
-- Create a manager instance
local manager = arclib.manager({
	url_target = "wss://archipelago.gg:38281",
	login_slotname = "PlayerName",
	login_gamename = "Your Game Name",
	modstore = core.get_mod_storage()  -- For persistence
})

-- Set up event handlers
manager.on("update", function()
	-- Handle state updates (items received, locations checked, etc.)
	local state = manager.state
	if state.items_received then
		-- Process received items
	end
end)

manager.on("printtext", function(text)
	-- Display chat messages from Archipelago
	core.chat_send_all(text)
end)
core.register_on_chat_message(function(_, msg)
		-- Relay local chat to archipelago
		manager:say(msg)
	end)

-- Load saved connection configuration
arclib.ux.configure({
	modstore = modstore,
	manager = manager
})

-- Chat command to access config UI
core.register_chatcommand("ap", {
	description = "Show Archipelago config form",
	func = function(name)
		arclib.ux.configure({
			modstore = modstore,
			player = name,
			manager = manager,
		})
	end
})
```

## API Reference

### State object

Both `arclib.manager` and `arclib.connection` expose a `state` table.

- The connection's `state` is the live, authoritative view of data received from the Archipelago server, maintained and updated internally by `arclib.connection`.
- The manager's `state` is a cached snapshot table that is updated on every connection `update` event by copying keys from the underlying connection's `state`. This snapshot persists across disconnects so your mod can continue to inspect the latest known state even when the socket is down.

Downstream consumers should treat both of these as read-only and use the manager's methods/events to send messages or change server-side state.

#### Contents and derived fields

The connection builds up `state` incrementally from server commands. The exact structure is defined by the Archipelago protocol, but the library adds some convenience/derived fields on top:

- `room_info` – Last `RoomInfo` command payload, expanded into top-level keys.
- `data_package` – Full data package (`games`, etc.), with additional lookup tables per game:
  - `item_id_to_name` – Inverse of `item_name_to_id`.
  - `location_id_to_name` – Inverse of `location_name_to_id`.
- `connected` / `room_update` – Latest connection/session metadata from `Connected` / `RoomUpdate` commands, expanded into top-level keys.
- `items_received` – Ordered array of all items received so far; kept in sync across incremental `ReceivedItems` updates, with resync on desync detection.
- `hintdata` – Raw key→hint-list mapping built from `Retrieved` / `SetReply` notifications.
- `hints` – Flattened array of all hint entries from `hintdata`.
- `checked_locations` / `missing_locations` – Arrays of known checked and missing location IDs.
- `checked_location_index` – Map `location_id -> status` built from `checked_locations` and `missing_locations`:
  - `true` – location is known checked
  - `false` – location is known missing
  - `nil` – location is currently unknown
- Other protocol-provided fields such as `slot`, `slot_info`, `players`, etc. that are passed through from the server without additional transformation.

The manager simply mirrors and accumulates these fields from the underlying connection, making them available as a long-lived snapshot via `manager.state`.

### Manager (`arclib.manager`)

The main interface for Archipelago connections.

Handles automatic reconnects and message resends, including persisting queued reliable messages across restarts.  Maintains a cached replicated state from the server, including across disconnects.

#### Constructor
```lua
local manager = arclib.manager(options)
```

##### Options

- `modstore`: Luanti mod storage for persistence
- `storeprefix`: Optional prefix for storage keys
- `url_target`: Archipelago WebSocket URL
- `url_proxy`: HTTP proxy URL (default: `http://localhost:9839`)
- `login_slotname`: Player slot name
- `login_gamename`: Game name
- `login_password`: Optional room password

#### Methods

- `manager:open()` - Start connection
- `manager:close()` - Stop connection
- `manager:check_location(locations)` - Check location(s) by name or ID (reliable)
- `manager:goal_complete()` - Send goal completion (reliable)
- `manager:say(text)` - Send chat message
- `manager:flush_send_queue()` - Manually flush pending messages

#### Events

- `update` - State updated from server (any data update received, including partial state during startup)
- `printtext` - Chat message received (from PrintJSON) and parsed
- `disconnect` - Connection lost
- `rejected` - Connection rejected by server
- `cmd:*` - Specific Archipelago commands, following Archipelago protocol's TitleCase naming

### Connection (`arclib.connection`)

Low-level protocol handler (used internally by manager).  Not intended for downstream use, exported as-is.

### WebSocket (`arclib.websocket`)

HTTP-to-WebSocket bridge client.  Not intended for downstream use, exported as-is.

### Utilities (`arclib.util`)

- `create_emitter()` - Create event emitter functions
- `deepcopy(src)` - Deep copy tables with cycle support
- `generate_uuid()` - Generate UUID v4
- `log(level, ...)` - Structured logging
- `print_json_convert(state, data)` - Convert PrintJSON to text
- `structstore(modstore, prefix)` - Persistent structured storage

### UX (`arclib.ux`)

- `configure(options)` - Load stored configuration / show configuration UI

### Item Visualization (`arclib.itemvis`)

Standard pseudo-3D visualization for Archipelago items, creating ephemeral visual models that aren't stored in the map.

#### Constructor
```lua
local vis = arclib.itemvis.add(options)
```

##### Options
- `pos` (required): Center position for the visual
- `check` (optional): Function returning truthy to keep visual, auto-destroy if falsy
- `applied_to_node` (optional): Node name this visual is attached to

#### Methods
- `vis:remove()` - Destroy the visual model
- `vis:explode()` - Destroy with particle explosion effect
- `vis:move_to(pos)` - Move the visual to a new position

#### Node Integration
- `arclib.itemvis.node_apply(pos, node)` - Apply visualization to a specific node
- `arclib.itemvis.node_register(nodenames)` - Register visualization for node types via ABM/LBM
- `arclib.itemvis.check_all()` - Manually trigger validation check

#### Utility Functions
- `arclib.itemvis.inside_radius(pos, radius)` - Find all itemvis instances within radius, returns array

#### Usage Example
```lua
-- Create a floating item visualization at a position
local vis = arclib.itemvis.add({
    pos = {x = 100, y = 10, z = 200},
    check = function()
        -- Keep visual only while condition is true
        return some_condition
    end
})

-- Create a node using itemvis for display.
core.register_node(modname .. ":apitem", {
		drawtype = "airlike",
		paramtype = "light",
		sunlight_propagates = true,
		walkable = false,
		on_construct = arclib.itemvis.node_apply,
		after_destruct = arclib.itemvis.node_apply,
		on_punch = function(pos)
			-- (Replace with your method of accessing manager and getting Location ID)
			api.manager:check_location(core.get_meta(pos):get_float("location_id"))
			for _, v in ipairs(arclib.itemvis.inside_radius(pos, 0.5)) do
				v:explode()
			end
			core.remove_node(pos)
		end
	})
arclib.itemvis.node_register({modname .. ":apitem"})
```

## Architecture

```
Your Mod
	↕
arclib.manager
arclib.connection
arclib.websocket
	↕ (HTTP)
External websockproxy
	↕ (WebSocket)
Archipelago Server
```