{
  "openapi": "3.1.1",
  "info": {
    "title": "ACDatService API",
    "description": "API for the ACDatService",
    "version": "0.1.0",
    "contact": {
      "name": "Contact Info",
      "email": "petridish@gmail.com",
      "url": "https://github.com/amoeba/acdatservice"
    }
  },
  "servers": [
    {
      "url": "https://dats.treestats.net/",
      "description": "Main ACDatService Server"
    }
  ],
  "paths": {
    "/dats": {
      "get": {
        "summary": "List available DATs",
        "description": "Returns a JSON object describing the available DATs (portal, cell, highres, and local_english) with their R2 object keys, file counts, size in bytes, and sha256 hashes.",
        "operation_id": "dats_index"
      }
    },
    "/setups/{id}": {
      "get": {
        "summary": "Get a portal DAT setup",
        "description": "Returns the raw binary content of a Setup (0x02) resource from client_portal.dat. The id can be specified as a decimal number or as a hex string with a 0x or 0X prefix. Add ?include=gfxobjs to receive a multipart/mixed response whose first part is the setup and whose remaining parts are the distinct GraphicsObject (0x01) resources referenced by the setup.",
        "operation_id": "setups_get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Setup ID as decimal or hex (0x- or 0X-prefixed).",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include",
            "in": "query",
            "description": "Optional related resources to include. Use gfxobjs to receive multipart/mixed containing the setup and its GraphicsObject parts.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/dats/{dat}/landblocks/{block}": {
      "get": {
        "summary": "Get a landblock metadata bundle",
        "description": "Returns the ACLB bundle for one landblock's terrain (…FFFF) and LandblockInfo (…FFFE) from the cell DAT. The block can be a 16-bit landblock id (0xB34A) or any full file id in the block (0xB34AFFFF); the high word is used. Bytes are served from the pre-extracted R2 bucket as cell/landblocks/0x{block:04X}.bin. Only the cell DAT has bundles.",
        "operation_id": "landblocks_get",
        "parameters": [
          {
            "name": "dat",
            "in": "path",
            "description": "DAT name. Only 'cell' has bundles.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "block",
            "in": "path",
            "description": "Landblock id (0xB34A) or a full file id in the block (0xB34AFFFF).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/dats/{dat}/setups/{id}": {
      "get": {
        "summary": "Get a precomputed setup pack",
        "description": "Returns the ACSP bundle of a Setup's full render closure, served from the extracted R2 bucket as portal/setups/0x{id:08X}.bin. Only the portal DAT has setup packs.",
        "operation_id": "setups_bundle_get",
        "parameters": [
          {
            "name": "dat",
            "in": "path",
            "description": "DAT name. Only 'portal' has setup packs.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "description": "Setup file id (0x02001B7F or decimal).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/dats/{dat}/files/{file_id}": {
      "get": {
        "summary": "Get a file by ID from a DAT",
        "description": "Returns the raw binary content of a DAT file by its ID. By default the file is served from the pre-extracted R2 bucket as a single flat object. Pass ?source=dat to read the file from the original DAT via D1 metadata and block-chain traversal instead; use this for files that have not been extracted yet or to compare against the extracted copy. The file_id can be specified as a decimal number (e.g., 16777217) or as a hex string with a 0x or 0X prefix (e.g., 0x1000001). Add ?format=json to request a JSON representation for file types that support it.",
        "operation_id": "files_get",
        "parameters": [
          {
            "name": "dat",
            "in": "path",
            "description": "DAT name. Use 'portal', 'cell', 'highres', or 'local_english'.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "file_id",
            "in": "path",
            "description": "File ID as decimal or hex (0x- or 0X-prefixed).",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "Optional response format. Use json to request a JSON representation for file types that support export.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "in": "query",
            "description": "Optional storage source. Omit or use 'extracted' to read the pre-extracted flat R2 object; use 'dat' to read the original DAT via D1 metadata and block-chain traversal (the legacy behavior, which also returns the X-R2-Read-Count response header).",
            "required": false,
            "schema": {
              "type": "string",
              "default": "extracted"
            }
          }
        ]
      }
    },
    "/icons": {
      "get": {
        "summary": "List icon metadata",
        "description": "Returns paginated JSON Lines file metadata for icon files. Pages default to 1000 records and are capped at 1000. For the next cursor, use the X-Next-After response header as the after value; offset is supported for compatibility.",
        "operation_id": "icons_index",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of icons to return. Defaults to 1000, max 1000.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1000,
              "minimum": 1,
              "maximum": 1000
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of icons to skip. Defaults to 0.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Return icons with IDs greater than this value. More efficient than offset for sequential pagination.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ]
      }
    },
    "/icons/{id}": {
      "get": {
        "summary": "Get an icon",
        "description": "Returns a PNG icon with optional scaling applied and any provided underlay, overlay, or UI effect mixed in. Example https://dats.treestats.net/icons/26967?scale=2. All Icon IDs can be passed as decimal or hex and either absolute or relative (to 0x06000000) values can be used. For example, all of these values return the same icon: 0x6957, 0x06006957, 26967, 100690263.",
        "operation_id": "icons_get",
        "parameters": [
          {
            "name": "icon_id",
            "in": "path",
            "description": "Icon ID as decimal or hex. Accepts absolute or relative values.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "scale",
            "in": "query",
            "description": "Optional integer value to scale the image by.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1,
              "maximum": 8
            }
          },
          {
            "name": "background",
            "in": "query",
            "description": "Optional background texture. Accepts texture ID (as decimal or hex, absolute or relative) or an ItemType name (case-insensitive). ItemTypes: melee_weapon, armor, clothing, jewelry, creature, food, money, misc, missile_weapon, container, gem, spell_components, key, caster, portal, promissory_note, mana_stone, service. Use 'random' to select a random ItemType background.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "underlay",
            "in": "query",
            "description": "Optional underlay texture ID as decimal or hex, absolute or relative.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "overlay",
            "in": "query",
            "description": "Optional overlay texture ID as decimal or hex, absolute or relative.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ui_effect",
            "in": "query",
            "description": "Optional UI effect texture. Accepts texture ID (as decimal or hex, absolute or relative) or a UiEffects name (case-insensitive). UiEffects: undef (transparent), magical, poisoned, boost_health, boost_mana, boost_stamina, fire, lightning, frost, acid, bludgeoning, slashing, piercing, nether, default (fire+magical), reversed. Use 'random' to select a random UiEffect.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/dats/world/landblock-instances/{block}": {
      "get": {
        "summary": "Get landblock instances",
        "description": "Returns the ACLI landblock-instances file for one landblock: the ACE world database's static props (fountains, doors, chests, lifestones, and similar), pre-resolved offline into one small blob. The block can be a 16-bit landblock id (0xB34A) or any full file id in the block (0xB34AFFFF); the high word is used. Bytes are served from the pre-extracted R2 bucket as world/landblock-instances/0x{block:04X}.bin.",
        "operation_id": "world_instances_get",
        "parameters": [
          {
            "name": "block",
            "in": "path",
            "description": "Landblock id (0xB34A) or a full file id in the block (0xB34AFFFF).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/dats/{dat}/files": {
      "get": {
        "summary": "List file metadata for a DAT",
        "description": "Returns JSON Lines file metadata for the requested DAT. Use 'portal', 'cell', 'highres', or 'local_english' for the dat parameter. Results are ordered by file ID and paginated; pages default to 1000 records and are capped at 1000. For the next cursor, use the X-Next-After response header as the after value; offset is supported for compatibility.",
        "operation_id": "files_index",
        "parameters": [
          {
            "name": "dat",
            "in": "path",
            "description": "DAT name. Use 'portal', 'cell', 'highres', or 'local_english'.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of files to return. Defaults to 1000, max 1000.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1000,
              "minimum": 1,
              "maximum": 1000
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of files to skip. Defaults to 0.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Return files with IDs greater than this value. More efficient than offset for sequential pagination.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ]
      }
    },
    "/dats/{dat}/envcells/{block}": {
      "get": {
        "summary": "Get an EnvCell bundle",
        "description": "Returns the ACLB bundle containing every EnvCell owned by one landblock from the cell DAT. The block can be a landblock id (0xB34A) or any full cell id within it (0x1E3033D); the high word is used. Bytes are served from the pre-extracted R2 bucket as cell/envcells/0x{block:04X}.bin. Only the cell DAT has bundles.",
        "operation_id": "envcells_get",
        "parameters": [
          {
            "name": "dat",
            "in": "path",
            "description": "DAT name. Only 'cell' has bundles.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "block",
            "in": "path",
            "description": "Landblock id (0xB34A) or any full file id in the block (0x1E3033D).",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/dats/{dat}/batch": {
      "get": {
        "summary": "Batch-read many files from a DAT",
        "description": "Returns a multipart/mixed response with one part per requested file ID that exists in the DAT. IDs are comma-separated decimals or 0x-prefixed hex values; duplicates are removed and order is preserved. Missing IDs are omitted (absence means not found) and never fail the batch. At most 512 ids and 8 MiB of combined payload are accepted, otherwise the request is rejected with 413.",
        "operation_id": "batch_get",
        "parameters": [
          {
            "name": "dat",
            "in": "path",
            "description": "DAT name. Use 'portal', 'cell', 'highres', or 'local_english'.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ids",
            "in": "query",
            "description": "Comma-separated file IDs, each a decimal value or a 0x/0X-prefixed hexadecimal value. Duplicates are removed and first-occurrence order is preserved.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    }
  }
}