---
title: ZEPETO Mannequin
slug: world-sdk-guide-ja/zepeto-mannequin
docTags: 
createdAt: 2024-09-20T13:03:30.714Z
---

ZEPETO Mannequinは、着せ替え/販売機能をサーポートするマネキンAPIパッケージです。

- オリジナル制作アイテムをワールドで販売できるようになります。
- ZEPETOアバターのNPCに指定したコーデを着せたマネキンを作成できます。
- マネキン又はオブジェクトとインタラクションし、ファッションアイテムを購入できます。

::embed[]{url="https://www.youtube.com/embed/sag4H7B5oM4"}

## STEP 1 : インストール

Window → Package Manager → を選択し、まず ZEPETO.World パッケージ 1.21.15 以降をインストールしてください。

その後、ZEPETO.Module 1.0.8 パッケージをインストールしてください。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/udZX8YuF8hT6tVw-JlCU4_image.png)

:::hint{type="danger"}
❗️ **注意事項**

- パフォーマンス向上の一環として、スタンドアロン パッケージは ZEPETO.Module 1.0.8 以降のバージョンのパッケージに統合されました。
  - 以前にインストールした ZEPETO.Mannquin パッケージを削除してください。
  - 既存のパッケージを削除した後、ZEPETO.Module パッケージ バージョン 1.0.8 以降をインストールしてください。
:::


STEP 2 : マネキンに設定するアイテムIDを確認する
-----------------------------

:::hint{type="success"}
👍 **アイテムID確認する方法**

- ZEPETO Studioでアイテム商品をクリックするとポップアップするURLで確認できます。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/yf-uLckQ1oUjFdhFUvKJa_image.png)

- アイテムIDを乱数形式でコピーし、Unityエディターに貼り付け、その前に「CR\_」を貼り付けます。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/m9_sRwGW49zqKSVmGoCWm_image.png)
:::

:::hint{type="info"}
📘 アイテム制作が初めての方は、次のガイドを参考にしてください \[[Create Your Item](https://docs.zepeto.me/studio/lang-id/docs/welcome)]
:::

## STEP 3 : マネキンの設定

マネキンオブジェクトは、全部で３つの方法で制作できます。

:::hint{type="danger"}
**❗️ 注意事項**

- ZEPETO Mannequinはご自身のオリジナル制作のアイテムだけがワールドに設定/販売する事ができます。
- 審査で拒否されたアイテムは販売する事ができません。
- Unityのログインが必須の機能です。
- マネキン機能を含んだパッケージをPublishする際も編集ログインが必要です。
- ZEPETO Template、ZEPETO Model Typeのマネキンを使用する場合、マネキンの数だけゼペトキャラクターが入場した程度のリソースを占めて、最適化に影響を与えることができます。
  - もし、ワールド内に多くのゼペットキャラクター形状のマネキンを入れなければならない場合は、Simple Typeのマネキンを選択した後、オブジェクトとして [ZEPETO BaseModel](https://studio.zepeto.me/console/download/652892d3a80a9f5505ed888f) を活用することをお勧めします。
:::

### ÉTAPE 3-1 : Type simple

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/AnIz9yZZwU8C4YF0ndlWk_image.png)

とても基本的な方式です。Mannequin次式で特定オブジェクトを追加し外形を調整できます。

1. 対話するオブジェクトを追加します。
2. オブジェクトにインタラクションする為、Colliderを必ず追加しなければなりません。

- is Tringeerチェックは必須です。万が一チェックが確認できなければ、自動的にトリッカーとして認識処理されます。
- Colliderを追加しないままマネキンのコンポーネットを追加する際、下記のような警告が出てきます。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/fK_5Ha1-AuFTtChPiw30n_image.png)

1. オブジェクトにマネキンコンポーネントを追加します。
2. Please set the following in the inspector.
   - icon: 基本的にはハンガーアイコンです。カスタムアイコンに変更可能です。
   - icon position: 基本的にマネキンコンポーネントがあるオブジェクトの位置にアイコンが現れます。
     - position objectを追加後、値を入れると思い通りの位置に現れます。
   - ids: 販売したいファッションアイテムIDを作成できます。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/rlyVQG8Ki9R23_qRnXFa2_image.png)

1. Empty Objectを追加し、オブジェクトの名前をMannequinScriptで作成します。
2. ZEPETO> Typescriptを追加し、スクリプトの名前をMannequinScriptで作成します。
3. 以下内容通りに作成します。

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { ZepetoPlayers, SpawnInfo } from 'ZEPETO.Character.Controller';
import { WorldService } from 'ZEPETO.World';
import { ItemContentsRequest, Mannequin, MannequinComponent, MannequinInteractable, MannequinPreviewer } from 'ZEPETO.Mannequin';
import { Object } from 'UnityEngine';

export default class MannequinScript extends ZepetoScriptBehaviour {

    private _previewer: MannequinPreviewer;

    Start() {
        // Code that creates a ZEPETO character based on the logged in ID  
        // ZepetoPlayers.instance.CreatePlayerWithUserId(WorldService.userId, SpawnInfo.Default, true);
      
        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            const character = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character;
            // Add Mannequin Interactable Component
            character.gameObject.AddComponent<MannequinInteractable>();
        });

        // Find all Mannequin components
        const mannequins = Object.FindObjectsOfType<MannequinComponent>();

        mannequins.forEach(m => {
            // Enter the Collider
            m.onActive.AddListener(contents => {
                Mannequin.OpenUI(contents);
                const zepetoContext = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character.Context;
                this._previewer = new MannequinPreviewer(zepetoContext, contents);
                this._previewer.PreviewContents();
            });

            // Exit the Collider
            m.onCancel.AddListener(() => {
                Mannequin.CloseUI();
                this._previewer?.ResetContents();
            });
        });
    }
}
```

1. スクリプトをオブジェクトに追加し、\[▶︎(play)]ボタンを押して実行します。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/p4Wihq0NAPHpmq67w9MNL_image.png)

### STEP 3-2 : ZEPETO Model Type

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/48aFFWnmATCvwLT3FLf6N_image.png)

ZEPETOアバターのNPCにアイテムIDを追加し、マネキン外形を変更することができます。

1. Empty Objectを生成して、名前をMannequinで作成します。
2. オブジェクトにインタラクションする為、Colliderを必ず追加しなければなりません。

- is Tringeerチェックは必須です。万が一チェックが確認できなければ、自動的にトリッカーとして認識処理されます。

1. オブジェクトにマネキンコンポーネントを追加します。
2. Please set the following in the inspector.
   - icon: 基本的にはハンガーアイコンです。カスタムアイコンに変更可能です。
   - icon position: 基本的にマネキンコンポーネントがあるオブジェクトの位置にアイコンが現れます。
     - position objectを追加後、値を入れると思い通りの位置に現れます。
   - ids: 販売したいファッションアイテムIDを作成できます。
   - pose: ポーズを選択し、設置できます。
     - 今後、思い通りのポーズをポーズid形態に提供する予定です。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/PCaWKswD5g7ACVXzEdwIZ_image.png)

:::hint{type="success"}
👍 シーンにマネキン スクリプトが既にある場合は、後の手順を省略できます。
:::

1. Empty Objectを追加し、オブジェクトの名前をMannequinScriptで作成します。
2. ZEPETO> Typescriptを追加し、スクリプトの名前をMannequinScriptで作成します。
3. 以下内容通りに作成します。

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { ZepetoPlayers, SpawnInfo } from 'ZEPETO.Character.Controller';
import { WorldService } from 'ZEPETO.World';
import { ItemContentsRequest, Mannequin, MannequinComponent, MannequinInteractable, MannequinPreviewer } from 'ZEPETO.Mannequin';
import { Object } from 'UnityEngine';

export default class MannequinScript extends ZepetoScriptBehaviour {

    private _previewer: MannequinPreviewer;

    Start() {
        // Code that creates a ZEPETO character based on the logged in ID  
        // ZepetoPlayers.instance.CreatePlayerWithUserId(WorldService.userId, SpawnInfo.Default, true);
      
        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            const character = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character;
            // Add Mannequin Interactable Component
            character.gameObject.AddComponent<MannequinInteractable>();
        });

        // Find all Mannequin components
        const mannequins = Object.FindObjectsOfType<MannequinComponent>();

        mannequins.forEach(m => {
            // Enter the Collider
            m.onActive.AddListener(contents => {
                Mannequin.OpenUI(contents);
                const zepetoContext = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character.Context;
                this._previewer = new MannequinPreviewer(zepetoContext, contents);
                this._previewer.PreviewContents();
            });

            // Exit the Collider
            m.onCancel.AddListener(() => {
                Mannequin.CloseUI();
                this._previewer?.ResetContents();
            });
        });
    }
}
```

1. スクリプトをオブジェクトに追加し、\[▶︎(play)]ボタンを押して実行します。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/EMJv5_sf6pElRT4-KznKk_image.png)

### STEP 3-3 : ZEPETO Template Type

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/zok-bPf4RVy7CNBT4hyO__image.png)

ZEPETO IDを入力したら、そのアバターが着用しているコーデをマネキンが着用し登場します。ただし、自分で作ったオリジナルアイテムでない場合はコーデは確認できないです。

1. Empty Objectを生成して、名前をMannequinで作成します。
2. オブジェクトにインタラクションする為、Colliderを必ず追加しなければなりません。

- is Tringeerチェックは必須です。万が一チェックが確認できなければ、自動的にトリッカーとして認識処理されます。

1. オブジェクトにマネキンコンポーネントを追加します。
2. Please set the following in the inspector.
   - icon: 基本的にはハンガーアイコンです。カスタムアイコンに変更可能です。
   - icon position: 基本的にマネキンコンポーネントがあるオブジェクトの位置にアイコンが現れます。
     - position objectを追加後、値を入れると思い通りの位置に現れます。
   - zepeto id: ZEPETO IDを入力してください。
   - pose: ポーズを選択し、設置できます。
     - 今後、思い通りのポーズをポーズid形態に提供する予定です。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/ESw381jcbxc0BcB5YHFBd_image.png)

:::hint{type="success"}
👍 シーンにマネキン スクリプトが既にある場合は、後の手順を省略できます。
:::

1. Empty Objectを追加し、オブジェクトの名前をMannequinScriptで作成します。
2. ZEPETO> Typescriptを追加し、スクリプトの名前をMannequinScriptで作成します。
3. 以下内容通りに作成します。

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { ZepetoPlayers, SpawnInfo } from 'ZEPETO.Character.Controller';
import { WorldService } from 'ZEPETO.World';
import { ItemContentsRequest, Mannequin, MannequinComponent, MannequinInteractable, MannequinPreviewer } from 'ZEPETO.Mannequin';
import { Object } from 'UnityEngine';

export default class MannequinScript extends ZepetoScriptBehaviour {

    private _previewer: MannequinPreviewer;

    Start() {
        // Code that creates a ZEPETO character based on the logged in ID  
        // ZepetoPlayers.instance.CreatePlayerWithUserId(WorldService.userId, SpawnInfo.Default, true);

        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            const character = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character;
            // Add Mannequin Interactable Component
            character.gameObject.AddComponent<MannequinInteractable>();
        });

        // Find all Mannequin components
        const mannequins = Object.FindObjectsOfType<MannequinComponent>();

        mannequins.forEach(m => {
            // Enter the Collider
            m.onActive.AddListener(contents => {
                Mannequin.OpenUI(contents);
                const zepetoContext = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character.Context;
                this._previewer = new MannequinPreviewer(zepetoContext, contents);
                this._previewer.PreviewContents();
            });

            // Exit the Collider
            m.onCancel.AddListener(() => {
                Mannequin.CloseUI();
                this._previewer?.ResetContents();
            });
        });
    }
}
```

1. スクリプトをオブジェクトに追加し、\[▶︎(play)]ボタンを押して実行します。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/-8GDERTsjJZ17Qmaj8W0V_image.png)

## STEP 4 : マネキン販売を使用

マネキン設置を正しく終えたら、マネキンオブジェクトのCollider領域内に入った際にインタラクション出来るアイコンが現れます。

アイコンをクリックした場合、購入ポップアップが開き、マネキンに設置したアイテムが現れます。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/7xzVgtpM7ESbo_E0Tnw7Z_image.png)

アイテムをクリックしたら、着せ替えが出来ます。

- 既に保有したアイテムは、価格の代わりにチェック表示が現れます。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/7UQQC_pl5Rv7HVtK8FZuU_image.png)

マネキンオブジェクトのCollider 領域から出た際、着せ替えが消去され、本来のコーデに戻ります。

| **テスト環境**                             | **購入処理**                                                                                                                                                                                                            |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Unity Editorで購入                       | プレイ中に購入が成功しコーデが変更できますが、プレイ終了すると本来の状態に戻ります。                                                                                                                                                                          |
| QRコードモバイルテスト環境での購入                    | この場合は、実際のサーバーに接続してテストをするので、購入成功時、コーデが変更となりワールドを退出した際にも変更されたコーデが維持されます。<br /><br />**また、購入成功時に、実際のサーバーでアイテムを購入することになりますので、実際のアカウントが保有するジェムが差し引かれ、衣装アイテムを所持することになります。購入した衣装を任意に捨てたり削除することはできませんので、テスト時に慎重に購入してください。** |
| ZEPETO Studioにパッケージ登録後、テストリンクから接続して購入 | この場合は、実際のサーバーに接続してテストをするので、購入成功時、コーデが変更となりワールドを退出した際にも変更されたコーデが維持されます。<br /><br />**また、購入成功時に、実際のサーバーでアイテムを購入することになりますので、実際のアカウントが保有するジェムが差し引かれ、衣装アイテムを所持することになります。購入した衣装を任意に捨てたり削除することはできませんので、テスト時に慎重に購入してください。** |


STEP 5 : マネキンマルチプレイの同期化
-----------------------

マルチプレイは、他のプレイヤーがマネキン機能を使用して着用した衣装を同期させる必要があります。

:::hint{type="success"}
👍 以下の内容を作業する前に、基本的なマルチプレイセッティングを完了させてください。
:::

1. クライアントスクリプトを追加します。ZEPETO > Typescript を追加して、スクリプトの名前をMannequinControllerに設定します。
2. 以下の内容通りに作成してください。

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { Room } from 'ZEPETO.Multiplay';
import { ClothesPreviewer, ItemContent, ItemContentsRequest, Mannequin, MannequinComponent, MannequinInteractable, MannequinPreviewer } from 'ZEPETO.Mannequin';
import { ZepetoContext } from 'Zepeto';
import { ZepetoPlayer, ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { GameObject, Object, Canvas, WaitForSecondsRealtime, LayerMask } from 'UnityEngine';
import { Player } from 'ZEPETO.Multiplay.Schema';
import { ZepetoWorldMultiplay } from 'ZEPETO.World';
 
class CharacterItem {
    property: string;
    id: string;
}
 
class ChangedItem {
    sessionId: string;
    characterItems: CharacterItem[];
}
 
export default class MannequinController extends ZepetoScriptBehaviour {
    private MESSAGE_TYPE = {
        OnChangedItem: "OnChangedItem",
        SyncChangedItem: "SyncChangedItem",
        CheckChangedItem: "CheckChangedItem"
    }
 
    private multiplay: ZepetoWorldMultiplay;
    private _room: Room;
    private _previewer: MannequinPreviewer
    private _context: ZepetoContext
 
    private _userZepetoContexts: Map<string, ZepetoContext> = new Map<string, ZepetoContext>();
    private _currentMannequinComponent: MannequinComponent = null;
    private _selectMannequinComponent: MannequinComponent = null;
    private _isOpenMannequinUI: boolean = false;
 
    private _basicClothString = "basicCloth" as const;
 
    Start() {
        this.multiplay = Object.FindObjectOfType<ZepetoWorldMultiplay>();
 
        Mannequin.OnOpenedShopUI.AddListener((item) => {
            // When you click OpenShopButton
            this.OpenedShopUI(item)
        });
        Mannequin.OnClosedShopUI.AddListener(() => {
            // When you click CloseShopButton
            this.ClosedShopUI()
        });
        Mannequin.OnSelectedItem.AddListener((itemcontent: ItemContent, select: boolean) => {
            // Action when item is selected
        });
 
        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            const myPlayer = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer;
 
            // Mannequin
            const character = myPlayer.character;
            character.gameObject.AddComponent<MannequinInteractable>();
 
            console.log("local _context set");
            this._context = character.Context;
 
            const mannequins = Object.FindObjectsOfType<MannequinComponent>()
            mannequins.forEach(mannequin => {
                // When you enter mannequin collider
                mannequin.onActive.AddListener(contents => {
                    if (this._currentMannequinComponent != null && this._currentMannequinComponent == mannequin) {
                        return;
                    }
 
                    if (contents == null || contents.length == 0) {
                        console.log("No mannequin data");
                        return;
                    }
 
                    if (this._isOpenMannequinUI) {
                        this.BreakMannequin();
                    }
 
                    this._selectMannequinComponent = mannequin;
                    Mannequin.OpenUI(contents);
                    console.log("onActive");
                });
 
                // [Option] When you leave mannequin collider
                mannequin.onCancel.AddListener( () => {
                    if (this._currentMannequinComponent == null || this._currentMannequinComponent != mannequin) {
                        return;
                    }
 
                    this.BreakMannequin();
                    console.log("onCancel");
                });
 
                let iconCanvas = mannequin.gameObject.GetComponentInChildren<Canvas>(true);
                if (iconCanvas != null) {
                    iconCanvas.gameObject.layer = LayerMask.NameToLayer("UI");
                }
            });
        });
 
        ZepetoPlayers.instance.OnAddedPlayer.AddListener((sessionId: string) => {
            if (ZepetoPlayers.instance.GetPlayer(sessionId).isLocalPlayer) {
                return;
            }
            const userContext = ZepetoPlayers.instance.GetPlayer(sessionId).character.Context;
            this._userZepetoContexts.set(sessionId, userContext);
            this._room.Send(this.MESSAGE_TYPE.CheckChangedItem, sessionId);
        });
        this.multiplay.RoomJoined += (room: Room) => {
            this._room = room;
            this.AddMessageHandler();
        };
    }
 
    private AddMessageHandler() {
        // [Option] Synchronize each player's clothes
        this._room.AddMessageHandler<ChangedItem>(this.MESSAGE_TYPE.SyncChangedItem, message => {
            console.log("syncChangedItem");
            if (message == null) {
                return;
            }
 
            if (false == this._userZepetoContexts.has(message.sessionId)) {
                return;
            }
 
            let itemContents: ItemContent[] = [];
 
            for (const characterItem of message.characterItems) {
                let itemContent: ItemContent = new ItemContent();
                itemContent.id = characterItem.id;
                itemContent.property = parseInt(characterItem.property);
 
                if (itemContent.id == this._basicClothString) {
                    itemContent.id = "";
                }
 
                itemContents.push(itemContent);
            }
            let clothesPreviewer:ClothesPreviewer = new ClothesPreviewer(this._userZepetoContexts.get(message.sessionId),itemContents);
            clothesPreviewer.PreviewContents();
        });
    }
 
    private ClosedShopUI() {
        this._currentMannequinComponent = null;
        this._isOpenMannequinUI = false;
    }
 
    private OpenedShopUI(items: ItemContent[]) {
        this._isOpenMannequinUI = true;
        this._currentMannequinComponent = this._selectMannequinComponent;
 
        this._previewer = new MannequinPreviewer(this._context, items);
        this._previewer.OnChanged.AddListener((changeValues) => {
            let characterItems: CharacterItem[] = [];
 
            for (const changeValue of changeValues) {
                let characterItem: CharacterItem = new CharacterItem();
                characterItem.id = changeValue.id;
                characterItem.property = changeValue.property.toString();
 
                if (characterItem.id == "") {
                    characterItem.id = this._basicClothString;
                }
                characterItems.push(characterItem);
            }
            this._room.Send(this.MESSAGE_TYPE.OnChangedItem, characterItems);
        });
 
        this._previewer.PreviewContents();
    }
 
    public BreakMannequin() {
        Mannequin.CloseUI();
        if (this._previewer) {
            this._previewer.ResetContents();
            this._previewer = null;
        }
 
        this._currentMannequinComponent = null;
        this._isOpenMannequinUI = false;
    }
 
}
```

1. Hierarchy > Empty Objectを作成して、名前をMannequinControllerに設定します。
2. 先ほど作成したスクリプトをMannequinControllerに追加してください。

![](https://api.archbee.com/api/optimize/xv-TGeWVTX2GDZMFGOf1Y/msOB-x0FVBpRhk4dRJIiw_image.png)



1. 次に、World.Multiplay > index.tsで、以下の内容を参考にサーバーコードを作成してください。

```typescript
import { Sandbox, SandboxOptions, SandboxPlayer } from 'ZEPETO.Multiplay';
import { Player, Transform, Vector3 } from 'ZEPETO.Multiplay.Schema';
 
class CharacterItem {
    property: string;
    id: string;
}
 
class ChangedItem {
    sessionId: string;
    characterItems: CharacterItem[];
}
 
enum Cloth {
    TOP = "19",
    BOTTOM = "20" ,
    DRESS = "22"
}
 
export default class extends Sandbox {
    private MESSAGE_TYPE = {
        OnChangedItem: "OnChangedItem",
        SyncChangedItem: "SyncChangedItem",
        CheckChangedItem: "CheckChangedItem"
    }
     
    // Map<sessionId, Map<CharacterItem.property, CharacterItem.id>>
    private ChangedItems: Map<string, Map<string, string>>;
 
    onCreate(options: SandboxOptions) {
        // Called when the Room object is created.
        // Handle the state or data initialization of the Room object.
        this.onMessage("onChangedTransform", (client, message) => {
            const player = this.state.players.get(client.sessionId);
 
            const transform = new Transform();
            transform.position = new Vector3();
            transform.position.x = message.position.x;
            transform.position.y = message.position.y;
            transform.position.z = message.position.z;
 
            transform.rotation = new Vector3();
            transform.rotation.x = message.rotation.x;
            transform.rotation.y = message.rotation.y;
            transform.rotation.z = message.rotation.z;
 
            player.transform = transform;
        });
        this.onMessage("onChangedState", (client, message) => {
            const player = this.state.players.get(client.sessionId);
            player.state = message.state;
            player.subState = message.subState; // Character Controller V2
        });
 
        // Mannequin server code
        this.ChangedItems = new Map<string, Map<string, string>>();
 
        this.onMessage<CharacterItem[]>(this.MESSAGE_TYPE.OnChangedItem, (client, message) => {
            // Overwrite clothes and set new parts
            if (this.ChangedItems.has(client.userId)) {
                const changedItemMap = this.ChangedItems.get(client.userId);
                for (const characterItem of message) {
                    if (characterItem.property == Cloth.DRESS) {
                        // In the case of a dress (22), remove the top (19) and bottom (20)
                        if (changedItemMap.has(Cloth.TOP)) {
                            changedItemMap.delete(Cloth.TOP);
                        }
                        if (changedItemMap.has(Cloth.BOTTOM)) {
                            changedItemMap.delete(Cloth.BOTTOM);
                        }
                    } else if (characterItem.property == Cloth.TOP || characterItem.property == Cloth.BOTTOM) {
                        // Remove the dress if it is a top (19) or bottom (20)
                        if (changedItemMap.has(Cloth.DRESS)) {
                            changedItemMap.delete(Cloth.DRESS);
                        }
                    }
 
                    changedItemMap.set(characterItem.property,characterItem.id);
                    console.log(`OnChangedItem old ${client.userId} : ${characterItem.property} // ${characterItem.id}`);
                }
            } else {
                // Initial registration
                let changedItemMap: Map<string,string> = new Map<string, string>();
                for (const characterItem of message) {
                    changedItemMap.set(characterItem.property,characterItem.id);
                }
                this.ChangedItems.set(client.sessionId,changedItemMap);
            }
 
            let changedItem: ChangedItem = new ChangedItem();
            changedItem.sessionId = client.sessionId;
            changedItem.characterItems = message;
 
            console.log(`OnChangedItem : ${changedItem.sessionId}`);
            for (const characterItem of changedItem.characterItems) {
                console.log(` ::: ${characterItem.property} - ${characterItem.id} `);
            }
            this.broadcast(this.MESSAGE_TYPE.SyncChangedItem, changedItem, {except: client});
        });
 
        this.onMessage<string>(this.MESSAGE_TYPE.CheckChangedItem,(client, message) => {
            if (false == this.ChangedItems.has(message)) {
                return;
            }
 
            let changedItem: ChangedItem = new ChangedItem();
            changedItem.sessionId = client.sessionId;
            changedItem.characterItems = [];
 
            for (const property of this.ChangedItems.get(message).keys()) {
                let characterItem: CharacterItem = new CharacterItem();
                characterItem.property = property;
                characterItem.id = this.ChangedItems.get(message).get(property);
 
                changedItem.characterItems.push(characterItem);
            }
 
            client.send<ChangedItem>(this.MESSAGE_TYPE.SyncChangedItem, changedItem );
        });
 
    }
 
    onJoin(client: SandboxPlayer) {
 
        // Create the player object defined in schemas.json and set the initial value.
        console.log(`[OnJoin] sessionId : ${client.sessionId}, HashCode : ${client.hashCode}, userId : ${client.userId}`)
 
        const player = new Player();
        player.sessionId = client.sessionId;
      
        if (client.userId) {
            player.zepetoUserId = client.userId;
        }
 
        // Manage the Player object using sessionId, a unique key value of the client object.
        // The client can check the information about the player object added by set by adding the add_OnAdd event to the players object.
        this.state.players.set(client.sessionId, player);
    }
 
    async onLeave(client: SandboxPlayer, consented?: boolean) {
 
        // By setting allowReconnection, it is possible to maintain connection for the circuit, but clean up immediately in the basic guide.
        // The client can check the information about the deleted player object by adding the add_OnRemove event to the players object.
        this.state.players.delete(client.sessionId);
        if (this.ChangedItems.has(client.sessionId)) {
            this.ChangedItems.delete(client.sessionId);
        }
    }
}
```

1. マルチプレイサーバーをOnにし、テストをしてください。

## イベント関数

ZEPETO Mannequin 1.1.0 バージョンからイベント関数を使用することができます。

### ZEPETO.Mannequin.Mannequin

| **関数**                                                                                     | **説明**                                                                                |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
| public static OnSelectedItem: UnityEngine\_Events.UnityEvent$2\<ItemContent, boolean>;     | マネキンコーデ購入ウィンドウで特定のアイテムを選択したときに呼び出され、選択したアイテム情報アイテムContentおよびアイテム選択の可否がboolean値に移されます。 |
| public static OnSucceededPurchaseItems: UnityEngine\_Events.UnityEvent$1\<ItemContent\[]>; | コーデ購入完了時に呼び出され、購入したアイテム情報アイテムContentリストが渡されます。                                        |
| public static OnFailedPurchaseItems: UnityEngine\_Events.UnityEvent$1\<ItemContent\[]>;    | コーデの購入に失敗時に呼び出され、購入に失敗したアイテム情報アイテムContentリストが渡されます。                                   |
| public static OnAppliedItems: UnityEngine\_Events.UnityEvent$1\<ItemContent\[]>;           | コーデ購入成功後、購入したアイテムを着用すると選択した時に呼び出され、着用したアイテム情報アイテムContentリストが渡されます。                    |
| public static OnOpenedShopUI: UnityEngine\_Events.UnityEvent$1\<ItemContent\[]>;           | マネキンコーデ購入ウィンドウが開く時に呼び出され、購入ウィンドウにあるアイテム情報ItemContentリストが送信されます。                       |
| public static OnClosedShopUI: UnityEngine\_Events.UnityEvent;                              | マネキンコーデの購入ウィンドウが閉じたときに呼び出されます。                                                        |

### ZEPETO.Mannequin.BasePreviewer

| **関数**                                                                                                 | **説明**                                                 |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ |
| public OnChanged: UnityEngine\_Events.UnityEvent$1\<ZEPETO\_Mannequin\_BasePreviewer.ChangedValue\[]>; | マネキンを押して着用中のアイテム情報が変わると毎回呼び出され、OnChagedValueリストが移動します。 |

OnChagedValueクラスのメンバー変数情報は次のとおりです。

| public property : ZepetoPropertyFlag | コーデ詳細情報 |
| ------------------------------------ | ------- |
| public id : string                   | item ID |


Mannequin.WorldCamera
---------------------

Mannequin.WorldCameraをセッティングしないと、マネキンインタラクションアイコンと関連したカメラとしてDepthが低いカメラが設定されます。

他のカメラを別途セッティングしたい場合には、Mannequin.WorldCameraを使用すると指定できます。

| **Variable**          | **説明**                                         |
| --------------------- | ---------------------------------------------- |
| Mannequin.WorldCamera | マネキンインタラクションアイコンと関連したカメラを直接セッティングできるようにする変数です。 |

従来のMannequinScriptにMannequin.WorldCameraをセッティングした例は以下の通りです。

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { ZepetoPlayers, SpawnInfo } from 'ZEPETO.Character.Controller';
import { WorldService } from 'ZEPETO.World';
import { ItemContentsRequest, Mannequin, MannequinComponent, MannequinInteractable, MannequinPreviewer } from 'ZEPETO.Mannequin';
import { Object } from 'UnityEngine';
 
export default class MannequinScript extends ZepetoScriptBehaviour {
     
    private _previewer: MannequinPreviewer;
 
    Start() {
        // Code that creates a ZEPETO character based on the logged in ID 
        // ZepetoPlayers.instance.CreatePlayerWithUserId(WorldService.userId, SpawnInfo.Default, true);
 
        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            const character = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character;
            // Add Mannequin Interactable Component
            character.gameObject.AddComponent<MannequinInteractable>();
             
            // Code to set up the Mannequin Icon World Canvas Camera as the ZEPETO Camera
            Mannequin.WorldCamera = ZepetoPlayers.instance.LocalPlayer.zepetoCamera.camera;
        });
 
        // Find all Mannequin components
        const mannequins = Object.FindObjectsOfType<MannequinComponent>();
 
        mannequins.forEach(m => {
            // Enter the Collider
            m.onActive.AddListener(contents => {
                Mannequin.OpenUI(contents);
                const zepetoContext = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character.Context;
                this._previewer = new MannequinPreviewer(zepetoContext, contents);
                this._previewer.PreviewContents();
            });
 
            // Exit the Collider
            m.onCancel.AddListener(() => {
                Mannequin.CloseUI();
                this._previewer?.ResetContents();
            });
        });
    }
}
```

## OnContentsLoaded API

A callback has been added that is triggered when all clothing items are fully loaded while using the Mannequin API to equip clothing items.

```typescript
public OnContentsLoaded: UnityEngine_Events.UnityEvent$1<ZEPETO_Mannequin_BasePreviewer.ChangedValue[]>;
```

An example of setting OnContentsLoaded in the existing MannequinScript is as follows.

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { ZepetoPlayers, SpawnInfo } from 'ZEPETO.Character.Controller';
import { WorldService } from 'ZEPETO.World';
import { ItemContentsRequest, Mannequin, MannequinComponent, MannequinInteractable, MannequinPreviewer } from 'ZEPETO.Mannequin';
import { Object } from 'UnityEngine';
 
export default class MannequinScript extends ZepetoScriptBehaviour {
 
    private _previewer: MannequinPreviewer;
 
    Start() {
        // Code that creates a ZEPETO character based on the logged in ID 
        // ZepetoPlayers.instance.CreatePlayerWithUserId(WorldService.userId, SpawnInfo.Default, true);
 
        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            const character = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character;
            // Add Mannequin Interactable Component
            character.gameObject.AddComponent<MannequinInteractable>();
        });
 
        // Find all Mannequin components
        const mannequins = Object.FindObjectsOfType<MannequinComponent>();
 
        mannequins.forEach(m => {
            // Enter the Collider
            m.onActive.AddListener(contents => {
                Mannequin.OpenUI(contents);
                const zepetoContext = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character.Context;
                this._previewer = new MannequinPreviewer(zepetoContext, contents);
 
                // Adding listener to OnContentsLoaded event
                this._previewer.OnContentsLoaded.AddListener((changedValues)=>{
                    console.log('Contents loaded:', changedValues);
                });
 
                this._previewer.PreviewContents();
            });
 
            // Exit the Collider
            m.onCancel.AddListener(() => {
                Mannequin.CloseUI();
                this._previewer?.ResetContents();
            });
        });
    } 
}
```

**
