diff --git a/README.ja.md b/README.ja.md index 2880f64..50b05ca 100644 --- a/README.ja.md +++ b/README.ja.md @@ -76,6 +76,10 @@ ws://127.0.0.1:8765/ws ### 目次 - [🏓 Ping-Pong(接続テスト)](#-ping-pong接続テスト) - [🌲 Tree(シーン構造)](#-treeシーン構造) +- [📦 Item(アイテムカタログ)](#-itemアイテムカタログ) + - [グループ一覧取得](#グループ一覧取得) + - [グループ内カテゴリ取得](#グループ内カテゴリ取得) + - [カテゴリ内アイテム取得](#カテゴリ内アイテム取得) - [🔄 Update(オブジェクト変更)](#-updateオブジェクト変更) - [Transform更新](#transform更新) - [アイテム色変更](#アイテム色変更) @@ -144,6 +148,127 @@ ws://127.0.0.1:8765/ws ] ``` +### 📦 Item(アイテムカタログ) + +シーンに追加可能なすべてのアイテムの情報を取得します。アイテムは階層構造で整理されています:グループ → カテゴリ → アイテム。 + +#### グループ一覧取得 + +すべてのアイテムグループの一覧を取得: + +**リクエスト:** +```json +{ + "type": "item", + "command": "list-groups" +} +``` + +**レスポンス:** +```json +{ + "type": "success", + "command": "list-groups", + "data": [ + { + "id": 0, + "name": "アイテム", + "categoryCount": 15 + }, + { + "id": 1, + "name": "ライト", + "categoryCount": 3 + } + ] +} +``` + +#### グループ内カテゴリ取得 + +指定したグループ内のカテゴリを取得: + +**リクエスト:** +```json +{ + "type": "item", + "command": "list-group", + "groupId": 0 +} +``` + +**レスポンス:** +```json +{ + "type": "success", + "command": "list-group", + "groupId": 0, + "data": { + "id": 0, + "name": "アイテム", + "categories": [ + { + "id": 0, + "name": "図形", + "itemCount": 25 + }, + { + "id": 1, + "name": "家具", + "itemCount": 42 + } + ] + } +} +``` + +#### カテゴリ内アイテム取得 + +指定したカテゴリ内のすべてのアイテムを取得: + +**リクエスト:** +```json +{ + "type": "item", + "command": "list-category", + "groupId": 0, + "categoryId": 0 +} +``` + +**レスポンス:** +```json +{ + "type": "success", + "command": "list-category", + "groupId": 0, + "categoryId": 0, + "data": { + "id": 0, + "name": "図形", + "groupId": 0, + "items": [ + { + "id": 0, + "name": "スフィア(通常)", + "properties": { + "isAnime": false, + "isScale": true, + "hasColor": true, + "colorSlots": 3, + "hasPattern": false, + "patternSlots": 0, + "isEmission": false, + "isGlass": false, + "bones": 0, + "childRoot": "" + } + } + ] + } +} +``` + ### 📝 Update(オブジェクト変更) #### Transform更新 diff --git a/README.md b/README.md index 33e9d15..d08fcd3 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,10 @@ All commands and responses use JSON format. ### Table of Contents - [🏓 Ping-Pong (Connection Test)](#-ping-pong-connection-test) - [🌲 Tree (Scene Structure)](#-tree-scene-structure) +- [📦 Item (Item Catalog)](#-item-item-catalog) + - [List Groups](#list-groups) + - [List Group Categories](#list-group-categories) + - [List Category Items](#list-category-items) - [🔄 Update (Object Properties)](#-update-object-properties) - [Update Transform](#update-transform) - [Update Item Color](#update-item-color) @@ -148,6 +152,127 @@ Retrieve the complete scene object hierarchy: ] ``` +### 📦 Item (Item Catalog) + +Retrieve information about all available items that can be added to the scene. Items are organized in a hierarchical structure: Groups → Categories → Items. + +#### List Groups + +Get a list of all item groups: + +**Request:** +```json +{ + "type": "item", + "command": "list-groups" +} +``` + +**Response:** +```json +{ + "type": "success", + "command": "list-groups", + "data": [ + { + "id": 0, + "name": "Items", + "categoryCount": 15 + }, + { + "id": 1, + "name": "Lights", + "categoryCount": 3 + } + ] +} +``` + +#### List Group Categories + +Get categories within a specific group: + +**Request:** +```json +{ + "type": "item", + "command": "list-group", + "groupId": 0 +} +``` + +**Response:** +```json +{ + "type": "success", + "command": "list-group", + "groupId": 0, + "data": { + "id": 0, + "name": "Items", + "categories": [ + { + "id": 0, + "name": "Shapes", + "itemCount": 25 + }, + { + "id": 1, + "name": "Furniture", + "itemCount": 42 + } + ] + } +} +``` + +#### List Category Items + +Get all items within a specific category: + +**Request:** +```json +{ + "type": "item", + "command": "list-category", + "groupId": 0, + "categoryId": 0 +} +``` + +**Response:** +```json +{ + "type": "success", + "command": "list-category", + "groupId": 0, + "categoryId": 0, + "data": { + "id": 0, + "name": "Shapes", + "groupId": 0, + "items": [ + { + "id": 0, + "name": "Sphere (Normal)", + "properties": { + "isAnime": false, + "isScale": true, + "hasColor": true, + "colorSlots": 3, + "hasPattern": false, + "patternSlots": 0, + "isEmission": false, + "isGlass": false, + "bones": 0, + "childRoot": "" + } + } + ] + } +} +``` + ### 📝 Update (Modify Objects) #### Update Transform diff --git a/notebooks/box.ipynb b/notebooks/box.ipynb new file mode 100644 index 0000000..5ba22c4 --- /dev/null +++ b/notebooks/box.ipynb @@ -0,0 +1,203 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "6287d4f5", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import json\n", + "import nest_asyncio\n", + "import asyncio\n", + "import websockets\n", + "import numpy as np\n", + "import math\n", + "import random\n", + "import colorsys\n", + "from tqdm.notebook import tqdm\n", + "nest_asyncio.apply()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f080eaaf", + "metadata": {}, + "outputs": [], + "source": [ + "async def websocket_test(payload, indent=None, quiet=False):\n", + " uri = \"ws://127.0.0.1:8765/ws\"\n", + " async with websockets.connect(uri) as ws:\n", + " await ws.send(json.dumps(payload))\n", + " if not quiet:\n", + " print(\"✅ send:\", payload)\n", + "\n", + " try:\n", + " # 5 秒以内に返事が来なければ TimeoutError\n", + " response = await asyncio.wait_for(ws.recv(), timeout=5)\n", + " if not quiet:\n", + " if indent:\n", + " print(\"📨 recv: \", json.dumps(json.loads(response), indent=indent, ensure_ascii=False))\n", + " else:\n", + " print(\"📨 recv:\", response)\n", + " return json.loads(response)\n", + " except asyncio.TimeoutError:\n", + " print(\"⏰ タイムアウト(5 秒以内にメッセージが来ませんでした)\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "b30fb5c4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ send: {'type': 'tree'}\n", + "📨 recv: [{\"name\":\"篠崎 遥\",\"objectInfo\":{\"id\":0,\"type\":\"OCICharFemale\"},\"children\":[]},{\"name\":\"center\",\"objectInfo\":{\"id\":2212,\"type\":\"OCIFolder\"},\"children\":[{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2213,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2215,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2217,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2219,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2221,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2223,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2225,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2227,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2229,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2231,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2233,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2235,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2237,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2239,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2241,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2243,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2245,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2247,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2249,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2251,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2253,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2255,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2257,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2259,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2261,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2263,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2265,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2267,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2269,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2271,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2273,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2275,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2277,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2279,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2281,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2283,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2285,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2287,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2289,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2291,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2293,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2295,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2297,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2299,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2301,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2303,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2305,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2307,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2309,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2311,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2313,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2315,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2317,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2319,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2321,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2323,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2325,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2327,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2329,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2331,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2333,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2335,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2337,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2339,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2341,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2343,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2345,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2347,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2349,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2351,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2353,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2355,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2357,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2359,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2361,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2363,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2365,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2367,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2369,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2371,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2373,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2375,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2377,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2379,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2381,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2383,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2385,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2387,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2389,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2391,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2393,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2395,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2397,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2399,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2401,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2403,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2405,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2407,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2409,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2411,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2413,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2415,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2417,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2419,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2421,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2423,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2425,\"type\":\"OCIItem\"},\"children\":[]},{\"name\":\"キューブ(通常)\",\"objectInfo\":{\"id\":2427,\"type\":\"OCIItem\"},\"children\":[]}]}]\n", + "✅ send: {'type': 'delete', 'id': 2212}\n", + "📨 recv: {\"type\":\"success\",\"message\":\"Object 2212 deleted successfully\"}\n", + "✅ send: {'type': 'add', 'command': 'folder', 'name': 'center'}\n", + "📨 recv: {\"type\":\"success\",\"message\":\"Folder added successfully with name: center\",\"objectId\":2212}\n", + "✅ send: {'type': 'update', 'command': 'transform', 'id': 2212, 'pos': [0.0, 1.5, 0.5]}\n", + "📨 recv: {\"type\":\"success\",\"message\":\"Transform updated for object ID 2212\"}\n" + ] + } + ], + "source": [ + "payload = {\n", + " \"type\": \"tree\",\n", + "}\n", + "tree = await websocket_test(payload)\n", + "\n", + "for item in tree:\n", + " if item[\"name\"] == \"center\":\n", + " payload = {\n", + " \"type\": \"delete\",\n", + " \"id\": item[\"objectInfo\"][\"id\"],\n", + " }\n", + " await websocket_test(payload)\n", + "\n", + "payload = {\n", + " \"type\": \"add\",\n", + " \"command\": \"folder\",\n", + " \"name\": \"center\"\n", + "}\n", + "response = await websocket_test(payload)\n", + "center_id = response[\"objectId\"]\n", + "\n", + "payload = {\n", + " \"type\": \"update\",\n", + " \"command\": \"transform\",\n", + " \"id\": center_id,\n", + " \"pos\": [0.0, 1.5, 0.5],\n", + "}\n", + "response = await websocket_test(payload)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "7d3ecb1c", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "b22b79937ef04580b3dca114fd534344", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/1080 [00:00 sendCallback) : base(sendCallback) { } + + public void Handle(ItemCommand cmd) + { + ApplyItemCommand(cmd); + } + + private void ApplyItemCommand(ItemCommand cmd) + { + try + { + switch (cmd.command?.ToLower()) + { + case "list-groups": + HandleListGroups(cmd); + break; + case "list-group": + HandleListGroup(cmd); + break; + case "list-category": + HandleListCategory(cmd); + break; + case "catalog": + HandleCatalog(cmd); + break; + default: + KKStudioSocketPlugin.Logger.LogWarning($"Unsupported item command: {cmd.command}"); + SendErrorResponse($"Unsupported item command: {cmd.command}"); + break; + } + } + catch (Exception ex) + { + KKStudioSocketPlugin.Logger.LogError($"Item command error: {ex.Message}"); + SendErrorResponse($"Item command error: {ex.Message}"); + } + } + + private void HandleListGroups(ItemCommand cmd) + { + try + { + var groups = GetItemGroups(); + + var response = new + { + type = "success", + command = "list-groups", + data = groups + }; + + Send(JsonConvert.SerializeObject(response)); + KKStudioSocketPlugin.Logger.LogDebug($"Item groups retrieved: {groups.Count} groups"); + } + catch (Exception ex) + { + KKStudioSocketPlugin.Logger.LogError($"List groups error: {ex.Message}"); + SendErrorResponse($"List groups error: {ex.Message}"); + } + } + + private void HandleListGroup(ItemCommand cmd) + { + try + { + if (cmd.groupId < 0) + { + SendErrorResponse("Group ID is required and must be non-negative"); + return; + } + + var groupData = GetGroupData(cmd.groupId); + if (groupData == null) + { + SendErrorResponse($"Group with ID {cmd.groupId} not found"); + return; + } + + var response = new + { + type = "success", + command = "list-group", + groupId = cmd.groupId, + data = groupData + }; + + Send(JsonConvert.SerializeObject(response)); + KKStudioSocketPlugin.Logger.LogDebug($"Group {cmd.groupId} data retrieved"); + } + catch (Exception ex) + { + KKStudioSocketPlugin.Logger.LogError($"List group error: {ex.Message}"); + SendErrorResponse($"List group error: {ex.Message}"); + } + } + + private void HandleListCategory(ItemCommand cmd) + { + try + { + if (cmd.groupId < 0 || cmd.categoryId < 0) + { + SendErrorResponse("Both group ID and category ID are required and must be non-negative"); + return; + } + + var categoryData = GetCategoryData(cmd.groupId, cmd.categoryId); + if (categoryData == null) + { + SendErrorResponse($"Category {cmd.categoryId} in group {cmd.groupId} not found"); + return; + } + + var response = new + { + type = "success", + command = "list-category", + groupId = cmd.groupId, + categoryId = cmd.categoryId, + data = categoryData + }; + + Send(JsonConvert.SerializeObject(response)); + KKStudioSocketPlugin.Logger.LogDebug($"Category {cmd.categoryId} in group {cmd.groupId} data retrieved"); + } + catch (Exception ex) + { + KKStudioSocketPlugin.Logger.LogError($"List category error: {ex.Message}"); + SendErrorResponse($"List category error: {ex.Message}"); + } + } + + private void HandleCatalog(ItemCommand cmd) + { + try + { + var catalog = BuildItemCatalog(); + var jsonResponse = JsonConvert.SerializeObject(catalog); + + KKStudioSocketPlugin.Logger.LogDebug($"Item catalog retrieved with {catalog.Count} groups"); + Send(jsonResponse); + } + catch (Exception ex) + { + KKStudioSocketPlugin.Logger.LogError($"Item catalog retrieval error: {ex.Message}"); + SendErrorResponse($"Item catalog retrieval error: {ex.Message}"); + } + } + + private List BuildItemCatalog() + { + var catalog = new List(); + + // Get singleton Info instance + var info = Singleton.Instance; + if (info?.dicItemGroupCategory == null) + { + KKStudioSocketPlugin.Logger.LogWarning("Item group category dictionary is null"); + return catalog; + } + + // Iterate through all groups + foreach (var groupPair in info.dicItemGroupCategory) + { + int groupId = groupPair.Key; + var groupInfo = groupPair.Value; + + var groupData = new + { + id = groupId, + name = groupInfo.name, + type = "group", + categories = BuildCategoriesForGroup(groupId, groupInfo) + }; + + catalog.Add(groupData); + } + + return catalog; + } + + private List BuildCategoriesForGroup(int groupId, Info.GroupInfo groupInfo) + { + var categories = new List(); + + if (groupInfo.dicCategory == null) + { + return categories; + } + + // Iterate through categories in this group + foreach (var categoryPair in groupInfo.dicCategory) + { + int categoryId = categoryPair.Key; + string categoryName = categoryPair.Value; + + var categoryData = new + { + id = categoryId, + name = categoryName, + type = "category", + items = BuildItemsForCategory(groupId, categoryId) + }; + + categories.Add(categoryData); + } + + return categories; + } + + private List BuildItemsForCategory(int groupId, int categoryId) + { + var items = new List(); + + var info = Singleton.Instance; + + // Check if this group/category combination exists in dicItemLoadInfo + if (info?.dicItemLoadInfo == null || + !info.dicItemLoadInfo.ContainsKey(groupId) || + !info.dicItemLoadInfo[groupId].ContainsKey(categoryId)) + { + return items; + } + + // Iterate through items in this category + foreach (var itemPair in info.dicItemLoadInfo[groupId][categoryId]) + { + int itemId = itemPair.Key; + var itemInfo = itemPair.Value; + + var itemData = new + { + id = itemId, + name = itemInfo.name, + type = "item", + groupId = groupId, + categoryId = categoryId, + properties = new + { + isAnime = itemInfo.isAnime, + isScale = itemInfo.isScale, + isEmission = itemInfo.isEmission, + isGlass = itemInfo.isGlass, + hasColor = itemInfo.isColor, + hasPattern = itemInfo.isPattren, + colorSlots = itemInfo.color?.Length ?? 0, + patternSlots = itemInfo.pattren?.Length ?? 0, + childRoot = itemInfo.childRoot, + bones = itemInfo.bones?.Count ?? 0 + }, + file = new + { + manifest = itemInfo.manifest, + bundlePath = itemInfo.bundlePath, + fileName = itemInfo.fileName + } + }; + + items.Add(itemData); + } + + return items; + } + + private List GetItemGroups() + { + var groups = new List(); + + var info = Singleton.Instance; + if (info?.dicItemGroupCategory == null) + { + return groups; + } + + foreach (var groupPair in info.dicItemGroupCategory) + { + int groupId = groupPair.Key; + var groupInfo = groupPair.Value; + + var groupData = new + { + id = groupId, + name = groupInfo.name, + categoryCount = groupInfo.dicCategory?.Count ?? 0 + }; + + groups.Add(groupData); + } + + return groups.OrderBy(g => { + var obj = g.GetType().GetProperty("id").GetValue(g, null); + return (int)obj; + }).ToList(); + } + + private object GetGroupData(int groupId) + { + var info = Singleton.Instance; + if (info?.dicItemGroupCategory == null || !info.dicItemGroupCategory.ContainsKey(groupId)) + { + return null; + } + + var groupInfo = info.dicItemGroupCategory[groupId]; + var categories = new List(); + + if (groupInfo.dicCategory != null) + { + foreach (var categoryPair in groupInfo.dicCategory) + { + int categoryId = categoryPair.Key; + string categoryName = categoryPair.Value; + + // Count items in this category + int itemCount = 0; + if (info.dicItemLoadInfo?.ContainsKey(groupId) == true && + info.dicItemLoadInfo[groupId]?.ContainsKey(categoryId) == true) + { + itemCount = info.dicItemLoadInfo[groupId][categoryId].Count; + } + + var categoryData = new + { + id = categoryId, + name = categoryName, + itemCount = itemCount + }; + + categories.Add(categoryData); + } + } + + return new + { + id = groupId, + name = groupInfo.name, + categories = categories.OrderBy(c => { + var obj = c.GetType().GetProperty("id").GetValue(c, null); + return (int)obj; + }).ToList() + }; + } + + private object GetCategoryData(int groupId, int categoryId) + { + var info = Singleton.Instance; + + // Check if group/category combination exists + if (info?.dicItemLoadInfo == null || + !info.dicItemLoadInfo.ContainsKey(groupId) || + !info.dicItemLoadInfo[groupId].ContainsKey(categoryId)) + { + return null; + } + + var items = new List(); + + foreach (var itemPair in info.dicItemLoadInfo[groupId][categoryId]) + { + int itemId = itemPair.Key; + var itemInfo = itemPair.Value; + + var itemData = new + { + id = itemId, + name = itemInfo.name, + properties = new + { + isAnime = itemInfo.isAnime, + isScale = itemInfo.isScale, + isEmission = itemInfo.isEmission, + isGlass = itemInfo.isGlass, + hasColor = itemInfo.isColor, + hasPattern = itemInfo.isPattren, + colorSlots = itemInfo.color?.Length ?? 0, + patternSlots = itemInfo.pattren?.Length ?? 0, + childRoot = itemInfo.childRoot, + bones = itemInfo.bones?.Count ?? 0 + } + }; + + items.Add(itemData); + } + + // Get category name + string categoryName = ""; + if (info.dicItemGroupCategory?.ContainsKey(groupId) == true) + { + var groupInfo = info.dicItemGroupCategory[groupId]; + if (groupInfo.dicCategory?.ContainsKey(categoryId) == true) + { + categoryName = groupInfo.dicCategory[categoryId]; + } + } + + return new + { + id = categoryId, + name = categoryName, + groupId = groupId, + items = items.OrderBy(i => { + var obj = i.GetType().GetProperty("id").GetValue(i, null); + return (int)obj; + }).ToList() + }; + } + + private void SendErrorResponse(string message) + { + var response = new { type = "error", message = message }; + Send(JsonConvert.SerializeObject(response)); + } + } +} \ No newline at end of file diff --git a/src/KKStudioSocket.Core/KKStudioSocket.Core.projitems b/src/KKStudioSocket.Core/KKStudioSocket.Core.projitems index 89811d2..d8633ba 100644 --- a/src/KKStudioSocket.Core/KKStudioSocket.Core.projitems +++ b/src/KKStudioSocket.Core/KKStudioSocket.Core.projitems @@ -19,5 +19,6 @@ + \ No newline at end of file diff --git a/src/KKStudioSocket.Core/KKStudioSocketPlugin.cs b/src/KKStudioSocket.Core/KKStudioSocketPlugin.cs index 0eb2ffe..230023f 100644 --- a/src/KKStudioSocket.Core/KKStudioSocketPlugin.cs +++ b/src/KKStudioSocket.Core/KKStudioSocketPlugin.cs @@ -149,6 +149,21 @@ protected override void OnMessage(MessageEventArgs e) KKStudioSocketPlugin.Logger.LogDebug("Tree handler executed"); break; + case "item": + KKStudioSocketPlugin.Logger.LogDebug("Handling item command"); + var itemCmd = JsonConvert.DeserializeObject(e.Data); + if (itemCmd != null) + { + var itemHandler = new ItemCommandHandler(Send); + itemHandler.Handle(itemCmd); + } + else + { + KKStudioSocketPlugin.Logger.LogWarning("Failed to parse item command"); + } + KKStudioSocketPlugin.Logger.LogDebug("Item handler executed"); + break; + case "update": var updateCmd = JsonConvert.DeserializeObject(e.Data); if (updateCmd != null) @@ -316,4 +331,12 @@ public class CameraCommand : BaseCommand public int cameraId; // For switching to specific camera object } + [Serializable] + public class ItemCommand : BaseCommand + { + public string command; + public int groupId = -1; + public int categoryId = -1; + } + } \ No newline at end of file