msw-search

Installation
SKILL.md

MSW Search

MSW has two distinct search targets. They behave differently, so they are covered in separate sections.

  1. API docs & implementation guides — Vector search that provides the details, code examples, related APIs, and implementation guidance that .d.mlua lacks.
  2. Resources — REST API to search and browse sprites, animations, sounds, resource packs, and avatars. The only path for obtaining RUIDs.

Routing Table

Request type Go to section
"How do I implement this?", "Show me an example", "What related APIs exist?" Document search
".d.mlua only has the signature; the description is insufficient" Document search
"I don't know the API name (semantic search)" Document search (type=both)
"Implementation guide / best practice / pattern" Document search (type=document)
"I need a SpriteRUID", "Find a sprite for monster / NPC / background" Resource search
"Find an animation / sound / resource pack" Resource search
"Details for this RUID", "Similar resources" Resource search
"Avatar rendering / default avatar" Resource search

Section 1 — Document Search (APIs & Guides)

Vector search that supplies the detailed descriptions, code examples, related APIs, and implementation guides missing from .d.mlua.

Access Methods

The same vector search backend can be accessed through two paths. Results are identical.

Method Condition Usage
MCP tool msw-guide-mcp is connected Call mlua_Document_Retriever, mlua_API_Retriever
Direct curl Fallback when MCP is not connected curl "http://10.10.200.51:31817/search?q=...&type=...&limit=..."

Decision Flow

Need API-related information
├─ Checking signature / type / property / enum
│   → Read .d.mlua first (highest priority)
│   → If .d.mlua is insufficient, use vector search
│     (code examples, parameter details, related APIs, etc.)
├─ Implementation guide / pattern / best practice
│   → Vector search (type=document)
├─ Don't know the API name (semantic search)
│   → Vector search (type=both)
└─ How to access vector search:
    ├─ msw-guide-mcp connected? → MCP tool
    └─ Not connected → curl

API Research Order

Priority 1 — .d.mlua (always first)

If you know the API name, always read .d.mlua first. Signatures, types, properties, event parameters, and enum values can be confirmed here accurately.

Path: Environment/NativeScripts/{Component,Service,Event,Enum,Logic,Misc}/Name.d.mlua

Situation Example
Confirm method signature "Does TransformComponent have SetPosition?"
Property type / existence "What is the type of SpriteRendererComponent.RUID?"
Event parameter structure "What are the AttackEvent constructor parameters?"
List of enum values "What are the BodyMoveType values?"
Method existence "What methods does SpawnService have?"

Priority 2 — Vector search (when .d.mlua is not enough)

.d.mlua contains only signatures and lacks detailed descriptions and examples. Use vector search when you need any of the following.

Situation Search type Example query
Need a code example api AIComponent example, BehaviorTree usage
Parameter details api BadgeService GetBadgeInfosAndWait parameters
Related API cross-references api AttackComponent related, HitComponent
ScriptOverridable check api AttackComponent CalcCritical override
Don't know the API name both damage calculation, inventory save
"How do I …?" implementation guide document how to make inventory system
Pattern / best practice document collision detection best practice

MCP mapping: mlua_API_Retriever = type=api, mlua_Document_Retriever = type=document.


MCP Tool Usage

When msw-guide-mcp is connected:

Tool Maps to type Description
mlua_API_Retriever api API details for Service / Component / Misc etc. (signatures, parameters, examples)
mlua_Document_Retriever document Authoring manuals, guidelines, MLua usage, and other document-style material

Tool names and parameters follow the latest MCP schema.

Connection check: If a tool call errors out, it is not connected — fall back to curl.


Direct curl Usage

When msw-guide-mcp is not connected:

GET http://10.10.200.51:31817/search?q={query}&type={type}&limit={limit}
Parameter Required Value Description
q O string Search query (natural language or API name)
type X api | document | both Search scope (default: both)
limit X integer Max results (default: 5)

How to choose type

Intent type
Specific API spec (parameters, return type, example) api
Implementation guidance (how-to, tutorial, concept) document
Ambiguous or broad scope both

Usage Examples

# Specific API details + example
curl "http://10.10.200.51:31817/search?q=AIComponent&type=api&limit=5"

# Implementation guide
curl "http://10.10.200.51:31817/search?q=how+to+make+an+inventory+system&type=document&limit=5"

# Semantic search (when exact API name is unknown)
curl "http://10.10.200.51:31817/search?q=collision+detection&type=both&limit=10"

Response Format

{
  "results": "formatted text with matching documents (title, section, content)"
}

Error Handling

Code Meaning Action
503 Service is starting up Retry after a short wait
500 Internal error (OpenSearch) Fall back to .d.mlua files
Connection failure Service not running Fall back to .d.mlua files

.d.mlua vs Search — Information Comparison

.d.mlua is a type stub (~29 lines); Search returns the full document (254+ lines).

Information .d.mlua Search
Method signature / types O O
Property declarations O O
Detailed method description (DetailDesc) X O
Code examples (AdditionalPageContent) X O
Per-parameter descriptions X O
Related APIs (SeeAlsoAPIs) X O
Related guides (SeeAlsoGuides) X O
ScriptOverridable flag X O
SyncDirection Partial O
Localized descriptions (Ko/Ja/Es/Zh) X O

Maker Editor Syntax → .mlua Conversion Rules

Code examples in search results use Maker Editor syntax. They must be converted before being used in a local .mlua file.

Item Maker Editor .mlua file Note
Override declaration override integer CalcDamage(...) method integer CalcDamage(...) overridemethod
Block { ... } ... end Braces → end
Exec space [server only] or omitted @ExecSpace("ServerOnly") Annotation must be explicit
Property Property: int32 Score = 0 @Sync property int32 Score = 0 Add @Sync if synced
Type int int integer C# int → mlua integer
Type number number number Same (double)
Type float float float Same (single)

number (64-bit double) and float (32-bit single) are assignable to each other but remain distinct types. Follow the .d.mlua declaration.

Conversion example — AttackComponent from search results:

-- Maker Editor syntax (search result)
override int CalcDamage(Entity attacker, Entity defender, string attackInfo) {
    return 50
}
override boolean CalcCritical(Entity attacker, Entity defender, string attackInfo) {
    return _UtilLogic:RandomDouble() < 0.3
}
-- Converted to .mlua
@ExecSpace("ServerOnly")
method integer CalcDamage(Entity attacker, Entity defender, string attackInfo)
    return 50
end

@ExecSpace("ServerOnly")
method boolean CalcCritical(Entity attacker, Entity defender, string attackInfo)
    return _UtilLogic:RandomDouble() < 0.3
end

Section 2 — Resource Search (Sprite / Animation / Sound / Resource Pack / Avatar)

REST API for searching and browsing MSW resources. Never guess or fabricate a RUID — always obtain one through this API.

Base URL

https://maplestoryworlds-resourcesearch-new.nexon.com/api
  • No authentication (public API)
  • All endpoints use the /v3/ prefix
  • Content-Type: application/json; charset=utf-8 (for POST requests)
  • Recommended timeout: 15 seconds

POST body rule — always use a temp file, never inline -d '...'

For every POST endpoint in this section (/v3/search/resources, /v3/resources/batch, /v3/avatar/render), write the JSON body to a temp file first and call curl with --data-binary "@file":

REQ="$TMPDIR/msw_req.json"
cat > "$REQ" <<'JSON'
{ "query": "주황버섯", "types": ["resource_pack"], "categories": ["mob"], "limit": 5 }
JSON

curl -s -X POST https://maplestoryworlds-resourcesearch-new.nexon.com/api/v3/search/resources \
  -H "Content-Type: application/json; charset=utf-8" \
  --data-binary "@$REQ"

Why: passing JSON inline (-d '{"query":"주황버섯",...}') frequently breaks on non-ASCII input (Korean / Japanese / Chinese / emoji). The shell re-encodes the argument and the server returns:

{ "detail": "There was an error parsing the body" }

The temp-file pattern also sidesteps the extra quoting/escaping required on Windows (PowerShell, Git Bash). Apply it uniformly even when the body is ASCII-only, so the recipe stays identical across platforms and languages.

On Windows PowerShell, use $env:TEMP\msw_req.json instead of $TMPDIR/msw_req.json and write the file with Set-Content -Encoding utf8 (or Out-File -Encoding utf8). The --data-binary "@file" part is unchanged.

Resource Types

type Description
sprite Static image (PNG)
animationclip Frame-based animation
resource_pack Finished asset bundling sprites + animations + sounds
sound Sound / audio clip

Categories

category Description
mob Monster
npc NPC
map Map / background / terrain
item Item
effect Effect
skill Skill
ui UI element

RUID

A 32-character hex string that uniquely identifies every resource. Example: "0017da7385e04bc4b2ddbe5949b4b462"

  • The id field in search results is the RUID
  • assetGuid is a separate Unity asset GUID (used in spawn_preset)
  • Never guess or fabricate a RUID — always obtain it from an API response

Common Response Fields

{
  "id": "32-char hex RUID",
  "type": "sprite|animationclip|resource_pack|sound",
  "category": "mob|npc|map|item|effect|skill|ui",
  "names": {
    "ko": ["Korean name"],
    "en": ["English name"]
  },
  "assetGuid": "Unity asset GUID (may or may not exist)",
  "payload": {
    "width": 64,
    "height": 64,
    "thumbnail": "https://...",
    "pivot": {"x": 32, "y": 32},
    "frames": [],
    "elements": []
  }
}

Endpoint Summary

Method Endpoint Purpose
POST /v3/search/resources Natural-language semantic search
GET /v3/search/resources/similar/{ruid} Find similar resources
GET /v3/resources/{ruid} Single resource details
POST /v3/resources/batch Batch fetch multiple resources
GET /v3/resources/tags/{ruid} AI-generated multilingual tags
GET /v3/resources List by type / category
GET /v3/resources/random Random resource recommendation
GET /v3/resources/packs/{pack_id} Resource pack details + components
GET /v3/avatars/defaults Default avatar body / head RUIDs
GET /v3/avatars/{ruid} Avatar item details
POST /v3/avatar/render Render an avatar

Resource Routing Guide

Situation Endpoint to use Reference file
"Find a slime sprite" POST /v3/search/resources references/resource/search.md
"Any more monsters like this one?" GET /v3/search/resources/similar/{ruid} references/resource/search.md
"Details for RUID abc123" GET /v3/resources/{ruid} references/resource/detail.md
"Show me a list of monster sprites" GET /v3/resources references/resource/browse.md
"What's inside this resource pack?" GET /v3/resources/packs/{pack_id} references/resource/browse.md
"Render an avatar" POST /v3/avatar/render references/resource/avatar.md

Typical Workflow

1. Semantic search (POST /v3/search/resources) → obtain RUID
2. Detail lookup (GET /v3/resources/{ruid}) → inspect payload
3. For resource packs → pack details (GET /v3/resources/packs/{pack_id}) → individual element RUIDs
4. Assign the individual RUID to SpriteRendererComponent.SpriteRUID

For detailed Request/Response of each endpoint, refer to the files under references/resource/.


Sprite Orientation — Most Resources Face Left

The vast majority of MSW sprite / animationclip / resource_pack assets — especially mob, npc, and player-character resources — are authored facing left in their default frames. A freshly spawned SpriteRendererComponent therefore renders facing left unless you flip it.

Situation What to do
Spawn an entity that should face right Set FlipX = true on SpriteRendererComponent (default is false = left-facing as authored)
Custom AI / chase using MovementComponent:MoveToDirection Update FlipX on direction change: sprite.FlipX = velocity.x > 0 (right ⇒ flip)
Native AIChaseComponent / AIWanderComponent Engine flips automatically based on movement — do nothing
Top-down (RectTile) movement Decide per-axis: usually flip when dx > 0; sprites with up/down frames need the StateAnimationComponent action set instead
_EffectService:PlayEffect(...) should face right Pass FlipX = true in the options table
Player-attached effect must follow the player's facing Use SyncFlip = true in PlayEffect options, or read PlayerControllerComponent.LookDirectionX
Resource is authored facing right (rare) Inspect payload.thumbnail via GET /v3/resources/{ruid} and invert the rule for that asset
-- Custom side-view chase: flip sprite to match movement direction
local sprite = self.Entity.SpriteRendererComponent
local selfX = self.Entity.TransformComponent.WorldPosition.x
local dx    = targetPos.x - selfX
if dx ~= 0 then
    sprite.FlipX = dx > 0   -- target on the right → flip
end

Sanity check — before assuming left-facing, hit GET /v3/resources/{ruid} and open payload.thumbnail. The convention holds for the overwhelming majority of MSW resources but is not contractually guaranteed; treat the thumbnail as the source of truth.

Do not use TransformComponent.Scale.x to flip — it breaks physics colliders. Always use SpriteRendererComponent.FlipX. (See msw-combat-system/SKILL.md line 423: "방향 판정 ★".)


Shared Tips

  1. Keyword choice — Use the exact name if you know it; natural-language Korean/English also works.
  2. Adjust limit — Use a larger value (10+) for broad exploration, smaller (3) for precise lookups.
  3. When search fails:
    • Document search fails → read .d.mlua directly and check mod/APIMetadata/ JSON.
    • Resource search fails → retry with synonyms or a different category; browse with GET /v3/resources by type/category.
    • POST returns {"detail":"There was an error parsing the body"} → you almost certainly used inline -d '{...}' with a non-ASCII value. Switch to the temp-file pattern (--data-binary "@file") described in Section 2.
  4. Composite queries are allowed — e.g. AttackComponent CalcCritical for docs, red slime jump for resources.
  5. No guessing — Never guess API names, RUIDs, or enum values; always confirm via search or references.
Related skills

More from msw-git/msw-ai-coding-plugins-official

Installs
25
First Seen
10 days ago