

終止支援通知： 將於 2026 AWS 年 5 月 20 日結束對 的支援 AWS SimSpace Weaver。2026 年 5 月 20 日之後，您將無法再存取 SimSpace Weaver 主控台或 SimSpace Weaver 資源。如需詳細資訊，請參閱[AWS SimSpace Weaver 終止支援](https://docs.aws.amazon.com/simspaceweaver/latest/userguide/simspaceweaver-end-of-support.html)。

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 SimSpace Weaver
<a name="working-with"></a>

本章提供的資訊和指導可協助您在 中建置自己的應用程式 SimSpace Weaver。

**Topics**
+ [設定模擬](working-with_configuring-simulation.md)
+ [模擬的持續時間上限](working-with_max-duration.md)
+ [開發應用程式](working-with_developing-apps.md)
+ [開發用戶端應用程式](working-with_developing-client-applications.md)
+ [取得自訂應用程式的 IP 地址和連接埠號碼](working-with_get-ip.md)
+ [啟動 Unreal Engine 檢視用戶端](working-with_unreal-client.md)
+ [中的本機開發 SimSpace Weaver](working-with_local-development.md)
+ [AWS SimSpace Weaver 應用程式開發套件](working-with_app-sdk.md)
+ [AWS SimSpace Weaver 示範架構](working-with_demo-framework.md)
+ [使用服務配額](working-with_quotas.md)
+ [偵錯模擬](working-with_debugging.md)
+ [自訂容器](working-with_custom-containers.md)
+ [使用 Python](working-with_python.md)
+ [支援其他引擎](working-with_engines.md)
+ [搭配 使用授權軟體 AWS SimSpace Weaver](working-with_byol.md)
+ [使用 管理您的 資源 AWS CloudFormation](working-with_cloudformation.md)
+ [快照](working-with_snapshots.md)
+ [簡訊](working-with_messaging.md)

# 設定模擬
<a name="working-with_configuring-simulation"></a>

**模擬結構描述 **（或**結構描述**) 是 YAML格式化的文字檔案，可指定模擬的組態。您可以使用相同的結構描述來啟動多個模擬。結構描述檔案位於模擬的專案資料夾中。您可以使用任何文字編輯器來編輯檔案。 SimSpace Weaver 只會在啟動模擬時讀取您的結構描述。您對結構描述檔案所做的任何編輯，都只會影響您在編輯後開始的新模擬。

若要設定模擬，請編輯模擬結構描述檔案 （針對您的作業系統使用適當的路徑分隔符號）：

```
project-folder\tools\project-name-schema.yaml
```

您在建立新的模擬時上傳模擬結構描述。專案的快速入門協助程式指令碼將上傳結構描述，做為建置模擬程序的一部分：

```
project-folder\tools\windows\quick-start.py
```

如需執行快速入門指令碼的詳細資訊，請參閱本指南[開始使用](getting-started.md)章節[詳細教學課程](getting-started_detailed.md)中的 。

## 模擬組態參數
<a name="working-with_configuring-simulation_config-parameters"></a>

模擬結構描述包含引導資訊，包括：
+ **模擬屬性** – SDK 版本和運算組態 ([工作者](w2aac51.md#glossary_worker)類型和數量）
+ **時鐘** – 刻度率和公差
+ **空間分割策略** – 空間拓撲 （例如網格）、邊界和置放群組 （工作者上的空間分割分組）
+ **網域及其應用程式** – 應用程式儲存貯體、路徑和啟動命令 (s)

SimSpace Weaver 使用您的結構描述組態來設定和安排空間分割區、啟動應用程式，並以您指定的刻度率推進模擬。

**注意**  
 SimSpace Weaver 應用程式開發套件中的 create-project 指令碼會根據範例應用程式，自動為您產生模擬結構描述。

下列主題說明模擬結構描述中的參數。如需模擬結構描述的完整說明，請參閱 [SimSpace Weaver 模擬結構描述參考](schema-reference.md)。

**Topics**
+ [模擬組態參數](#working-with_configuring-simulation_config-parameters)
+ [SDK 版本](working-with_configuring-simulation_sdk-version.md)
+ [模擬屬性](working-with_configuring-simulation_simulation-properties.md)
+ [工作程序](working-with_configuring-simulation_workers.md)
+ [時鐘](working-with_configuring-simulation_clock.md)
+ [分割策略](working-with_configuring-simulation_partitioning-strategies.md)
+ [網域](working-with_configuring-simulation_domains.md)

# SDK 版本
<a name="working-with_configuring-simulation_sdk-version"></a>

`sdk_version` 欄位指定 SimSpace Weaver 結構描述格式化的版本。有效值：`1.17`、`1.16`、`1.15`、`1.14`、`1.13`、`1.12`

**重要**  
的值`sdk_version`僅包含主要版本編號和第一個次要版本編號。例如， 值`1.12`會指定所有版本 `1.12.x`，例如 `1.12.0`、 `1.12.1`和 `1.12.2`。

# 模擬屬性
<a name="working-with_configuring-simulation_simulation-properties"></a>

結構描述的 `simulation_properties`區段會指定實體索引欄位 （通常是空間位置） 的記錄組態和資料類型。

```
simulation_properties:
  log_destination_service: "logs"
  log_destination_resource_name: "MySimulationLogs"
  default_entity_index_key_type: "Vector3<f32>"
```

的值`log_destination_service`決定 值的解譯`log_destination_resource_name`。目前，僅支援的值為 `logs`。這表示 的值`log_destination_resource_name`是 Amazon CloudWatch Logs 中日誌群組的名稱

**注意**  
記錄是選用的。如果您不設定日誌目的地屬性，則模擬不會產生日誌。

需要 `default_entity_index_key_type` 屬性。唯一有效的值為 `Vector3<f32>`。

# 工作程序
<a name="working-with_configuring-simulation_workers"></a>

`workers` 區段會指定您想要用於模擬的工作者類型和數量。 SimSpace Weaver 會使用自己的工作者類型來映射至 Amazon EC2 執行個體類型。

```
workers:
  MyComputeWorkers:
    type: "sim.c5.24xlarge"
    desired: 1
```

## 啟用多工作者模擬
<a name="working-with_configuring-simulation_workers_multi-worker"></a>

您可以建立使用超過 1 個工作者的模擬。根據預設，模擬會使用 1 個工作者。您必須先修改模擬結構描述，才能開始模擬。

**注意**  
您無法變更已啟動的模擬。如果您想要為執行中的模擬啟用多工作者，您必須先停止並刪除模擬。

若要使用多個工作者，請將運算執行個體`desired`的數量設定為大於 1 的值。每個工作者的應用程式數量上限。如需詳細資訊，請參閱 [SimSpace Weaver 端點和配額](service-quotas.md)。只有在工作者上的應用程式數量超過此限制時， SimSpace Weaver 才會使用超過 1 個工作者。 SimSpace Weaver 可以在任何可用的工作者上放置應用程式。無法保證在特定工作者上放置應用程式。

下列結構描述程式碼片段示範了請求 2 個工作者的模擬組態。如果應用程式數量超過 1 個工作者的應用程式數量上限， SimSpace Weaver 會嘗試配置第二個工作者。

```
workers:
  MyComputeWorkers:
    type: "sim.c5.24xlarge"
    desired: 2
```

# 時鐘
<a name="working-with_configuring-simulation_clock"></a>

`clock` 區段指定模擬時鐘的屬性。目前，您只能設定**刻度率** （時鐘傳送給應用程式的每秒刻度數）。刻度率是最高速率。有效的刻度率可能會較低，因為刻度的所有操作 （例如實體更新） 必須完成，才能開始下一個刻度。刻度率也稱為**時鐘率**。

的有效值`tick_rate`取決於結構描述中`sdk_version`指定的 。

**刻度率的有效值**
+ 早於 的版本`"1.14"`：
  + `10`
  + `15`
  + `30`
+ 版本 `"1.14"` 或更新版本：
  + `"10"`
  + `"15"`
  + `"30"`
  + `"unlimited"`

    如需詳細資訊，請參閱[無限制刻度率](#working-with_configuring-simulation_clock_unlimited)。

**重要**  
對於具有`sdk_version`早於 值`"1.14"`的結構描述`tick_rate`是**整數**，例如 `30`。
對於 `"1.14"`或更高`sdk_version`版本的結構描述， 的值`tick_rate`是**字串**，例如 `"30"`。值**必須包含雙引號**。  
如果您將版本`"1.12"`或結構描述轉換為版本 `"1.13"` `"1.14"`或更新版本，則必須以`tick_rate`雙引號括住 的值。

## 無限制刻度率
<a name="working-with_configuring-simulation_clock_unlimited"></a>

您可以將 `tick_rate` 設定為 `"unlimited"` ，讓您的模擬能夠以程式碼執行的速度執行。使用無限制的刻度率， 會在所有應用程式完成目前刻度的遞交後立即 SimSpace Weaver 傳送下一個刻度。

**重要**  
1.14.0 之前的 SimSpace Weaver 版本不支援無限制的刻度率。結構描述`sdk_version`中 的最小值為 `"1.14"`。

**中的無限制刻度率 SimSpace Weaver Local**  
SimSpace Weaver Local 會實作 `"unlimited"`，就好像結構描述指定了 10 kHz (10000) 的刻度率。效果與 中的無限制刻度率相同 AWS 雲端。您仍然會在結構描述`tick_rate: "unlimited"`中指定 。如需 SimSpace Weaver Local 的相關資訊，請參閱 [中的本機開發 SimSpace Weaver](working-with_local-development.md)。

## 有關時鐘的常見問題
<a name="working-with_configuring-simulation_clock_faq"></a>

### Q1. (問題 1)：我可以將 STARTED 模擬變更為使用不同的刻度率嗎？
<a name="working-with_configuring-simulation_clock_faq_q1"></a>

您無法變更在其生命週期的任何階段已存在於 AWS 雲端 之模擬的刻度率。您也無法變更在 中執行之模擬的刻度率SimSpace Weaver Local。您可以在結構描述`tick_rate`中設定 ，並從該結構描述開始新的模擬。

### Q2. (問題 2): 我可以在 1.14 之前的版本中以無限制的刻度率執行模擬嗎？
<a name="working-with_configuring-simulation_clock_faq_q2"></a>

否，1.14.0 之前的版本不支援無限制的刻度率。

## 故障診斷時鐘錯誤
<a name="working-with_configuring-simulation_clock_troubleshooting"></a>

如果您的模擬無法啟動，您可以在 **DescribeSimulation** API 的輸出`"StartError"`中檢查 的值。結構描述中的無效`tick_rate`值會產生下列錯誤。

**注意**  
此處顯示的錯誤輸出會顯示在多行上，以改善可讀性。實際錯誤輸出是單行。
+ `sdk_version` 早於 ，`"1.14"`而 的值`tick_rate`是無效的整數。有效值：`10`、`15`、`30`

  ```
  "[{\"errorType\":\"SchemaFormatInvalid\",\"errorMessage\":
      \"$.clock.tick_rate: does not have a value in the enumeration [10, 15, 30]\"}]"
  ```
+ `sdk_version` 早於 ，`"1.14"`而 的值`tick_rate`是字串。有效值：`10`、`15`、`30`

  ```
  "[{\"errorType\":\"SchemaFormatInvalid\",\"errorMessage\":
      \"$.clock.tick_rate: does not have a value in the enumeration [10, 15, 30]\"},
      {\"errorType\":\"SchemaFormatInvalid\",
      \"errorMessage\":\"$.clock.tick_rate: string found, integer expected\"}]"
  ```
+ `sdk_version` 是 `"1.14"`或更新版本，而 的值`tick_rate`是無效的字串。有效值：`"10"`、`"15"`、`"30"`、`"unlimited"`

  ```
  "[{\"errorType\":\"SchemaFormatInvalid\",\"errorMessage\":
      \"$.clock.tick_rate: does not have a value in the enumeration [10, 15, 30, unlimited]\"}]"
  ```
+ `sdk_version` 是 `"1.14"`或更新版本，而 的值`tick_rate`是整數。有效值：`"10"`、`"15"`、`"30"`、`"unlimited"`

  ```
  "[{\"errorType\":\"SchemaFormatInvalid\",\"errorMessage\":
      \"$.clock.tick_rate: does not have a value in the enumeration [10, 15, 30, unlimited]\"},
      {\"errorType\":\"SchemaFormatInvalid\",
      \"errorMessage\":\"$.clock.tick_rate: integer found, string expected\"}]"
  ```

# 分割策略
<a name="working-with_configuring-simulation_partitioning-strategies"></a>

`partitioning_strategies` 區段指定空間應用程式的分割區組態屬性。您可以為分割策略提供自己的名稱 （本節中的一組屬性），並將其用於空間應用程式組態。

```
partitioning_strategies:
  MyGridPartitioning:
    topology: "Grid"
    aabb_bounds:
      x: [0, 1000]
      y: [0, 1000]
    grid_placement_groups:
      x: 1
      y: 1
```

`topology` 屬性指定模擬使用的座標系統類型。值`Grid`指定二維 (2D) 網格。

對於`Grid`拓撲，模擬空間會建模為軸對齊週框方塊 (AABB)。您可以在 `aabb_bounds` 屬性中指定 AABB 每個軸的座標邊界。模擬中存在空間中的所有實體都必須在 AABB 中具有位置。

## 網格置放群組
<a name="working-with_configuring-simulation_partitioning-strategies_placement-groups"></a>

**置放群組**是 SimSpace Weaver 您要放置在相同工作者上的空間應用程式分割區集合。您可以在 `grid_placement_groups` 屬性中指定置放群組 （在網格中） 的數量和配置。 SimSpace Weaver 會嘗試將分割區平均分散到置放群組。在相同置放群組中具有分割區的空間應用程式的擁有權區域將在空間上相鄰。

我們建議 x \$1 y 等於您想要的工作者數量。如果不相等， SimSpace Weaver 會嘗試平衡可用工作者之間的置放群組。

如果您未指定置放群組組態， SimSpace Weaver 會為您計算一個。

# 網域
<a name="working-with_configuring-simulation_domains"></a>

您可以為網域的一組組態屬性提供名稱。網域中應用程式的啟動設定會決定網域的類型：
+ **`launch_apps_via_start_app_call`** – 自訂網域
+ **`launch_apps_by_partitioning_strategy`** – 空間網域
+ **`launch_apps_per_worker`** （不包含在範例應用程式中） – 服務網域

**重要**  
SimSpace Weaver 每個模擬最多支援 5 個網域。這包括所有空間、自訂和服務網域。

```
domains:
  MyViewDomain:
    launch_apps_via_start_app_call: {}
    app_config:
      package: "s3://weaver-myproject-111122223333-us-west-2/MyViewApp.zip"
      launch_command: ["MyViewApp"]
      required_resource_units:
        compute: 1
      endpoint_config:
        ingress_ports:
          - 7000
  MySpatialDomain:
    launch_apps_by_partitioning_strategy:
      partitioning_strategy: "MyGridPartitioning"
      grid_partition:
        x: 2
        y: 2
    app_config:
      package: "s3://weaver-myproject-111122223333-us-west-2/MySpatialApp.zip"
      launch_command: ["MySpatialApp"]
      required_resource_units:
        compute: 1
```

**注意**  
SimSpace Weaver 應用程式開發套件 1.12.x 版專案針對應用程式 .zip 檔案和結構描述使用不同的儲存貯體：  
Weaver-*lowercase-project-name*-*account-number*-app-zips-*region*
Weaver-*lowercase-project-name*-*account-number*-schemas-*region*

**Topics**
+ [應用程式組態](working-with_configuring-simulation_domains_app-config.md)
+ [設定空間網域](working-with_configuring-simulation_domains_spatial.md)
+ [網路端點](working-with_configuring-simulation_domains_endpoints.md)
+ [設定服務網域](working-with_configuring-simulation_domains_service-domains.md)

# 應用程式組態
<a name="working-with_configuring-simulation_domains_app-config"></a>

您可以將應用程式 (`app_config`) 的組態指定為其網域組態的一部分。所有類型的網域都使用這些相同的應用程式組態屬性。

```
    app_config:
      package: "s3://weaver-myproject-111122223333-us-west-2/MyViewApp.zip"
      launch_command: ["MyViewApp"]
      required_resource_units:
        compute: 1
```

**注意**  
SimSpace Weaver 應用程式開發套件 1.12.x 版專案針對應用程式 .zip 檔案和結構描述使用不同的儲存貯體：  
Weaver-*lowercase-project-name*-*account-number*-app-zips-*region*
Weaver-*lowercase-project-name*-*account-number*-schemas-*region*

`package` 屬性指定 S3 儲存貯體中 zip 檔案的 S3 URI。zip 檔案包含應用程式可執行檔 （也稱為*二進位* ) 及其所需的任何其他資源 （例如程式庫）。應用程式可執行檔的每個執行個體都會在工作者的Docker容器中執行。

`launch_command` 屬性會指定可執行檔的名稱，以及執行應用程式的任何命令列選項。的值`launch_command`是陣列。整個啟動命令字串的每個字符都是陣列中的 元素。

**範例**
+ 對於啟動命令： `MyTestApp --option1 value1`
+ 指定： `launch_command: ["MyTestApp", "-option1", "value1"]`

`required_resource_units` 屬性會指定 SimSpace Weaver 應配置給此應用程式的運算資源單位數量。運算資源單位是工作者(RAM)上固定數量的處理容量(vCPU)和記憶體。您可以增加此值，以增加應用程式在工作者上執行時可用的運算能力。每個工作者的運算資源單位數量有限。如需詳細資訊，請參閱[SimSpace Weaver 端點和配額](service-quotas.md)。

# 設定空間網域
<a name="working-with_configuring-simulation_domains_spatial"></a>

對於空間網域，您必須指定 `partitioning_strategy`。此屬性的值是您提供給分割策略的名稱，您在結構描述的另一個部分中定義。

```
  MySpatialDomain:
    launch_apps_by_partitioning_strategy:
      partitioning_strategy: "MyGridPartitioning"
      grid_partition:
        x: 2
        y: 2
    app_config:
      package: "s3://weaver-myproject-111122223333-us-west-2/MySpatialApp.zip"
      launch_command: ["MySpatialApp"]
      required_resource_units:
        compute: 1
```

**注意**  
SimSpace Weaver 應用程式開發套件 1.12.x 版專案針對應用程式 .zip 檔案和結構描述使用不同的儲存貯體：  
Weaver-*lowercase-project-name*-*account-number*-app-zips-*region*
Weaver-*lowercase-project-name*-*account-number*-schemas-*region*

具有`Grid`拓撲 （此版本中唯一支援的拓撲） 的分割策略 SimSpace Weaver 會指示 在網格中排列此網域的空間應用程式分割區。`grid_partition` 屬性會指定分割區網格的數字列和資料欄。

SimSpace Weaver 將為分割區網格中的每個儲存格啟動 1 個空間應用程式的執行個體。例如，如果空間網域具有`grid_partition`值 `x: 2`和 `y: 2`，空間網域中有 2 \$1 2 = 4 個分割區。 SimSpace Weaver 將啟動空間網域中設定的 4 個應用程式執行個體，並為每個應用程式執行個體指派 1 個分割區。

**主題**
+ [空間網域的資源需求](#working-with_configuring-simulation_domains_spatial_resources)
+ [多個空間網域](#working-with_configuring-simulation_domains_spatial_multiple)
+ [有關空間網域的常見問題](#working-with_configuring-simulation_domains_spatial_faq)
+ [對空間網域進行故障診斷](#working-with_configuring-simulation_domains_spatial_troubleshooting)

## 空間網域的資源需求
<a name="working-with_configuring-simulation_domains_spatial_resources"></a>

您可以為每個工作者指派最多 17 個運算資源單位。您可以在空間網域的 `app_config`區段中指定每個空間應用程式使用的運算資源單位數量。

**Example 結構描述程式碼片段，顯示空間應用程式的運算資源單位**  

```
  MySpatialDomain:
    launch_apps_by_partitioning_strategy:
      partitioning_strategy: "MyGridPartitioning"
      grid_partition:
        x: 2
        y: 2
    app_config:
      package: "s3://weaver-myproject-111122223333-artifacts-us-west-2/MySpatialApp.zip"
      launch_command: ["MySpatialApp"]
      required_resource_units:
        compute: 1
```

若要計算網域所需的運算資源單位數量，請將網格中的儲存格數量 （在您的 中`grid_partition`，`x`\$1`y`) 乘以指派給空間應用程式的運算資源單位數量。

對於先前的範例，網域會`MySpatialDomain`指定：
+ `x`: `2`
+ `y`: `2`
+ `compute`: `1`

的網格`MySpatialDomain`有 2 \$1 2 = 4 個儲存格。空間網域需要 4 \$1 1 = 4 個運算資源單位。

結構描述中指定之所有網域的運算資源單位總數，必須小於或等於工作者`desired`數乘以每個工作者的運算資源單位數上限 (17)。

## 多個空間網域
<a name="working-with_configuring-simulation_domains_spatial_multiple"></a>

您可以設定模擬使用超過 1 個空間網域。例如，您可以使用 1 個空間網域來控制模擬中的主要演員 （例如人物和汽車），並使用不同的空間網域來控制環境。

您也可以使用多個空間網域，將不同的資源指派給模擬的不同部分。例如，如果您的模擬具有的實體類型比其他類型多 10 倍的實體執行個體，您可以建立不同的網域來處理每個實體類型，並為具有更多實體的網域配置更多資源。

**重要**  
SimSpace Weaver 1.14.0 之前的版本不支援多個空間網域。

**重要**  
AWS SimSpace Weaver Local 目前不支援多個空間網域。如需 SimSpace Weaver Local 的相關資訊，請參閱 [中的本機開發 SimSpace Weaver](working-with_local-development.md)。

**重要**  
SimSpace Weaver 每個模擬最多支援 5 個網域。這包括所有空間、自訂和服務網域。

### 設定多個空間網域
<a name="working-with_configuring-simulation_domains_spatial_multiple_configure"></a>

若要設定多個空間網域，請在結構描述中將其他空間網域定義新增為個別的命名區段。每個網域都必須指定 `launch_apps_by_partitioning_strategy`金鑰。請參閱下列範例結構描述。

```
sdk_version: "1.14"
workers:
  MyComputeWorkers:
    type: "sim.c5.24xlarge"
    desired: 1
clock:
  tick_rate: "30"
partitioning_strategies:
  MyGridPartitioning:
    topology: Grid
    aabb_bounds:
      x: [0, 1000]
      y: [0, 1000]
domains:
  MySpatialDomain:
    launch_apps_by_partitioning_strategy:
      partitioning_strategy: "MyGridPartitioning"
      grid_partition:
        x: 2
        y: 2
    app_config:
      package: "s3://weaver-myproject-111122223333-artifacts-us-west-2/MySpatialApp.zip"
      launch_command: ["MySpatialApp"]
      required_resource_units:
        compute: 1
  MySecondSpatialDomain:
    launch_apps_by_partitioning_strategy:
      partitioning_strategy: "MyGridPartitioning"
      grid_partition:
        x: 2
        y: 2
    app_config:
      package: "s3://weaver-myproject-111122223333-artifacts-us-west-2/MySpatialApp2.zip"
      launch_command: ["MySpatialApp2"]
      required_resource_units:
        compute: 1
```

### 將空間網域放在一起
<a name="working-with_configuring-simulation_domains_spatial_multiple_placement"></a>

在某些情況下，您可能想要將空間網域的分割區放置在工作者上另一個網域的分割區旁。如果這些分割區彼此建立跨網域訂閱，這可以改善效能特性。

將頂層金鑰`placement_constraints`新增至您的結構描述，以指定哪些網域 SimSpace Weaver 應放在一起。所需的`on_workers`金鑰必須參考結構描述中的具名`workers`組態。

**Example 結構描述程式碼片段，顯示放在一起的空間網域**  

```
workers:
  MyComputeWorkers:
    type: "sim.c5.24xlarge"
    desired: 2
placement_constraints:
  - placed_together: ["MySpatialDomain", "MySecondSpatialDomain"]
    on_workers: ["MyComputeWorkers"]
```

**重要**  
如果您使用置放群組：  
請確定 x \$1 y 是工作者數目的倍數。
請確定置放群組值是您放在一起之網域網格維度的通用除數。
如果您**不使用**置放群組：  
請確定空間網域網格的 1 個軸具有等於工作者數量的通用除數。
如需置放群組的詳細資訊，請參閱 [分割策略](working-with_configuring-simulation_partitioning-strategies.md#working-with_configuring-simulation_partitioning-strategies_placement-groups)。

## 有關空間網域的常見問題
<a name="working-with_configuring-simulation_domains_spatial_faq"></a>

### Q1. (問題 1)：如何將另一個空間網域新增至現有的模擬？
<a name="working-with_configuring-simulation_domains_spatial_faq_q1"></a>
+ **針對執行中的模擬** – 您無法變更執行中模擬的組態。變更結構描述中的網域組態、上傳結構描述和應用程式 zip，然後啟動新的模擬。
+ **對於新的模擬** – 將網域組態新增至結構描述、上傳結構描述和應用程式壓縮，然後啟動新的模擬。

## 對空間網域進行故障診斷
<a name="working-with_configuring-simulation_domains_spatial_troubleshooting"></a>

當您嘗試啟動模擬但網域組態無效時， 可能會收到下列錯誤。

```
"StartError": "[{\"errorType\":\"SchemaFormatInvalid\",\"errorMessage\":
    \"We were unable to determine an arrangement of your domains that would fit 
    within the provided set of workers. This can generally be resolved by 
    increasing the number of workers if able, decreasing your domains\u0027 
    [\u0027\u0027grid_partition\u0027\u0027] values, or adjusting the 
    dimensions of your [\u0027\u0027grid_placement_groups\u0027\u0027].\"}]"
```

**可能的原因**
+ 結構描述為應用程式配置的運算資源單位比工作者可用的更多。
+ SimSpace Weaver 無法判斷將網域放在工作者上的安排。當您指定多個空間網域，但網域網格之間沒有共同的除數或多個，例如 2x4 網格和 3x5 網格之間） 時，就會發生這種情況。

# 網路端點
<a name="working-with_configuring-simulation_domains_endpoints"></a>

自訂和服務應用程式可以有外部用戶端可以連線的網路端點。您可以在 `ingress_ports`中指定連接埠號碼清單做為 的值`endpoint_config`。這些連接埠號碼皆為 TCP 和 UDP。自訂或服務應用程式應繫結至您在 中指定的連接埠號碼`ingress_ports`。 會在執行時間 SimSpace Weaver 動態配置連接埠號碼，並將這些連接埠映射至動態連接埠。您可以在應用程式開始尋找動態 （實際） 連接埠號碼後呼叫 **describe-app** API。如需詳細資訊，請參閱快速入門教學[取得自訂應用程式的 IP 地址和連接埠號碼取得 IP 地址和連接埠號碼](working-with_get-ip.md)中的 。

```
domains:
  MyViewDomain:
    launch_apps_via_start_app_call: {}
    app_config:
      package: "s3://weaver-myproject-111122223333-us-west-2/MyViewApp.zip"
      launch_command: ["MyViewApp"]
      required_resource_units:
        compute: 1
      endpoint_config:
        ingress_ports:
          - 7000
```

**注意**  
SimSpace Weaver 應用程式開發套件 1.12.x 版專案針對應用程式 .zip 檔案和結構描述使用不同的儲存貯體：  
Weaver-*lowercase-project-name*-*account-number*-app-zips-*region*
Weaver-*lowercase-project-name*-*account-number*-schemas-*region*

**注意**  
`endpoint_config` 是自訂應用程式和服務應用程式的選用屬性。如果您未指定 `endpoint_config`，則應用程式不會有網路端點。

# 設定服務網域
<a name="working-with_configuring-simulation_domains_service-domains"></a>

網域組態`launch_apps_per_worker:`中存在 表示它是具有服務應用程式的服務網域。 會為您 SimSpace Weaver 啟動和停止服務應用程式。當 SimSpace Weaver 啟動和停止應用程式時，應用程式會被視為具有*受管生命週期* 。 SimSpace Weaver 目前支援在每個工作者上啟動 1 或 2 個服務應用程式。

**Example 設定為在每個工作者上啟動 1 個服務應用程式的網域範例**  

```
domains:
  MyServiceDomain:
    launch_apps_per_worker:
      count: 1
    app_config:
      package: "s3://weaver-myproject-111122223333-app-zips-us-west-2/PlayerConnectionServiceApp.zip"
      launch_command: ["PlayerConnectionServiceApp"]
      required_resource_units:
        compute: 1
      endpoint_config:
        ingress_ports:
          - 9000
          - 9001
```

**Example 設定為在每個工作者上啟動 2 個服務應用程式的網域範例**  

```
domains:
  MyServiceDomain:
    launch_apps_per_worker:
      count: 2
    app_config:
      package: "s3://weaver-myproject-111122223333-app-zips-us-west-2/PlayerConnectionServiceApp.zip"
      launch_command: ["PlayerConnectionServiceApp"]
      required_resource_units:
        compute: 1
      endpoint_config:
        ingress_ports:
          - 9000
          - 9001
```

# 模擬的持續時間上限
<a name="working-with_max-duration"></a>

中的每個模擬 AWS SimSpace Weaver 都有*一個最長持續時間*設定，指定模擬可以執行的時間上限。當您啟動模擬時，您會提供最長持續時間做為參數。[`StartSimulation` 應用程式程式設計界面 (API)](https://docs.aws.amazon.com/simspaceweaver/latest/APIReference/API_StartSimulation.html) 具有選用參數 `MaximumDuration`。參數的值為分鐘 (m 或 M)、小時 (h 或 H) 或天數 (d 或 D)。例如， `1h`或 `1H`表示 1 小時。 會在達到此限制時 SimSpace Weaver 停止模擬。

## 最大值
<a name="working-with_max-duration_max-value"></a>

的最高有效值`MaximumDuration`為 `14D`，或其對等值，以小時 (`336H`) 或分鐘 () 為單位`20160M`。

## 預設值
<a name="working-with_max-duration_default-value"></a>

`MaximumDuration` 為選用參數。如果您未提供值， SimSpace Weaver 會使用 的值`14D`。

## 最小值
<a name="working-wtih_max-duration_min-value"></a>

的最低有效值`MaximumDuration`是數值相當於 的值`0`。例如，值 `0M`、 `0H`和 `0D`，在數值上都相當於 `0`。

如果您提供最長持續時間的最小值，模擬會在達到 `STOPPING` 狀態後立即轉換為 `STARTED` 狀態。

## 使用主控台啟動模擬
<a name="working-with_max-duration_console"></a>

您可以在[SimSpace Weaver 主控台](https://console.aws.amazon.com/simspaceweaver)中啟動模擬時，提供**最長持續時間**的值。當您選擇**開始模擬**時，請在**模擬設定**表單的**持續時間上限**欄位中輸入值。

**重要**  
如果您未提供**最長持續時間**的值， SimSpace Weaver 會使用[預設值](#working-with_max-duration_default-value) (`14D`)。

## 達到其最長持續時間的模擬狀態
<a name="working-with_max-duration_sim-state"></a>

當 SimSpace Weaver 自動停止達到其最長持續時間的模擬時，模擬**的狀態**為 `STOPPING`（如果進行中） 或 `STOPPED`。在 [SimSpace Weaver 主控台](https://console.aws.amazon.com/simspaceweaver)中，模擬**的目標狀態**仍為 `STARTED`，因為這是使用者請求的最後一個狀態。

# 開發應用程式
<a name="working-with_developing-apps"></a>

SimSpace Weaver 開發需要Amazon Linux 2 (AL2)環境來建置應用程式，因為您的模擬會在 Amazon Linux中於 上執行AWS Cloud。如果您使用的是 Windows，則可以使用 SimSpace Weaver 應用程式 SDK 中的指令碼來建立和啟動容器，該Docker容器AL2執行了您建置 SimSpace Weaver 應用程式所需的相依性。您也可以使用 啟動AL2環境Windows Subsystem for Linux (WSL)，或使用原生AL2系統。如需詳細資訊，請參閱[設定 的本機環境 SimSpace Weaver](setting-up_local.md)。

**注意**  
無論您如何設定本機開發環境，當您上傳應用程式以在 中執行時，您的應用程式都會在Docker容器中執行 AWS 雲端。**您的應用程式無法直接存取主機作業系統**。

**SimSpace Weaver 應用程式的一般流程**

1. 建立 應用程式。

1. 迴圈：

   1. 透過建立 開始更新`Transaction`。

      1. 如果模擬正在關閉，請退出迴圈。

   1. 處理訂閱和擁有權實體事件。

   1. 更新模擬。

   1. 遞交 `Transaction`以結束更新。

1. 銷毀應用程式。

## 空間應用程式
<a name="working-with_developing-apps_spatial-apps"></a>

每個空間應用程式都有一個擁有區域，這是模擬世界的空間區域。位於空間應用程式擁有區域的實體會存放在應用程式指派的分割區中。單一空間應用程式對其指派的分割區中的所有實體擁有完整所有權 （讀取和寫入許可）。沒有其他應用程式可以寫入這些實體。空間應用程式會提升其實體的狀態。每個空間應用程式只擁有 1 個分割區。 SimSpace Weaver 會使用實體的空間位置來編製索引，並將其指派給空間應用程式分割區。

 SimSpace Weaver 應用程式開發套件提供範例應用程式。您可以在下列資料夾中找到範例應用程式空間應用程式的原始程式碼 （使用適用於您作業系統的正確路徑分隔符號）：

```
sdk-folder\Samples\PathfindingSample\src\SpatialApp
```

## 自訂應用程式
<a name="working-with_developing-apps_custom-apps"></a>

您可以建立並使用自訂應用程式來與模擬互動。

**自訂應用程式可以**
+ 建立實體
+ 訂閱其他分割區
+ 遞交變更

**自訂應用程式的一般流程**

1. 建立 應用程式。

1. 在模擬中訂閱特定區域：

   1. 建立 `Transaction`以開始第一次更新。

   1. 為特定區域建立訂閱。

   1. 遞交 `Transaction`以結束第一次更新。

1. 迴圈：

   1. 建立 `Transaction`以開始更新。

      1. 如果模擬正在關閉，請退出迴圈。

   1. 程序狀態變更。

   1. 遞交 `Transaction`以結束更新。

1. 銷毀應用程式。

自訂應用程式建立實體之後，必須將實體轉移到空間網域，實體才能在模擬中空間內存在。 SimSpace Weaver 會使用實體的空間位置，將實體放置在適當的空間應用程式分割區中。建立實體的自訂應用程式無法在將實體轉移至空間網域後更新或刪除實體。

 SimSpace Weaver 應用程式開發套件提供範例應用程式。您可以使用範例應用程式中包含的自訂應用程式，做為您自己自訂應用程式的模型。您可以在下列資料夾中找到範例應用程式的檢視應用程式 （自訂應用程式） 的原始碼 （使用適用於您作業系統的正確路徑分隔符號）：

```
sdk-folder\Samples\PathfindingSample\src\ViewApp
```

# 開發用戶端應用程式
<a name="working-with_developing-client-applications"></a>

您可能想要將用戶端連線至模擬的一些原因包括：
+ 將即時流量資訊注入城市規模模擬。
+ 建立*human-in-the-loop*模擬，其中人工運算子控制模擬的某些層面。
+ 讓使用者能夠與模擬互動，例如用於訓練模擬。

這些範例中的自訂應用程式充當模擬狀態與外部世界之間的界面。用戶端會連線至自訂應用程式，以與模擬互動。

SimSpace Weaver 不會處理用戶端應用程式及其與您的自訂應用程式的通訊。您負責用戶端應用程式的設計、建立、操作和安全性，以及其與自訂應用程式的通訊。 SimSpace Weaver 只會公開每個自訂應用程式的 IP 地址和連接埠號碼，以便用戶端可以與其連線。

 SimSpace Weaver 應用程式開發套件提供用戶端用於其範例應用程式。您可以使用這些用戶端做為您自己的用戶端應用程式的模型。您可以在下列資料夾中找到範例應用程式用戶端的原始程式碼：

------
#### [ Docker ]

```
sdk-folder\packaging-tools\clients\PathfindingSampleClients
```

------
#### [ WSL ]

**重要**  
為了您的方便，我們提供這些說明。它們適用於 Windows Subsystem for Linux (WSL)，不支援。如需詳細資訊，請參閱[設定 的本機環境 SimSpace Weaver](setting-up_local.md)。

```
sdk-folder/packaging-tools/clients/PathfindingSampleClients
```

------

如需建置和使用範例應用程式用戶端的詳細資訊，請參閱中的教學課程[入門 SimSpace Weaver](getting-started.md)。

# 取得自訂應用程式的 IP 地址和連接埠號碼
<a name="working-with_get-ip"></a>

若要檢視模擬，您可以建立自訂應用程式，並與用戶端連線。如需詳細資訊，請參閱 中的教學課程[入門 SimSpace Weaver](getting-started.md)。您可以使用下列程序來取得自訂應用程式的 IP 地址和連接埠號碼。為您的作業系統使用適當的路徑分隔符號 （例如，`\`在 Windows 和 Linux `/`中）。

**取得您的 IP 地址和連接埠號碼**

1. 使用 ** ListSimulations** API 取得模擬的名稱。

   ```
   aws simspaceweaver list-simulations
   ```

   輸出範例：

   ```
   {
       "Simulations": [
           {
               "Status": "STARTED",
               "CreationTime": 1664921418.09,
               "Name": "MyProjectSimulation_22-10-04_22_10_15",
               "Arn": "arn:aws:simspaceweaver:us-west-2: 111122223333:simulation/MyProjectSimulation_22-10-04_22_10_15",
               "TargetStatus": "STARTED"
           }
       ]
   
   }
   ```

1. 使用 ** DescribeSimulation** API 取得模擬中的網域清單。

   ```
   aws simspaceweaver describe-simulation --simulation simulation-name
   ```

   在輸出的 `Domains`區段中尋找 `LiveSimulationState`區段。

   輸出範例：

   ```
       "LiveSimulationState": {
           "Domains": [
               {
                   "Type": "",
                   "Name": "MySpatialSimulation",
                   "Lifecycle": "Unknown"
               },
               {
                   "Type": "",
                   "Name": "MyViewDomain",
                   "Lifecycle": "ByRequest"
               }
           ],
   ```

1. 使用 ** ListApps** API 取得網域中的自訂應用程式清單。例如，範例專案中檢視 （自訂） 應用程式的網域名稱為 `MyViewDomain`。在輸出中尋找應用程式名稱。

   ```
   aws simspaceweaver list-apps --simulation simulation-name --domain domain-name
   ```

   輸出範例：

   ```
    
   {
       "Apps": [
           {
               "Status": "STARTED",
               "Domain": "MyViewDomain",
               "TargetStatus": "STARTED",
               "Name": "ViewApp",
               "Simulation": "MyProjectSimulation_22-10-04_22_10_15"
           }
       ]
   }
   ```

1. 使用 ** DescribeApp** API 取得 IP 地址和連接埠號碼。對於範例專案，網域名稱為 `MyViewDomain`，應用程式名稱為 `ViewApp`。

   ```
   aws simspaceweaver describe-app --simulation simulation-name --domain domain-name --app app-name
   ```

   IP 地址和連接埠號碼位於輸出的 `EndpointInfo` 區塊中。IP 地址是 的值`Address`，連接埠號碼是 的值`Actual`。

   輸出範例：

   ```
   {
       "Status": "STARTED",
       "Domain": "MyViewDomain",
       "TargetStatus": "STARTED",
       "Simulation": "MyProjectSimulation_22-10-04_22_10_15",
       "LaunchOverrides": {
           "LaunchCommands": []
       },
       "EndpointInfo": {
           "IngressPortMappings": [
               {
                   "Declared": 7000,
                   "Actual": 4321
               }
           ],
           "Address": "198.51.100.135"
       },
       "Name": "ViewApp"
   }
   ```
**注意**  
的值`Declared`是應用程式程式碼應繫結的連接埠號碼。的值`Actual`是向用戶端 SimSpace Weaver 公開以連接到您 app 的連接埠號碼。將`Declared`連接埠 SimSpace Weaver 映射至`Actual`連接埠。

# 啟動 Unreal Engine 檢視用戶端
<a name="working-with_unreal-client"></a>

 導覽至：

```
sdk-folder/Samples/PathfindingSample/tools/cloud
```

1. 請執行下列其中一個命令：
   + Docker： `python quick-start.py`
   + WSL： `python quick-start.py --al2`

1. 取得 IP 地址和「實際」連接埠號碼。這些將位於執行 quick-start.py 的主控台輸出中，或依照 中的程序取得[取得自訂應用程式的 IP 地址和連接埠號碼取得 IP 地址和連接埠號碼](working-with_get-ip.md)。

1.  導覽至：

   ```
   sdk-folder/Clients/TCP/UnrealClient/lib
   ```

1.  執行下列命令來建置 NNG 程式庫：

   ```
   cmake -S . -B build 
   cmake --build build --config RelWithDebInfo 
   cmake --install build
   ```

1.  在**文字編輯器**中，開啟 `view_app_url.txt`。

1.  使用檢視應用程式的 IP 地址和連接埠號碼更新 URL： `tcp://ip-address:actual-port-number`（看起來應該像 `tcp://198.51.100.135:1234`)。

1.  在 **Unreal 編輯器**中，選擇**播放**。

## 故障診斷
<a name="working-with_unreal-client_troubleshooting"></a>
+  **NNG CMake 安裝步驟失敗，並顯示「可能需要管理權限」：**

  ```
  CMake Error at build/_deps/nng-build/src/cmake_install.cmake:39 (file):
    file cannot create directory: C:/Program Files
    (x86)/ThirdPartyNngBuild/lib.  Maybe need administrative privileges.
  Call Stack (most recent call first):
    build/_deps/nng-build/cmake_install.cmake:37 (include)
    build/cmake_install.cmake:73 (include)
  ```
  +  **解決方法：**如果 UnrealClient/lib 目錄中`nng.so`存在 `nng.lib`或 ，則可以安全地忽略此錯誤。如果沒有，請嘗試在具有管理員權限的終端機中執行 cmake 建置命令。
+  **「CMake to find a package configuration file provided by nng」：**

  ```
  CMake Error at CMakeLists.txt:23 (find_package):
  By not providing "Findnng.cmake" in CMAKE_MODULE_PATH this project has
   asked CMake to find a package configuration file provided by "nng", but
   CMake did not find one.
  ```
  +  **解決方法：**CMake 在尋找`Findnng.cmake`檔案時遇到問題。使用 CMake 建置時，請新增引數 `-DTHIRD_PARTY_LIB_PATH sdk-folder/ThirdParty`。在重新執行 CMake 建置之前，請確定 `Findnng.cmake` 檔案仍在 `ThirdParty`目錄中。

    ```
    cmake -S . -B build -DTHIRD_PARTY_LIB_PATH sdk-folder/ThirdParty
    cmake --build build --config RelWithDebInfo 
    cmake --install build
    ```

# 中的本機開發 SimSpace Weaver
<a name="working-with_local-development"></a>

您可以在本機部署 SimSpace Weaver 應用程式，以進行快速測試和偵錯。

**要求**
+ 完成「[設定 SimSpace Weaver](setting-up.md)」中的步驟。

**Topics**
+ [步驟 1：啟動本機模擬](working-with_local_launch.md)
+ [步驟 2：檢視本機模擬](working-with_local-development_view.md)
+ [步驟 3：停止本機模擬 （在 Windows 上選用）](working-with_local-development_stop-sim.md)
+ [故障診斷 中的本機開發 SimSpace Weaver](working-with_local-development_troubleshooting.md)

# 步驟 1：啟動本機模擬
<a name="working-with_local_launch"></a>

1. 導覽至

   ```
   cd sdk-folder/Samples/sample-name/tools/local
   ```

1. 執行下列命令，在本機建置和啟動模擬。

   ```
   python quick-start.py
   ```

   此指令碼將執行下列動作：

   1. 建置專案。
      +  `quick-start.py` 會呼叫 https：//build.py. 中定義的 `build_project` 函數。此步驟會根據專案而有所不同。對於 PathfindingSample，會使用 CMake。CMake 和 Docker 命令，可在 build.py：//。

   1. 啟動本機模擬
      + 指令碼將針對結構描述中定義的每個空間分割區啟動一個本機程序。
      + 指令碼將為結構描述中定義的每個自訂應用程式啟動一個程序。
      + 空間應用程式會先啟動，接著是自訂應用程式，每個應用程式都會依照顯示在結構描述中的順序。

**重要**  
在不支援 GUI 的環境中啟動時，例如主控台 SSH 工作階段，請使用 `--noappwindow`選項將所有輸出重新導向至目前的終端機。

**重要**  
對於 Linux 使用者，指令碼假設您的系統具有 `xterm`命令。如果您的 Linux 發行版本沒有 `xterm`命令，請使用 `--noappwindow`選項將所有輸出重新導向至目前的終端機。
+  -h​、 -求助​ 
  +  列出這些參數。
+  --clean 
  +  在建置之前刪除建置目錄的內容。
+  --nobuild 
  +  略過重建專案。
+  --noappwindow 
  +  請勿為每個應用程式開啟新視窗。反之，請將 stdout 重新導向至目前的終端機。
+  --logfile 
  +  將主控台輸出寫入日誌檔案。
+  --consoleclient 
  +  自動連接組態中列出的主控台用戶端。
+  --結構描述 SCHEMA
  + 此調用將使用的結構描述。預設為 https：//config.py 中的「SCHEMA」。

# 步驟 2：檢視本機模擬
<a name="working-with_local-development_view"></a>

若要檢視本機模擬，您可以使用 SimSpaceWeaverAppSdkDistributable 隨附的任何用戶端。如需建置和使用範例用戶端的詳細資訊，請參閱 中的教學課程[入門 SimSpace Weaver](getting-started.md)。

您必須更新用戶端中的 IP 地址和連接埠號碼，才能連線至本機模擬的檢視應用程式。一律搭配 使用下列值SimSpace Weaver Local：

```
tcp://127.0.0.1:7000
```

根據您選取的用戶端，您可以更新 IP 地址和連接埠號碼，如下所示：
+ **Unreal** – 變更第 1 行的 URL `view_app_url.txt`
+ **主控台** – 使用 IP 地址和連接埠號碼 URL 做為參數啟動用戶端

# 步驟 3：停止本機模擬 （在 Windows 上選用）
<a name="working-with_local-development_stop-sim"></a>

**注意**  
Linux 需要此步驟，但 Windows 則為選用。

1.  導覽至：

   ```
   sdk-folder/Samples/sample-name/tools/local
   ```

1.  執行下列命令來停止本機模擬並刪除任何共用記憶體資源。

   ```
   python stop-and-delete.py
   ```

    此指令碼將執行下列動作：
   +  停止本機程序。
   +  刪除共用記憶體物件 （僅在 Linux 上需要）。

**stop-and-delete.py 參數**
+  -h​、 -求助​ 
  +  列出這些參數。
+  --stop 
  +  僅嘗試停止程序。
+  --delete 
  +  僅嘗試刪除共用記憶體資源。
+  -- 程序 
  +  要停止的程序名稱。如果您的程序名稱與結構描述中的套件名稱不相符，請使用此選項。
+  --結構描述 SCHEMA 
  +  此調用將使用的結構描述。預設為 https：//www.config.py 中的 'SCHEMA' 值。

# 故障診斷 中的本機開發 SimSpace Weaver
<a name="working-with_local-development_troubleshooting"></a>
+  **Linux：找不到 xterm 命令 / 無法開啟** 
  + 在 Linux 上執行時，本機指令碼會假設 xterm 命令存在。如果您沒有 xterm 命令或在不支援 GUI 的環境中執行，請在執行快速入門指令碼時使用 `--noappwindow`選項。
+  ** 沒有開啟的應用程式視窗！ **
  +  當本機模擬立即當機時，就會發生這種情況。若要在當機後查看主控台輸出，請在執行快速入門指令碼時使用 `--noappwindow`或 `--logfile`選項。
+  ** 檢視應用程式啟動或檢視用戶端連線後，模擬不會勾選！ **
  +  使用 `—noappwindow`選項執行 通常會解決這類問題。否則，重新啟動幾次也會成功 （雖然速率較低）。

# AWS SimSpace Weaver 應用程式開發套件
<a name="working-with_app-sdk"></a>

 SimSpace Weaver 應用程式開發套件提供 APIs，可讓您用來控制模擬中的實體並回應 SimSpace Weaver 事件。它包含下列命名空間：
+ **API** – API 及其使用的核心定義

與下列程式庫連結：
+ `libweaver_app_sdk_cxx_v1_full.so`

**重要**  
當您在 中執行應用程式時，程式庫可用於動態連結 AWS 雲端。您不需要使用應用程式上傳它。

**注意**  
 SimSpace Weaver 應用程式開發套件 APIs 會控制模擬中的資料。這些 APIs與 SimSpace Weaver 服務 APIs，可在其中控制您的 SimSpace Weaver 服務資源 （例如模擬、應用程式和時鐘） AWS。如需詳細資訊，請參閱[SimSpace Weaver API 參考](api-reference.md)。

**Topics**
+ [API 方法會傳回 Result](working-with_app-sdk_return-result.md)
+ [在頂層與應用程式 SDK 互動](working-with_app-sdk_top-level.md)
+ [模擬管理](working-with_app-sdk_sim.md)
+ [訂閱](working-with_app-sdk_sub.md)
+ [實體](working-with_app-sdk_ent.md)
+ [實體事件](working-with_app-sdk_events.md)
+ [Result 和錯誤處理](working-with_app-sdk_result.md)
+ [一般和網域類型](working-with_app-sdk_generics.md)
+ [其他應用程式 SDK 操作](working-with_app-sdk_misc.md)

# API 方法會傳回 Result
<a name="working-with_app-sdk_return-result"></a>

大多數 SimSpace Weaver API 函數都有傳回類型 `Aws::WeaverRuntime::Result<T>`。如果函數已成功執行，則 `Result`包含 `T`。否則， `Result`包含`Aws::WeaverRuntime::ErrorCode`代表來自 錯誤碼的 Rust App SDK。

**Example 範例**  

```
Result<Transaction> BeginUpdate(Application& app)
```

此方法：
+ `Transaction` 如果 成功`BeginUpdate()`執行，則傳回 。
+ `Aws::WeaverRuntime::ErrorCode` 如果`BeginUpdate()`失敗，傳回 。

# 在頂層與應用程式 SDK 互動
<a name="working-with_app-sdk_top-level"></a>

**生命週期**
+  SimSpace Weaver 應用程式開發套件會管理應用程式生命週期。您不需要讀取或寫入應用程式的生命週期狀態。

**資料分割**
+ 使用 `Result <PartitionSet> AssignedPartitions(Transaction& txn);`取得擁有的分割區。
+ 使用 `Result <PartitionSet> AllPartitions(Transaction& txn);`取得模擬中的所有分割區。

# 模擬管理
<a name="working-with_app-sdk_sim"></a>

本節說明常見模擬管理任務的解決方案。

**Topics**
+ [開始模擬](working-with_app-sdk_sim_start.md)
+ [更新模擬](working-with_app-sdk_sim_update.md)
+ [終止模擬](working-with_app-sdk_sim_terminate.md)

# 開始模擬
<a name="working-with_app-sdk_sim_start"></a>

使用 `CreateApplication()`建立應用程式。

**Example 範例**  

```
Result<Application> applicationResult = Api::CreateApplication();

if (!applicationResult)
{
    ErrorCode errorCode = WEAVERRUNTIME_EXPECT_ERROR(applicationResult);

    std::cout << "Failed to create application. Error code " <<
        static_cast<std::underlying_type_t<ErrorCode>>(errorCode) <<
        " Last error message "<< Api::LastErrorMessage() << ".";

    return 1;
}

/**
* Run simulation
*/
RunSimulation(std::move(applicationResult.assume_value()));
```

# 更新模擬
<a name="working-with_app-sdk_sim_update"></a>

使用下列`BeginUpdate`函數更新應用程式：
+ `Result<Transaction> BeginUpdate(Application& app)`
+ `Result<bool> BeginUpdateWillBlock(Application& app)` – 告訴您 `BeginUpdate()`是否會封鎖。

使用 `Result<void> Commit(Transaction& txn)`遞交變更。

**Example 範例**  

```
Result<void> AppDriver::RunSimulation(Api::Application app) noexcept
{
    while (true)
    {
        {
            bool willBlock;

            do
            {
                WEAVERRUNTIME_TRY(willBlock, Api::BeginUpdateWillBlock(m_app));
            } while (willBlock);
        }

        WEAVERRUNTIME_TRY(Transaction transaction, Api::BeginUpdate(app));

        /**
         * Simulate app.
         */
        WEAVERRUNTIME_TRY(Simulate(transaction));
        WEAVERRUNTIME_TRY(Api::Commit(std::move(transaction)));
    }

    return Success();
}
```

# 終止模擬
<a name="working-with_app-sdk_sim_terminate"></a>

使用 `Result<void> DestroyApplication(Application&& app)`來終止應用程式和模擬。

其他應用程式發現，從`ErrorCode::ShuttingDown`對 `BeginUpdateWillBlock()`或 的呼叫接收到模擬時，模擬正在關閉`BeginUpdate()`。當應用程式收到 時`ErrorCode::ShuttingDown`，它可以呼叫 `Result<void> DestroyApplication(Application&& app)` 來終止自己。

**Example 範例**  

```
Result<void> AppDriver::EncounteredAppError(Application&& application) noexcept
{
    const ErrorCode errorCode = WEAVERRUNTIME_EXPECT_ERROR(runAppResult);

    switch (errorCode)
    {
    case ErrorCode::ShuttingDown:
        {
            // insert custom shutdown process here.

            WEAVERRUNTIME_TRY(Api::DestroyApplication(std::move(application)));
            return Success();
        }
    default:
        {
            OnAppError(errorCode);
            return errorCode;
        }
    }
}
```

**重要**  
僅在 `Result<void> DestroyApplication(Application&& app)`之後呼叫 `Api::Commit()`。在更新期間銷毀應用程式可能會導致未定義的行為。

**重要**  
您必須在程式結束`DestroyApplication()`之前呼叫 ，以確保應用程式回報為成功終止。  
當程式結束`DestroyApplication()`時，無法呼叫 將導致狀態被視為 `FATAL`。

# 訂閱
<a name="working-with_app-sdk_sub"></a>

您可以使用訂閱區域和網域 ID 建立訂閱。網域 ID 代表擁有該訂閱區域的網域。`BoundingBox2F32` 描述訂閱區域。使用下列函數建立訂閱：

```
Result<SubscriptionHandle> CreateSubscriptionBoundingBox2F32(Transaction& txn, DomainId id, const BoundingBox2F32& boundingBox)
```

**Example 範例**  

```
Result<void> CreateSubscriptionInSpatialDomain(Transaction& transaction)
{
    WEAVERRUNTIME_TRY(Api::PartitionSet partitionSet, Api::AllPartitions(transaction)); 
    
    Api::DomainId spatialDomainId;

    for (const Api::Partition& partition : partitionSet.partitions)
    {
        if (partition.domain_type == Api::DomainType::Spatial)
        {
            /**
            * Get the spatial domain ID.
            */
            spatialDomainId = partition.domain_id;
            break;
        }
    }
    
    constexpr Api::BoundingBox2F32 subscriptionBounds { 
        /* min */ { /* x */ 0, /* y */ 0 }, 
        /* max */ { /* x */ 1000, /* y */ 1000 } }

    WEAVERRUNTIME_TRY(
        Api::SubscriptionHandle subscriptionHandle,
        Api::CreateSubscriptionBoundingBox2F32(
        transaction,
        spatialDomainId,
        subscriptionBounds));
        
    return Success();
}
```

您可以使用 `Api::SubscriptionHandle`傳回的 `CreateSubscriptionBoundingBox2F32()`來修改訂閱。您可以將它做為引數傳遞給下列函數：

```
Result<void> ModifySubscriptionBoundingBox2F32(Transaction& txn, SubscriptionHandle handle, const BoundingBox2F32& boundingBox)
```

```
Result<void> DeleteSubscription(Transaction& txn, SubscriptionHandle handle)
```

# 實體
<a name="working-with_app-sdk_ent"></a>

您可以使用從 `Result<Api::Entity>`傳回`Api:Entity`的 的 `CreateEntity()`，或實體進入應用程式的訂閱區域時，從所有權變更事件呼叫 `Store`和 `Load` APIs （如需詳細資訊，請參閱 [實體事件](working-with_app-sdk_events.md))。我們建議您追蹤`Api::Entity`物件，以便使用這些 APIs。

**Topics**
+ [建立實體](working-with_app-sdk_ent_create.md)
+ [將實體轉移到空間網域](working-with_app-sdk_ent_transfer.md)
+ [寫入和讀取實體欄位資料](working-with_app-sdk_ent_readwrite.md)
+ [儲存實體的位置](working-with_app-sdk_ent_store-position.md)
+ [載入實體的位置](working-with_app-sdk_ent_load-position.md)

# 建立實體
<a name="working-with_app-sdk_ent_create"></a>

使用 `CreateEntity()`建立實體。您可以定義`Api::TypeId`您傳遞至此函數的 意義。

```
Namespace
{
    constexpr Api::TypeId k_entityTypeId { /* value */ 512 };
}

Result<void> CreateEntity(Transaction& transaction)
{
    WEAVERRUNTIME_TRY(
        Api::Entity entity,
        Api::CreateEntity(
            transaction, Api::BuiltinTypeIdToTypeId(k_entityTypeId )));
}
```

**注意**  
`Api::BuiltinTypeId` 為 保留 0-511 的值。您的實體 TypeID(`k_entityTypeId`在此範例中為 ) 必須具有 512 或更高的值。

# 將實體轉移到空間網域
<a name="working-with_app-sdk_ent_transfer"></a>

自訂應用程式或服務應用程式建立實體後，應用程式必須將實體轉移到空間網域，實體才能在模擬中空間上存在。空間網域中的實體可由其他應用程式讀取，並由空間應用程式更新。使用 `ModifyEntityDomain()` API 將實體轉移到空間網域。

```
AWS_WEAVERRUNTIME_API Result<void> ModifyEntityDomain(Transaction& txn, const Entity& entity, DomainId domainId) noexcept;
```

如果 `DomainId` 不符合呼叫應用程式指派`Partition`的 `DomainType::Spatial` ，則 `DomainId` 必須是 。 `Domain`所有權轉移至新的 會在 期間`Domain`發生`Commit(Transaction&&)`。參數

`txn`  
目前的 `Transaction`。

`entity`  
變更 `Entity`的目標`Domain`。

`domainId`  
`DomainId` `Domain` 目的地的 `Entity`。

`Success` 如果實體網域已成功變更，此 API 會傳回 。

# 寫入和讀取實體欄位資料
<a name="working-with_app-sdk_ent_readwrite"></a>

所有實體資料欄位都是 Blob 類型。您最多可以將 1，024 個位元組的資料寫入實體。我們建議您盡可能減少 Blob，因為較大的大小會降低效能。當您寫入 Blob 時，您會將 SimSpace Weaver 指標傳遞至資料及其長度。當您從 Blob 讀取時， SimSpace Weaver 會為您提供要讀取的指標和長度。在應用程式呼叫 之前，所有讀取都必須完成`Commit()`。當應用程式呼叫 時，從讀取呼叫傳回的指標會失效`Commit()`。

**重要**  
在`Commit()`不支援 之後從快取 Blob 指標讀取，可能會導致模擬失敗。
不支援寫入讀取呼叫傳回的 Blob 指標，並可能導致模擬失敗。

**Topics**
+ [儲存實體的欄位資料](working-with_app-sdk_ent_readwrite_store.md)
+ [載入實體的欄位資料](working-with_app-sdk_ent_readwrite_load.md)
+ [載入已移除實體的欄位資料](working-with_app-sdk_ent_readwrite_load-removed.md)

# 儲存實體的欄位資料
<a name="working-with_app-sdk_ent_readwrite_store"></a>

下列範例示範如何存放 （寫入狀態結構） 應用程式所擁有實體的欄位資料。這些範例使用以下函數：

```
AWS_WEAVERRUNTIME_API Result<void> StoreEntityField(
    Transaction& txn,
    const Entity& entity,
    TypeId keyTypeId,
    FieldIndex index,
    std::int8_t* src,
    std::size_t length) noexcept;
```

`Api::TypeId keyTypeId` 參數代表傳入資料的 資料類型。

`Api::TypeId keyTypeId` 參數應該`Api::TypeId`會從 接收對應的 `Api::BuiltinTypeId`。如果沒有適當的轉換，您可以使用 `Api::BuiltinTypeId::Dynamic`。

對於複雜的資料類型，請使用 `Api::BuiltInTypeId::Dynamic`。

**注意**  
的值`FieldIndex index`必須大於 0。值 0 保留給索引鍵 （請參閱 `StoreEntityIndexKey()`)。

**Example 使用基本資料類型的範例**  

```
namespace
{
    constexpr Api::FieldIndex k_isTrueFieldId { /* value */ 1 };
}

Result<void> SetEntityFields(
    Api::Entity& entity, 
    Transaction& transaction)
{
    bool value = true;
    
    auto* src = reinterpret_cast<std::int8_t*>(value);
    size_t length = sizeof(*value);
    
    WEAVERRUNTIME_TRY(Api::StoreEntityField(
        transaction,
        entity,
        Api::BuiltinTypeIdToTypeId(
            Aws::WeaverRuntime::Api::BuiltinTypeId::Bool),
        k_isTrueFieldId,
        src,
        length));
}
```

**Example 使用 struct保留資料的範例**  

```
namespace
{
    constexpr Api::FieldIndex k_dataFieldId { /* value */ 1 };
}

struct Data
{
    bool boolData;
    float floatData;
};

Result<void> SetEntityFields(
    Api::Entity& entity, 
    Transaction& transaction)
{
    Data data = { /* boolData */ false, /* floatData */ -25.93 };
    
    auto* src = reinterpret_cast<std::int8_t*>(data);
    size_t length = sizeof(*data);
    
    WEAVERRUNTIME_TRY(Api::StoreEntityField(
        transaction,
        entity,
        Api::BuiltinTypeIdToTypeId(
            Aws::WeaverRuntime::Api::BuiltinTypeId::Dynamic),
        k_dataFieldId,
        src,
        length));
}
```

# 載入實體的欄位資料
<a name="working-with_app-sdk_ent_readwrite_load"></a>

下列範例示範如何載入 實體的欄位資料 （從狀態結構讀取）。這些範例使用以下函數：

```
Result<std::size_t> LoadEntityField(
    Transaction& txn,
    const Entity& entity,
    TypeId keyTypeId,
    FieldIndex index,
    std::int8_t** dest) noexcept;
```

`Api::TypeId keyTypeId` 參數應該`Api::TypeId`會從 接收對應的 `Api::BuiltinTypeId`。如果沒有適當的轉換，您可以使用 `Api::BuiltinTypeId::Dynamic`。

**注意**  
`FieldIndex` 索引的值必須大於 0。值 0 保留給索引鍵 （請參閱 `StoreEntityIndexKey()`)。

**Example 使用基本資料類型的範例**  

```
namespace
{
    constexpr Api::FieldIndex k_isTrueFieldId { /* value */ 1 };
}

Result<void> LoadEntityFields(
    Api::Entity& entity, 
    Transaction& transaction)
{
    std::int8_t* dest = nullptr;
    
    WEAVERRUNTIME_TRY(Api::LoadEntityField(
        transaction,
        entity,
        Api::BuiltinTypeIdToTypeId(
            Aws::WeaverRuntime::Api::BuiltinTypeId::Bool),
        k_isTrueFieldId,
        &dest));
    
    bool isTrueValue = *reinterpret_cast<bool*>(dest);
}
```

**Example 使用 struct保留資料的範例**  

```
namespace
{
    constexpr Api::FieldIndex k_dataFieldId { /* value */ 1 };
}

struct Data
{
    bool boolData;
    float floatData;
};

Result<void> LoadEntityFields(
    Api::Entity& entity, 
    Transaction& transaction)
{
    std::int8_t* dest = nullptr;
    
    WEAVERRUNTIME_TRY(Api::LoadEntityField(
        transaction,
        entity,
        Api::BuiltinTypeIdToTypeId(
            Aws::WeaverRuntime::Api::BuiltinTypeId::Dynamic),
        k_dataFieldId,
        &dest));
    
    Data dataValue = *reinterpret_cast<Data*>(dest);
}
```

# 載入已移除實體的欄位資料
<a name="working-with_app-sdk_ent_readwrite_load-removed"></a>

您無法載入 （從狀態結構讀取） 實體欄位資料，用於已從應用程式的擁有權和訂閱區域移除的實體。下列範例會導致 錯誤，因為它因為 而`Api::LoadIndexKey()`呼叫實體`Api::ChangeListAction::Remove`。第二個範例顯示直接在應用程式中存放和載入實體資料的正確方式。

**Example 不正確程式碼的範例**  

```
Result<void> ProcessSubscriptionChanges(Transaction& transaction)
{
    /* ... */
    
    WEAVERRUNTIME_TRY(Api::SubscriptionChangeList subscriptionChangeList, 
        Api::AllSubscriptionEvents(transaction));
    
    for (const Api::SubscriptionEvent& event : 
        subscriptionChangeList.changes)
    {
        switch (event.action)
        {
        case Api::ChangeListAction::Remove:
            {
                std::int8_t* dest = nullptr;
    
                /**
                 * Error!
                 * This calls LoadEntityIndexKey on an entity that
                 * has been removed from the subscription area.
                 */
                WEAVERRUNTIME_TRY(Api::LoadEntityIndexKey(
                    transaction,
                    event.entity,
                    Api::BuiltinTypeIdToTypeId(
                        Api::BuiltinTypeId::Vector3F32),
                    &dest));
    
                AZ::Vector3 position = 
                    *reinterpret_cast<AZ::Vector3*>(dest);
                break;
            }
        }
 
    }

    /* ... */
}
```

**Example 在應用程式中存放和載入實體資料的正確方式範例**  

```
Result<void> ReadAndSaveSubscribedEntityPositions(Transaction& transaction)
{
    static std::unordered_map<Api::EntityId, AZ::Vector3> 
        positionsBySubscribedEntity;

    WEAVERRUNTIME_TRY(Api::SubscriptionChangeList subscriptionChangeList, 
        Api::AllSubscriptionEvents(transaction));

    for (const Api::SubscriptionEvent& event : 
        subscriptionChangeList.changes)
    {
        switch (event.action)
        {
        case Api::ChangeListAction::Add:
            {
                std::int8_t* dest = nullptr;

                /**
                 * Add the position when the entity is added.
                 */
                WEAVERRUNTIME_TRY(Api::LoadEntityIndexKey(
                    transaction,
                    event.entity,
                    Api::BuiltinTypeIdToTypeId(
                        Api::BuiltinTypeId::Vector3F32),
                    &dest));

                AZ::Vector3 position = 
                    *reinterpret_cast<AZ::Vector3*>(dest);
                positionsBySubscribedEntity.emplace(
                    event.entity.descriptor->id, position);

                break;
            }
        case Api::ChangeListAction::Update:
            {
                std::int8_t* dest = nullptr;

                /**
                 * Update the position when the entity is updated.
                 */
                WEAVERRUNTIME_TRY(Api::LoadEntityIndexKey(
                    transaction,
                    event.entity,
                    Api::BuiltinTypeIdToTypeId(
                        Api::BuiltinTypeId::Vector3F32),
                    &dest));

                AZ::Vector3 position = 
                    *reinterpret_cast<AZ::Vector3*>(dest);
                positionsBySubscribedEntity[event.entity.descriptor->id] = 
                    position;

                break;
            }
        case Api::ChangeListAction::Remove:
            {
                /**
                 * Load the position when the entity is removed.
                 */
                AZ::Vector3 position = positionsBySubscribedEntity[
                    event.entity.descriptor->id];

                /**
                 * Do something with position...
                 */
                break;
            }
        }
    }
    
    /* ... */
}
```

# 儲存實體的位置
<a name="working-with_app-sdk_ent_store-position"></a>

您可以使用整數資料結構來存放 （寫入狀態結構） 實體的位置。這些範例使用以下函數：

```
Result<void> StoreEntityIndexKey(
    Transaction& txn, 
    const Entity& entity, 
    TypeId keyTypeId, 
    std::int8_t* src, 
    std::size_t length)
```

**注意**  
您必須提供 `Api::BuiltinTypeId::Vector3F32`給 `Api::StoreEntityIndexKey()`，如下列範例所示。

**Example 使用陣列代表位置的範例**  

```
Result<void> SetEntityPositionByFloatArray(
    Api::Entity& entity, 
    Transaction& transaction)
{
    std::array<float, 3> position = { /* x */ 25, /* y */ 21, /* z */ 0 };
    
    auto* src = reinterpret_cast<std::int8_t*>(position.data());
    std::size_t length = sizeof(position);
    
    WEAVERRUNTIME_TRY(Api::StoreEntityIndexKey(
        transaction,
        entity,
        Api::BuiltinTypeIdToTypeId(Api::BuiltinTypeId::Vector3F32),
        src,
        length));
}
```

**Example 使用 struct代表位置的範例**  

```
struct Position 
{
   float x;
   float y;
   float z;
};

Result<void> SetEntityPositionByStruct(
    Api::Entity& entity, 
    Transaction& transaction)
{
    Position position = { /* x */ 25, /* y */ 21, /* z */ 0 };
    
    auto* src = reinterpret_cast<std::int8_t*>(&position);
    std::size_t length = sizeof(position);
    
    WEAVERRUNTIME_TRY(Api::StoreEntityIndexKey(
        transaction,
        entity,
        Api::BuiltinTypeIdToTypeId(Api::BuiltinTypeId::Vector3F32),
        src,
        length));
}
```

# 載入實體的位置
<a name="working-with_app-sdk_ent_load-position"></a>

您可以使用整數資料結構載入 （從狀態結構讀取） 實體的位置。這些範例使用以下函數：

**注意**  
您必須提供 `Api::BuiltinTypeId::Vector3F32`給 `Api::LoadEntityIndexKey()`，如下列範例所示。

**Example 使用陣列代表位置的範例**  

```
Result<void> GetEntityPosition(Api::Entity& entity, 
    Transaction& transaction)
{
    std::int8_t* dest = nullptr;
    
    WEAVERRUNTIME_TRY(Aws::WeaverRuntime::Api::LoadEntityIndexKey(
        transaction,
        entity,
        Api::BuiltinTypeIdToTypeId(
            Aws::WeaverRuntime::Api::BuiltinTypeId::Vector3F32),
        &dest));
        
    std::array<float, 3> position = 
        *reinterpret_cast<std::array<float, 3>*>(dest);
}
```

**Example 使用 struct代表位置的範例**  

```
struct Position 
{struct
   float x;
   float y;
   float z;
};

Result<void> GetEntityPosition(Api::Entity& entity, Transaction& transaction)
{
    std::int8_t* dest = nullptr;
    
    WEAVERRUNTIME_TRY(Aws::WeaverRuntime::Api::LoadEntityIndexKey(
        transaction,
        entity,
        Api::BuiltinTypeIdToTypeId(
            Aws::WeaverRuntime::Api::BuiltinTypeId::Vector3F32),
        &dest));
        
    Position position = *reinterpret_cast<Position*>(dest);
}
```

# 實體事件
<a name="working-with_app-sdk_events"></a>

您可以在 SimSpace Weaver 應用程式 SDK 中使用下列函數，以取得所有擁有權和訂閱事件：
+ `Result<OwnershipChangeList> OwnershipChanges(Transaction& txn) `
+ `Result<SubscriptionChangeList> AllSubscriptionEvents(Transaction& txn) `

如果您需要回呼驅動實體事件處理，您可以使用 SimSpace Weaver 示範架構。如需詳細資訊，請參閱下列標頭檔案：
+ `sdk-folder/packaging-tools/samples/ext/DemoFramework/include/DemoFramework/EntityEventProcessor.h`

您也可以建立自己的實體事件處理。

**Topics**
+ [逐一查看擁有實體的事件](working-with_app-sdk_events_own.md)
+ [逐一查看已訂閱實體的事件](working-with_app-sdk_events_sub.md)
+ [逐一查看實體的所有權變更事件](working-with_app-sdk_events_change.md)

# 逐一查看擁有實體的事件
<a name="working-with_app-sdk_events_own"></a>

使用 `OwnershipChanges()`取得擁有實體 （應用程式擁有區域中的實體） 的事件清單。函數具有下列簽章：

```
Result<OwnershipChangeList> OwnershipChanges(Transaction& txn)
```

然後，使用迴圈逐一查看實體，如下列範例所示。

**Example 範例**  

```
WEAVERRUNTIME_TRY(Result<Api::OwnershipChangeList> ownershipChangesResult, Api::OwnershipChanges(transaction));

for (const Api::OwnershipChange& event : ownershipChangeList.changes)
{
    Api::Entity entity = event.entity;
    Api::ChangeListAction action = event.action;

    switch (action)
    {
    case Api::ChangeListAction::None:
        // insert code to handle the event
        break;
    case Api::ChangeListAction::Remove:
        // insert code to handle the event
        break;
    case Api::ChangeListAction::Add:
        // insert code to handle the event
        break;
    case Api::ChangeListAction::Update:
        // insert code to handle the event
        break;
    case Api::ChangeListAction::Reject:
        // insert code to handle the event
        break;
    }
}
```

**事件類型**
+ `None` – 實體位於 區域，且其位置和欄位資料未修改。
+ `Remove` – 實體已從 區域移除。
+ `Add` – 實體已新增至 區域。
+ `Update` – 實體位於 區域並已修改。
+ `Reject` – 應用程式無法從 區域移除實體。

**注意**  
如果發生`Reject`事件，應用程式將在下次刻度再次嘗試傳輸。

# 逐一查看已訂閱實體的事件
<a name="working-with_app-sdk_events_sub"></a>

使用 `AllSubscriptionEvents()`取得已訂閱實體 （應用程式訂閱區域中的實體） 的事件清單。函數具有下列簽章：

```
Result<SubscriptionChangeList> AllSubscriptionEvents(Transaction& txn)
```

然後，使用迴圈逐一查看實體，如下列範例所示。

**Example 範例**  

```
WEAVERRUNTIME_TRY(Api::SubscriptionChangeList subscriptionChangeList, Api::AllSubscriptionEvents(transaction));

for (const Api::SubscriptionEvent& event : subscriptionChangeList.changes)
{
    Api::Entity entity = event.entity;
    Api::ChangeListAction action = event.action;

    switch (action)
    {
    case Api::ChangeListAction::None:
        // insert code to handle the event
        break;
    case Api::ChangeListAction::Remove:
        // insert code to handle the event
        break;
    case Api::ChangeListAction::Add:
        // insert code to handle the event
        break;
    case Api::ChangeListAction::Update:
        // insert code to handle the event
        break;
    case Api::ChangeListAction::Reject:
        // insert code to handle the event
        break;
    }
}
```

**事件類型**
+ `None` – 實體位於 區域，且其位置和欄位資料未修改。
+ `Remove` – 實體已從 區域移除。
+ `Add` – 實體已新增至 區域。
+ `Update` – 實體位於 區域並已修改。
+ `Reject` – 應用程式無法從 區域移除實體。

**注意**  
如果發生`Reject`事件，應用程式將在下次刻度再次嘗試傳輸。

# 逐一查看實體的所有權變更事件
<a name="working-with_app-sdk_events_change"></a>

若要取得實體在擁有權區域和訂閱區域之間移動的事件，請比較目前和先前實體擁有權與訂閱事件之間的變更。

您可以透過閱讀來處理這些事件：
+ `Api::SubscriptionChangeList`
+ `Api::OwnershipEvents`

然後，您可以將變更與先前儲存的資料進行比較。

下列範例顯示如何處理實體所有權變更事件。此範例假設，對於在已訂閱實體和擁有實體之間轉換的實體 （任一方向），所有權移除/新增事件會先發生，接著是下一個刻度中的訂閱移除/新增事件。

**Example 範例**  

```
Result<void> ProcessOwnershipEvents(Transaction& transaction)
{
    using EntityIdsByAction =
        std::unordered_map<Api::ChangeListAction, 
        std::vector<Api::EntityId>>;
    using EntityIdSetByAction =
        std::unordered_map<Api::ChangeListAction, 
        std::unordered_set<Api::EntityId>>;
   
    static EntityIdsByAction m_entityIdsByPreviousOwnershipAction;
    
    EntityIdSetByAction entityIdSetByAction;
   
    /**
     * Enumerate Api::SubscriptionChangeList items 
     * and store Add and Remove events.
     */ 
    WEAVERRUNTIME_TRY(Api::SubscriptionChangeList subscriptionEvents, 
        Api::AllSubscriptionEvents(transaction));
   
    for (const Api::SubscriptionEvent& event : subscriptionEvents.changes)
    {
        const Api::ChangeListAction action = event.action;
    
        switch (action)
        {
        case Api::ChangeListAction::Add:
        case Api::ChangeListAction::Remove:
    
            {
                entityIdSetByAction[action].insert(
                    event.entity.descriptor->id);
                break;
            }
        case Api::ChangeListAction::None:
        case Api::ChangeListAction::Update:
        case Api::ChangeListAction::Reject:
            {
                break;
            }
        }
    }
    
    EntityIdsByAction entityIdsByAction;
    
    /**
     * Enumerate Api::OwnershipChangeList items 
     * and store Add and Remove events.
     */
    
    WEAVERRUNTIME_TRY(Api::OwnershipChangeList ownershipChangeList, 
        Api::OwnershipChanges(transaction));
   
    for (const Api::OwnershipChange& event : ownershipChangeList.changes)
    {
        const Api::ChangeListAction action = event.action;
    
        switch (action)
        {
        case Api::ChangeListAction::Add:
        case Api::ChangeListAction::Remove:
            {
                entityIdsByAction[action].push_back(
                    event.entity.descriptor->id);
                break;
            }
        case Api::ChangeListAction::None:
        case Api::ChangeListAction::Update:
        case Api::ChangeListAction::Reject:
            {
                break;
            }
        }
    
    }
      
    std::vector<Api::EntityId> fromSubscribedToOwnedEntities;
    std::vector<Api::EntityId> fromOwnedToSubscribedEntities;
   
    /**
     * Enumerate the *previous* Api::OwnershipChangeList Remove items
     * and check if they are now in 
     * the *current* Api::SubscriptionChangeList Add items.
     *
     * If true, then that means 
     * OnEntityOwnershipChanged(bool isOwned = false)
     */ 
    for (const Api::EntityId& id : m_entityIdsByPreviousOwnershipAction[
        Api::ChangeListAction::Remove])
    {
        if (entityIdSetBySubscriptionAction[
            Api::ChangeListAction::Add].find(id) !=
                entityIdSetBySubscriptionAction[
                Api::ChangeListAction::Add].end())
        {
            fromOwnedToSubscribedEntities.push_back(id);
        }
    }
    
   
    /**
     * Enumerate the *previous* Api::OwnershipChangeList Add items
     * and check if they are now in 
     * the *current* Api::SubscriptionChangeList Remove items.
     *
     * If true, then that means 
     * OnEntityOwnershipChanged(bool isOwned = true)
     */ 
    for (const Api::EntityId& id : m_entityIdsByPreviousOwnershipAction[
        Api::ChangeListAction::Add])
    {
        if (entityIdSetBySubscriptionAction[
            Api::ChangeListAction::Remove].find(id) !=
            
                entityIdSetBySubscriptionAction[
                Api::ChangeListAction::Remove].end())
        {
            fromSubscribedToOwnedEntities.push_back(id);
        }
    }
    
    m_entityIdsByPreviousOwnershipAction = entityIdsByOwnershipAction;
    
    return Success();
}
```

# Result 和錯誤處理
<a name="working-with_app-sdk_result"></a>

`Aws::WeaverRuntime::Result<T>` 類別使用第三方`Outcome`程式庫。您可以使用下列模式來檢查 API 呼叫傳回的 `Result`和 擷取錯誤。

```
void DoBeginUpdate(Application& app)
{
    Result<Transaction> transactionResult = Api::BeginUpdate(app);
    
    if (transactionResult)
    {
        Transaction transaction = 
            std::move(transactionResult).assume_value();
        
        /**
         * Do things with transaction ...
         */
    }
    else
    {     
        ErrorCode errorCode = WEAVERRUNTIME_EXPECT_ERROR(transactionResult);
        /**
         * Macro compiles to:
         * ErrorCode errorCode = transactionResult.assume_error();
         */
    }
}
```

## Result 控制陳述式巨集
<a name="working-with_app-sdk_result_macro"></a>

在傳回類型為 的函數內`Aws::WeaverRuntime::Result<T>`，您可以使用`WEAVERRUNTIME_TRY`巨集，而不是先前的程式碼模式。巨集將執行傳遞給它的函數。如果傳遞的函數失敗，巨集會讓封裝函數傳回錯誤。如果傳遞的函數成功，則執行會繼續進行到下一行。下列範例顯示先前`DoBeginUpdate()`函數的重寫。此版本使用`WEAVERRUNTIME_TRY`巨集，而非if-else控制項結構。請注意，函數的傳回類型為 `Aws::WeaverRuntime::Result<void>`。

```
Aws::WeaverRuntime::Result<void> DoBeginUpdate(Application& app)
{
    /**
     * Execute Api::BeginUpdate() 
     * and return from DoBeginUpdate() if BeginUpdate() fails.
     * The error is available as part of the Result.
     */
    WEAVERRUNTIME_TRY(Transaction transaction, Api::BeginUpdate(m_app));
    
    /**
     * Api::BeginUpdate executed successfully.
     *
     * Do things here.
     */
    
    return Aws::Success();
}
```

如果`BeginUpdate()`失敗，則巨集會提早`DoBeginUpdate()`傳回失敗。您可以使用 `WEAVERRUNTIME_EXPECT_ERROR`巨集從 取得 `Aws::WeaverRuntime::ErrorCode` `BeginUpdate()`。下列範例顯示 `Update()`函數如何在失敗時呼叫 `DoBeginUpdate()` 並取得錯誤代碼。

```
void Update(Application& app)
{
    Result<void> doBeginUpdateResult = DoBeginUpdate(app);
    
    if (doBeginUpdateResult)
    {
        /**
         * Successful.
         */
    }
    else
    {    
        /**
         * Get the error from Api::BeginUpdate().
         */ 
        ErrorCode errorCode = WEAVERRUNTIME_EXPECT_ERROR(doBeginUpdateResult);

    }
}
```

您可以將 的傳回類型變更為 ，`Update()`將 的錯誤碼`BeginUpdate()`提供給呼叫 `Update()` 的函數`Aws::WeaverRuntime::Result<void>`。您可以重複此程序，讓錯誤碼繼續沿著呼叫堆疊傳送。

# 一般和網域類型
<a name="working-with_app-sdk_generics"></a>

 SimSpace Weaver 應用程式 SDK 提供單精度資料類型 `Api::Vector2F32`和 `Api::BoundingBox2F32`，以及雙精度 `Api::Vector2F64`和 `Api::BoundingBox2F64`。這些資料類型是沒有便利方法的被動資料結構。請注意，API 僅使用 `Api::Vector2F32`和 `Api::BoundingBox2F32`。您可以使用這些資料類型來建立和修改訂閱。

 SimSpace Weaver 示範架構提供最小版本的AzCore數學程式庫，其中包含 `Vector3`和 `Aabb` 。如需詳細資訊，請參閱 中的標頭檔案：
+ `sdk-folder/packaging-tools/samples/ext/DemoFramework/include/AzCore/Math`

# 其他應用程式 SDK 操作
<a name="working-with_app-sdk_misc"></a>

**Topics**
+ [AllSubscriptionEvents 和 OwnershipChanges包含上次呼叫的事件](working-with_app-sdk_misc_events-from-last-call.md)
+ [處理後釋放讀取鎖定 SubscriptionChangeList](working-with_app-sdk_misc_release-locks.md)
+ [建立獨立的應用程式執行個體進行測試](working-with_app-sdk_misc_testing-app.md)

# AllSubscriptionEvents 和 OwnershipChanges包含上次呼叫的事件
<a name="working-with_app-sdk_misc_events-from-last-call"></a>

傳回對 的呼叫值，`Api::AllSubscriptionEvents()`並`Api::OwnershipChanges()`包含來自上次呼叫的事件，**而非上次刻度**。在下列範例中， `secondSubscriptionEvents`和 `secondOwnershipChangeList`是空的，因為其函數會在第一次呼叫後立即呼叫。

如果您等待 10 個刻度，然後呼叫 `Api::AllSubscriptionEvents()`和 `Api::OwnershipChanges()`，則其結果將同時包含事件和過去 10 個刻度 （而不是最後一個刻度） 的變更。

**Example 範例**  

```
Result<void> ProcessOwnershipChanges(Transaction& transaction)
{
    WEAVERRUNTIME_TRY(
        Api::SubscriptionChangeList firstSubscriptionEvents,
        Api::AllSubscriptionEvents(transaction));
    WEAVERRUNTIME_TRY(
        Api::OwnershipChangeList firstOwnershipChangeList,
        Api::OwnershipChanges(transaction));
    
    WEAVERRUNTIME_TRY(
        Api::SubscriptionChangeList secondSubscriptionEvents,
        Api::AllSubscriptionEvents(transaction));
    WEAVERRUNTIME_TRY(
        Api::OwnershipChangeList secondOwnershipChangeList,
        Api::OwnershipChanges(transaction));
    
    /**
     * secondSubscriptionEvents and secondOwnershipChangeList are 
     * both empty because there are no changes since the last call.
     */
}
```

**注意**  
函數`AllSubscriptionEvents()`已實作，但函數`SubscriptionEvents()`**未實作**。

# 處理後釋放讀取鎖定 SubscriptionChangeList
<a name="working-with_app-sdk_misc_release-locks"></a>

當您開始更新時，在先前刻度的其他分割區中有遞交資料的共用記憶體區段。這些共用記憶體區段可能會被讀取器鎖定。應用程式無法完全遞交，直到所有讀取器都釋放鎖定為止。作為最佳化，應用程式應該在處理`Api::SubscriptionChangelist`項目後呼叫 `Api::ReleaseReadLeases()`以釋出鎖定。這可減少遞交時間的爭用。 預設會`Api::Commit()`釋出讀取租用，但最佳實務是在處理訂閱更新後手動釋出。

**Example 範例**  

```
Result<void> ProcessSubscriptionChanges(Transaction& transaction)
{
    WEAVERRUNTIME_TRY(ProcessSubscriptionChanges(transaction));
    
    /**
     * Done processing Api::SubscriptionChangeList items.
     * Release read locks. 
     */
        
    WEAVERRUNTIME_EXPECT(Api::ReleaseReadLeases(transaction));
    
    ...
}
```

# 建立獨立的應用程式執行個體進行測試
<a name="working-with_app-sdk_misc_testing-app"></a>

您可以使用 在實際模擬中執行程式碼之前，`Api::CreateStandaloneApplication()`建立獨立的應用程式來測試應用程式邏輯。

**Example 範例**  

```
int main(int argc, char* argv[])
{
    Api::StandaloneRuntimeConfig config = { 
        /* run_for_seconds (the lifetime of the app) */ 3,
        /* tick_hertz (the app clock rate) */ 10 };
    
    Result<Application> applicationResult =
        Api::CreateStandaloneApplication(config);

    ...
}
```

# AWS SimSpace Weaver 示範架構
<a name="working-with_demo-framework"></a>

 AWS SimSpace Weaver 示範架構 （示範架構） 是公用程式程式庫，可用來開發 SimSpace Weaver 應用程式。

**示範架構提供**
+ 程式碼範例和程式設計模式供您使用和檢查
+ 簡化簡單應用程式開發的抽象和公用程式函數
+ 測試 SimSpace Weaver 應用程式 SDK 實驗性功能的簡單方法

我們設計 SimSpace Weaver 了應用程式 SDK 搭配低階 SimSpace Weaver APIs 存取，以提供更高的效能。相反地，我們設計了示範架構，以提供更高階的抽象和 API 存取，讓 SimSpace Weaver APIs 更容易使用。與直接使用 SimSpace Weaver 應用程式 SDK 相比，易用性的成本較低。可以容忍較低效能的模擬 （例如沒有即時效能需求的模擬） 可能是使用示範架構的理想候選者。我們建議您將 SimSpace Weaver 應用程式 SDK 中的原生功能用於複雜的應用程式，因為示範架構不是完整的工具組。

**示範架構包含**
+ 支援並示範以下項目的工作程式碼範例：
  + 應用程式流程管理
  + 回呼驅動實體事件處理
+ 一組第三方公用程式程式庫：
  + spdlog （記錄程式庫）
  + (AZCore數學程式庫） 的最小版本，僅包含：
    + Vector3
    + Aabb
  + cxxopts （命令列選項剖析器程式庫）
+ 專屬於 的公用程式函數 SimSpace Weaver

示範架構包含程式庫、來源檔案和 CMakeLists。檔案包含在 SimSpace Weaver 應用程式 SDK 可分發套件中。

# 使用服務配額
<a name="working-with_quotas"></a>

本節說明如何使用 的服務配額 SimSpace Weaver。**配額**也稱為**限制**。如需服務配額清單，請參閱 [SimSpace Weaver 端點和配額](service-quotas.md)。本節中的 APIs 來自一組**應用程式 APIs**。應用程式 APIs與服務 APIs不同。應用程式 APIs 是 SimSpace Weaver 應用程式 SDK 的一部分。您可以在本機系統的應用程式 SDK 資料夾中找到應用程式 APIs 的文件：

```
sdk-folder\SimSpaceWeaverAppSdk-sdk-version\documentation\index.html
```

**Topics**
+ [取得應用程式的限制](#working-with_quotas_get-app-limits)
+ [取得應用程式使用的資源量](#working-with_quotas_get-app-resources)
+ [重設指標](#working-with_quotas_reset-metrics)
+ [超過限制](#working-with_quotas_exceed-limit)
+ [記憶體不足](#working-with_quotas_out-of-memory)
+ [最佳實務](#working-with_quotas_best-practices)

## 取得應用程式的限制
<a name="working-with_quotas_get-app-limits"></a>

您可以使用**RuntimeLimits**應用程式 API 來查詢應用程式的限制。

```
Result<Limit> RuntimeLimit(Application& app, LimitType type)
```Parameters

**Application& 應用程式**  
應用程式參考。

**LimitType 類型**  
具有下列限制類型的列舉：  

```
enum LimitType {
    Unset = 0,
    EntitiesPerPartition = 1,
    RemoteEntityTransfers = 2,
    LocalEntityTransfers = 3
};
```

下列範例會查詢實體計數限制。

```
WEAVERRUNTIME_TRY(auto entity_limit,
    Api::RuntimeLimit(m_app, Api::LimitType::EntitiesPerPartition))
Log::Info("Entity count limit", entity_limit.value);
```

## 取得應用程式使用的資源量
<a name="working-with_quotas_get-app-resources"></a>

您可以呼叫**RuntimeMetrics**應用程式 API，以取得應用程式使用的資源量：

```
Result<std::reference_wrapper<const AppRuntimeMetrics>> RuntimeMetrics(Application& app) noexcept
```Parameters

**Application& 應用程式**  
應用程式參考。

API 會傳回包含指標struct的 參考。計數器指標會保留執行中的總值，而且只會增加。計量指標會保留可增加或減少的值。應用程式執行時間會在事件增加值時更新計數器。執行時間只會在您呼叫 API 時更新量測值。 SimSpace Weaver 保證參考在應用程式的生命週期內有效。對 API 重複呼叫不會變更參考。

```
struct AppRuntimeMetrics {
    uint64_t total_committed_ticks_gauge,

    uint32_t active_entity_gauge,
    uint32_t ticks_since_reset_counter,

    uint32_t load_field_counter,
    uint32_t store_field_counter,

    uint32_t created_entity_counter,
    uint32_t deleted_entity_counter,

    uint32_t entered_entity_counter,
    uint32_t exited_entity_counter,

    uint32_t rejected_incoming_transfer_counter,
    uint32_t rejected_outgoing_transfer_counter
}
```

## 重設指標
<a name="working-with_quotas_reset-metrics"></a>

**ResetRuntimeMetrics** 應用程式 API 會重設 `AppRuntimeMetrics` 中的值struct。

```
Result<void> ResetRuntimeMetrics(Application& app) noexcept
```

下列範例示範如何在**ResetRuntimeMetrics**應用程式中呼叫 。

```
if (ticks_since_last_report > 100)
{
    auto metrics = WEAVERRUNTIME_EXPECT(Api::RuntimeMetrics(m_app));
    Log::Info(metrics);

    ticks_since_last_report = 0;

    WEAVERRUNTIME_EXPECT(Api::ResetRuntimeMetrics(m_app));
}
```

## 超過限制
<a name="working-with_quotas_exceed-limit"></a>

超過限制的應用程式 API 呼叫將傳回 `ErrorCode::CapacityExceeded`，但實體傳輸除外。 SimSpace Weaver 會在**遞交**和**BeginUpdate**應用程式 API 操作中以非同步方式處理實體傳輸，因此如果傳輸因實體傳輸限制而失敗，則不會有傳回錯誤的特定操作。若要偵測傳輸失敗，您可以將 `rejected_incoming_transfer_counter`和 `rejected_outgoing_transfer_counter`（在 `AppRuntimeMetrics` 中struct) 的目前值與其先前的值進行比較。拒絕的實體不會在分割區中，但應用程式仍然可以模擬它們。

## 記憶體不足
<a name="working-with_quotas_out-of-memory"></a>

SimSpace Weaver 使用垃圾收集器程序來清理和釋放釋放的記憶體。寫入資料的速度可能比垃圾收集器釋放記憶體的速度快。如果發生這種情況，寫入操作可能會超過應用程式的預留記憶體限制。 SimSpace Weaver 會傳回包含 `OutOfMemory`（和其他詳細資訊） 訊息的內部錯誤。如需詳細資訊，請參閱[跨時間分散寫入](#working-with_quotas_best-practices_spread-writes)。

## 最佳實務
<a name="working-with_quotas_best-practices"></a>

下列最佳實務是設計應用程式的一般準則，以避免超過限制。它們可能不適用於您的特定應用程式設計。

### 經常監控並放慢速度
<a name="working-with_quotas_best-practices_monitor"></a>

您應該經常監控指標，並減慢接近限制的操作。

### 避免超過訂閱限制和轉移限制
<a name="working-with_quotas_best-practices_subscription-and-xfer"></a>

如果可能，設計您的模擬以減少遠端訂閱和實體傳輸的數量。您可以使用置放群組在同一個工作者上放置多個分割區，並減少工作者之間遠端實體傳輸的需求。

### 跨時間分散寫入
<a name="working-with_quotas_best-practices_spread-writes"></a>

刻度中的更新數量和大小可能會對遞交交易所需的時間和記憶體產生重大影響。大型記憶體需求可能會導致應用程式執行期用盡記憶體。您可以將寫入分散到不同時間，以降低每個刻度的平均更新總大小。這有助於改善效能並避免超過限制。建議您不要在每個刻度上寫入超過 12 MB 的平均值，或每個實體寫入超過 1.5 KB 的平均值。

# 偵錯模擬
<a name="working-with_debugging"></a>

您可以使用下列方法來取得模擬的相關資訊。

**主題**
+ [使用SimSpace Weaver Local並查看主控台輸出](#working-with_debugging_use-local)
+ [查看 Amazon CloudWatch Logs 中的日誌](#working-with_debugging_logs)
+ [使用 **describe** API 呼叫](#working-with_debugging_api)
+ [連接用戶端](#working-with_debugging_client)

## 使用SimSpace Weaver Local並查看主控台輸出
<a name="working-with_debugging_use-local"></a>

建議您先在本機開發模擬，然後在 中執行它們 AWS 雲端。當您使用 執行 時，可以直接檢視主控台輸出SimSpace Weaver Local。如需詳細資訊，請參閱[中的本機開發 SimSpace Weaver](working-with_local-development.md)。

## 查看 Amazon CloudWatch Logs 中的日誌
<a name="working-with_debugging_logs"></a>

當您在應用程式的主控台輸出中執行模擬 AWS 雲端 時， 會傳送至 Amazon CloudWatch Logs 中的日誌串流。您的模擬也會寫入其他日誌資料。如果您希望模擬寫入日誌資料，則必須在模擬結構描述中啟用記錄。如需詳細資訊，請參閱[SimSpace Weaver Amazon CloudWatch Logs 中的日誌](cloudwatch-logs.md)。

**警告**  
您的模擬可以產生大量日誌資料。日誌資料可以快速成長。您應該密切監看日誌，並在不再需要它們時停止模擬。記錄可能會產生大量成本。

## 使用 **describe** API 呼叫
<a name="working-with_debugging_api"></a>

您可以使用下列服務 APIs在 中取得模擬的相關資訊 AWS 雲端。
+ **ListSimulations** – 取得 中所有模擬的清單 AWS 雲端。  
**Example 範例**  

  ```
  aws simspaceweaver list-simulations
  ```
+ **DescribeSimulation** – 取得模擬的詳細資訊。  
**Example 範例**  

  ```
  aws simspaceweaver describe-simulation --simulation MySimulation
  ```
+ **DescribeApp** – 取得應用程式的詳細資訊。  
**Example 範例**  

  ```
  aws simspaceweaver describe-app --simulation MySimulation --domain MyCustomDomain --app MyCustomApp
  ```

如需 SimSpace Weaver APIs的詳細資訊，請參閱 [SimSpace Weaver API 參考](api-reference.md)。

## 連接用戶端
<a name="working-with_debugging_client"></a>

您可以將用戶端連線至執行中的自訂或服務應用程式，而您在模擬結構描述`endpoint_config`中使用 定義。 SimSpace Weaver 應用程式 SDK 包含範例用戶端，您可以用來檢視範例應用程式。您可以查看這些範例用戶端的原始程式碼和範例應用程式，了解如何建立自己的用戶端。如需如何建置和執行範例用戶端的詳細資訊，請參閱 中的教學課程[入門 SimSpace Weaver](getting-started.md)。

您可以在下列資料夾中找到範例用戶端的原始程式碼：
+ `sdk-folder\packaging-tools\clients\PathfindingSampleClients\`

# 偵錯本機模擬
<a name="working-with_debugging_local"></a>

您可以使用 偵錯您的SimSpace Weaver Local應用程式Microsoft Visual Studio。如需如何使用 偵錯的詳細資訊Visual Studio，請參閱 [Microsoft Visual Studio documentation。](https://learn.microsoft.com/en-us/visualstudio/debugger/debugger-feature-tour)

**偵錯本機模擬**

1. 請確定您的 `schema.yaml` 位於您的工作目錄中。

1. 在 中**Visual Studio**，開啟您要偵錯的每個應用程式的內容選單 （例如 `PathfindingSampleLocalSpatial`或 `PathfindingSampleLocalView`)，並在偵錯區段中設定工作目錄。

1. 開啟您要偵錯之應用程式的內容選單，然後選取**設定為啟動專案**。

1. 選擇 F5以開始偵錯應用程式。

偵錯模擬的要求與正常執行模擬的要求相同。您必須開始結構描述中指定的空間應用程式數量。例如，如果您的結構描述指定了 2x2 網格，而且您在偵錯模式下啟動空間應用程式，則在您啟動另外 3 個空間應用程式 （在偵錯模式下或不在偵錯模式下） 之前，模擬不會執行。

若要偵錯自訂應用程式，您必須先啟動空間應用程式，然後在偵錯工具中啟動自訂應用程式。

請注意，您的模擬會在鎖定步驟中執行。一旦應用程式達到中斷點，所有其他應用程式都會暫停。從該中斷點繼續之後，其他應用程式將會繼續。

# 自訂容器
<a name="working-with_custom-containers"></a>

AWS SimSpace Weaver 應用程式會在容器化 Amazon Linux 2(AL2) 環境中執行。在 中 AWS 雲端， 會在從 Amazon Elastic Container Registry (Amazon ECR) 提供的`amazonlinux:2`映像建置的 Docker 容器中 SimSpace Weaver 執行模擬。您可以建立自訂 Docker 映像檔，將其存放在 Amazon ECR 中，並將該映像檔用於模擬，而不是我們提供的預設 Docker 映像檔。

您可以使用自訂容器來管理您的軟體相依性，並包含不在標準 Docker 映像中的其他軟體元件。例如，您可以將應用程式使用的公開可用的軟體程式庫新增至容器，並只將自訂程式碼放入應用程式 zip 檔案中。

**重要**  
我們僅支援 Amazon ECR 儲存庫中託管的 AL2 Docker 映像，無論是在 Amazon ECR Public Gallery 或您的私有 Amazon ECR 登錄檔中。我們不支援在 Amazon ECR 外部託管的 Docker 映像。如需 Amazon ECR 的詳細資訊，請參閱 *[Amazon Elastic Container Registry 文件](https://docs.aws.amazon.com/ecr)*。

**Topics**
+ [建立自訂容器](working-with_custom-containers_create.md)
+ [修改專案以使用自訂容器](working-with_custom-containers_modify-project.md)
+ [關於自訂容器的常見問答集](working-with_custom-containers_faq.md)
+ [對自訂容器進行故障診斷](working-with_custom-containers_troubleshooting.md)

# 建立自訂容器
<a name="working-with_custom-containers_create"></a>

這些指示假設您知道如何使用 Docker 和 Amazon Elastic Container Registry (Amazon ECR)。如需 Amazon ECR 的詳細資訊，請參閱《*[Amazon ECR 使用者指南](https://docs.aws.amazon.com/AmazonECR/latest/userguide)*》。

**先決條件**
+ 您用來執行這些動作的 IAM 身分 （使用或角色） 具有使用 Amazon ECR 的正確許可
+ Docker 安裝在您的本機系統上

**建立自訂容器**

1. 建立 `Dockerfile`。

   `Dockerfile` 執行 AWS SimSpace Weaver 應用程式的 會從 Amazon ECR 中的Amazon Linux 2映像開始。

   ```
   # parent image required to run AWS SimSpace Weaver apps
   FROM public.ecr.aws/amazonlinux/amazonlinux:2
   ```

1. 建置您的 `Dockerfile`。

1. 將容器映像上傳至 Amazon ECR。
   + [使用 AWS 管理主控台。](https://docs.aws.amazon.com/AmazonECR/latest/userguide/getting-started-console.html)
   + [使用 AWS Command Line Interface。](https://docs.aws.amazon.com/AmazonECR/latest/userguide/getting-started-cli.html)
**注意**  
如果您在嘗試將容器映像上傳至 Amazon ECR `AccessDeniedException`時發生錯誤，您的 IAM 身分 （使用者或角色） 可能沒有使用 Amazon ECR 的必要許可。您可以將 `AmazonEC2ContainerRegistryPowerUser` AWS 受管政策連接至 IAM 身分，然後再試一次。如需如何連接政策的詳細資訊，請參閱*AWS Identity and Access Management 《 使用者指南*》中的[新增和移除 IAM 身分許可](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html)。

# 修改專案以使用自訂容器
<a name="working-with_custom-containers_modify-project"></a>

這些指示假設您已經知道如何使用 ， AWS SimSpace Weaver 並希望讓您的應用程式儲存和開發工作流程更有效率 AWS 雲端 。

**先決條件**
+ 您在 Amazon Elastic Container Registry (Amazon ECR) 中有自訂容器。如需建立自訂容器的詳細資訊，請參閱 [建立自訂容器](working-with_custom-containers_create.md)。

**若要修改專案以使用自訂容器**

1. 將許可新增至專案的模擬應用程式角色，以使用 Amazon ECR。

   1. 如果您還沒有具有下列許可的 IAM 政策，請建立政策。我們建議使用政策名稱 `simspaceweaver-ecr`。如需如何建立 IAM 政策的詳細資訊，請參閱*AWS Identity and Access Management 《 使用者指南*》中的[建立 IAM 政策](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create.html)。

      ```
      {
          "Version": "2012-10-17",		 	 	 
          "Statement": [
              {
                  "Sid": "Statement",
                  "Effect": "Allow",
                  "Action": [
                      "ecr:BatchGetImage",
                      "ecr:GetDownloadUrlForLayer",
                      "ecr:GetAuthorizationToken"
                  ],
                  "Resource": "*"
              }
          ]
      }
      ```

   1. 尋找專案模擬應用程式角色的名稱：

      1. 在文字編輯器中，開啟 CloudFormation 範本：

         ```
         sdk-folder\PackagingTools\sample-stack-template.yaml
         ```

      1. 在 下尋找 `RoleName` 屬性`WeaverAppRole`。值是專案模擬應用程式角色的名稱。  
**Example**  

         ```
         AWSTemplateFormatVersion: "2010-09-09"
         Resources:
           WeaverAppRole:
             Type: 'AWS::IAM::Role'
             Properties:
               RoleName: 'weaver-MySimulation-app-role'
               AssumeRolePolicyDocument:
                 Version: "2012-10-17"		 	 	 
                 Statement:
                 - Effect: Allow
                   Principal:
                     Service:
                       - 'simspaceweaver.amazonaws.com'
         ```

   1. 將`simspaceweaver-ecr`政策連接至專案的模擬應用程式角色。如需如何連接政策的詳細資訊，請參閱*AWS Identity and Access Management 《 使用者指南*》中的[新增和移除 IAM 身分許可](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html)。

   1. 導覽至 `sdk-folder`並執行下列命令來更新範例 SimSpace Weaver 堆疊：

      ```
      python setup.py --cloudformation
      ```

1. 在專案的模擬結構描述中指定您的容器映像。
   + 您可以在 下新增選用`default_image`屬性`simulation_properties`，以指定所有網域的預設自訂容器映像。
   + 針對您要使用自訂容器映像`app_config`的網域，在 中新增 `image` 屬性。指定 Amazon ECR 儲存庫 URI 做為值。您可以為每個網域指定不同的映像。
     + 如果`image`未針對網域指定 `default_image` 且已指定 ，則該網域中的應用程式會使用預設映像。
     + 如果 `image` 未指定網域，`default_image`且未指定，則該網域中的應用程式會在標準 SimSpace Weaver 容器中執行。  
**Example 包含自訂容器設定的結構描述程式碼片段**  

   ```
   sdk_version: "1.17.0"
   simulation_properties:
     log_destination_service: "logs"
     log_destination_resource_name: "MySimulationLogs"
     default_entity_index_key_type: "Vector3<f32>"
     default_image: "111122223333.dkr.ecr.us-west-2.amazonaws.com/my-ecr-repository:latest" # image to use if no image specified for a domain
   domains:
     MyCustomDomain:
       launch_apps_via_start_app_call: {}
       app_config:
         package: "s3://weaver-myproject-111122223333-us-west-2/MyViewApp.zip" 
         launch_command: ["MyViewApp"]  
         required_resource_units:
           compute: 1
         endpoint_config:
           ingress_ports:
             - 7000
         image: "111122223333.dkr.ecr.us-west-2.amazonaws.com/my-ecr-repository:latest" # custom container image to use for this domain 
     MySpatialDomain:
       launch_apps_by_partitioning_strategy:
         partitioning_strategy: "MyGridPartitioning"
         grid_partition:
           x: 2
           y: 2
       app_config:
         package: "s3://weaver-myproject-111122223333-us-west-2/MySpatialApp.zip" 
         launch_command: ["MySpatialApp"] 
         required_resource_units:
           compute: 1
         image: "111122223333.dkr.ecr.us-west-2.amazonaws.com/my-ecr-repository:latest" # custom container image to use for this domain
   ```

1. 照常建置和上傳您的專案。

# 關於自訂容器的常見問答集
<a name="working-with_custom-containers_faq"></a>

## Q1. (問題 1)：如果我想要變更容器的內容該怎麼辦？
<a name="working-with_custom-containers_faq_q1"></a>
+ **針對執行中的模擬** – 您無法變更執行中模擬的容器。您必須建立新的容器，並啟動使用該容器的新模擬。
+ **對於新的模擬** – 建立新的容器，將其上傳至 Amazon Elastic Container Registry (Amazon ECR)，然後啟動使用該容器的新模擬。

## Q2. (問題 2): 如何變更模擬的容器映像？
<a name="working-with_custom-containers_faq_q2"></a>
+ **針對執行中的模擬** – 您無法變更執行中模擬的容器。您必須啟動使用新容器的新模擬。
+ **對於新的模擬** – 在專案的模擬結構描述中指定新的容器映像。如需詳細資訊，請參閱[修改專案以使用自訂容器](working-with_custom-containers_modify-project.md)。

# 對自訂容器進行故障診斷
<a name="working-with_custom-containers_troubleshooting"></a>

**Topics**
+ [將映像上傳至 Amazon Elastic Container Registry (Amazon ECR) 時的 AccessDeniedException](working-with_custom-containers_troubleshooting_access-denied.md)
+ [使用自訂容器的模擬無法啟動](working-with_custom-containers_troubleshooting_no-start.md)

# 將映像上傳至 Amazon Elastic Container Registry (Amazon ECR) 時的 AccessDeniedException
<a name="working-with_custom-containers_troubleshooting_access-denied"></a>

如果您在嘗試將容器映像上傳至 Amazon ECR `AccessDeniedException`時發生錯誤，您的 IAM 身分 （使用者或角色） 可能沒有使用 Amazon ECR 的必要許可。您可以將 `AmazonEC2ContainerRegistryPowerUser` AWS 受管政策連接至 IAM 身分，然後再試一次。如需如何連接政策的詳細資訊，請參閱*AWS Identity and Access Management 《 使用者指南*》中的[新增和移除 IAM 身分許可](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html)。

# 使用自訂容器的模擬無法啟動
<a name="working-with_custom-containers_troubleshooting_no-start"></a>

**對秘訣進行故障診斷**
+ 如果您的模擬已啟用記錄，請檢查您的錯誤日誌。
+ 在沒有自訂容器的情況下測試模擬。
+ 在本機測試模擬。如需詳細資訊，請參閱[中的本機開發 SimSpace Weaver](working-with_local-development.md)。

# 使用 Python
<a name="working-with_python"></a>

您可以針對 SimSpace Weaver 應用程式和用戶端使用 Python。Python 軟體開發套件 (Python SDK) 包含在標準 SimSpace Weaver 應用程式開發套件可分發套件中。使用 Python 開發的運作方式與其他支援語言的開發類似。

**重要**  
SimSpace Weaver 僅支援 Python 3.9 版。

**重要**  
SimSpace Weaver 支援 Python 需要 1.15.0 SimSpace Weaver 版或更新版本。

**Topics**
+ [建立 Python 專案](working-with_python_create-project.md)
+ [啟動 Python 模擬](working-with_python_start-sim.md)
+ [範例 Python 用戶端](working-with_python_client.md)
+ [有關使用 Python 的常見問題](working-with_python_faq.md)
+ [故障診斷 Python 相關問題](working-with_python_troubleshooting.md)

# 建立 Python 專案
<a name="working-with_python_create-project"></a>

## Python 自訂容器
<a name="working-with_python_create-project_container"></a>

若要在 中執行 Python 型 SimSpace Weaver 模擬 AWS 雲端，您可以建立包含必要相依性的自訂容器。如需詳細資訊，請參閱[自訂容器](working-with_custom-containers.md)。

Python 自訂容器必須包含下列項目：
+ gcc
+ openssl-devel
+ bzip2-devel
+ libffi-devel
+ wget
+ tar
+ gzip
+ make
+ Python (3.9 版）

如果您使用 `PythonBubblesSample` 範本來建立專案，您可以執行`quick-start.py`指令碼 （位於專案的 `tools` 資料夾） 來建立具有必要相依性的 Docker 映像。指令碼會將映像上傳至 Amazon Elastic Container Registry (Amazon ECR)。

`quick-start.py` 指令碼使用以下 `Dockerfile`：

```
FROM public.ecr.aws/amazonlinux/amazonlinux:2
RUN yum -y install gcc openssl-devel bzip2-devel libffi-devel 
RUN yum -y install wget
RUN yum -y install tar
RUN yum -y install gzip
RUN yum -y install make
WORKDIR /opt
RUN wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz 
RUN tar xzf Python-3.9.0.tgz
WORKDIR /opt/Python-3.9.0
RUN ./configure --enable-optimizations
RUN make altinstall
COPY requirements.txt ./
RUN python3.9 -m pip install --upgrade pip
RUN pip3.9 install -r requirements.txt
```

您可以將自己的相依性新增至 `Dockerfile`：

```
RUN yum -y install dependency-name
```

`requirements.txt` 檔案包含`PythonBubblesSample`範例模擬所需的 Python 套件清單：

```
Flask==2.1.1
```

您可以將自己的 Python 套件相依性新增至 `requirements.txt`：

```
package-name==version-number
```

`Dockerfile` 和 `requirements.txt`位於專案的 `tools`資料夾中。

**重要**  
在技術上，您不需要搭配 Python 模擬使用自訂容器，但強烈建議您使用自訂容器。我們提供的標準 Amazon Linux 2 (AL2) 容器沒有 Python。因此，如果您不使用具有 Python 的自訂容器，則必須在上傳到的每個應用程式 zip 檔案中包含 Python 和所需的相依性 SimSpace Weaver。

# 啟動 Python 模擬
<a name="working-with_python_start-sim"></a>

您可以在 中SimSpace Weaver Local和 SimSpace Weaver 中，以與一般模擬相同的方式啟動 Python 型 SimSpace Weaver 模擬 AWS 雲端。如需詳細資訊，請參閱 中的教學課程[入門 SimSpace Weaver](getting-started.md)。

`PythonBubblesSample` 包含自己的 Python 範例用戶端。如需詳細資訊，請參閱[範例 Python 用戶端](working-with_python_client.md)。

# 範例 Python 用戶端
<a name="working-with_python_client"></a>

如果您使用 `PythonBubblesSample` 範本建立專案，則您的專案會包含 Python 範例用戶端。您可以使用範例用戶端來檢視`PythonBubblesSample`模擬。您也可以使用範例用戶端做為起點來建立自己的 Python 用戶端。

下列程序假設您已建立`PythonBubblesSample`專案並啟動其模擬。

**啟動 Python 用戶端**

1. 在**命令提示字元視窗中**，前往`PyBubbleClient`範例專案資料夾。

   ```
   cd sdk-folder\Clients\HTTP\PyBubbleClient
   ```

1. 執行 Python 用戶端。

   ```
   python tkinter_client.py --host ip-address --port port-number
   ```

**參數**  
**host**  
模擬的 IP 地址。對於在 中啟動的模擬 AWS 雲端，您可以在 [SimSpace Weaver 主控台](https://console.aws.amazon.com/simspaceweaver)中找到模擬的 IP 地址，或使用快速入門教學課程中[取得自訂應用程式的 IP 地址和連接埠號碼取得 IP 地址和連接埠號碼](working-with_get-ip.md)的 中的程序。對於本機模擬，請使用 `127.0.0.1`做為 IP 地址。  
**port**  
模擬的連接埠號碼。對於在 中啟動的模擬 AWS 雲端，這是`Actual`連接埠號碼。您可以在 [SimSpace Weaver 主控台](https://console.aws.amazon.com/simspaceweaver)中找到模擬的連接埠號碼，或使用快速入門教學課程中[取得自訂應用程式的 IP 地址和連接埠號碼取得 IP 地址和連接埠號碼](working-with_get-ip.md)的程序。對於本機模擬，請使用 `7000`做為連接埠號碼。  
**simsize**  
要在用戶端中顯示的實體數量上限。

# 有關使用 Python 的常見問題
<a name="working-with_python_faq"></a>

## Q1. (問題 1)：支援哪些版本的 Python？
<a name="working-with_python_faq_q1"></a>

SimSpace Weaver 僅支援 Python 3.9 版。

# 故障診斷 Python 相關問題
<a name="working-with_python_troubleshooting"></a>

**Topics**
+ [自訂容器建立期間失敗](working-with_python_troubleshooting_create-container-failure.md)
+ [您的 Python 模擬無法啟動](working-with_python_troubleshooting_no-start.md)
+ [Python 模擬或檢視用戶端擲回 ModuleNotFound 錯誤](working-with_python_troubleshooting_module-not-found.md)

# 自訂容器建立期間失敗
<a name="working-with_python_troubleshooting_create-container-failure"></a>

如果您在執行`no basic auth credentials`後收到錯誤`quick-start.py`，則 Amazon ECR 的臨時登入資料可能會出現問題。使用您的 AWS 區域 ID 和 AWS 帳戶號碼執行下列命令：

```
aws ecr get-login-password --region region | docker login --username AWS --password-stdin account_id.dkr.ecr.region.amazonaws.com
```

**Example**  

```
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.region.amazonaws.com
```

**重要**  
請確定 AWS 區域 您指定的 與您用於模擬的相同。使用 AWS 區域 SimSpace Weaver 支援的其中一個 。如需詳細資訊，請參閱[SimSpace Weaver 端點和配額](service-quotas.md)。

執行 `aws ecr`命令後，請`quick-start.py`再次執行 。

**要檢查的其他疑難排解資源**
+ [對自訂容器進行故障診斷](working-with_custom-containers_troubleshooting.md)
+ 《[Amazon ECR 使用者指南》中的 Amazon ECR 疑難排解](https://docs.aws.amazon.com/AmazonECR/latest/userguide/troubleshooting.html) **
+ 《[Amazon ECR 使用者指南》中的使用 Amazon ECR 設定](https://docs.aws.amazon.com/AmazonECR/latest/userguide/get-set-up-for-amazon-ecr.html) **

# 您的 Python 模擬無法啟動
<a name="working-with_python_troubleshooting_no-start"></a>

您可能會在模擬的管理日誌中看到`Unable to start app`錯誤。如果您的自訂容器建立失敗，可能會發生這種情況。如需詳細資訊，請參閱[自訂容器建立期間失敗](working-with_python_troubleshooting_create-container-failure.md)。如需日誌的詳細資訊，請參閱 [SimSpace Weaver Amazon CloudWatch Logs 中的日誌](cloudwatch-logs.md)。

如果您確定您的容器沒有任何問題，請檢查應用程式的 Python 原始程式碼。您可以使用 SimSpace Weaver Local 來測試您的應用程式。如需詳細資訊，請參閱[中的本機開發 SimSpace Weaver](working-with_local-development.md)。

# Python 模擬或檢視用戶端擲回 ModuleNotFound 錯誤
<a name="working-with_python_troubleshooting_module-not-found"></a>

當找不到所需的 Python 套件時，Python 會擲回`ModuleNotFound`錯誤。

如果您的模擬位於 中 AWS 雲端，請確定您的自訂容器具有 中列出的所有必要相依性`requirements.txt`。如果您編輯 ，請記得`quick-start.py`再次執行 `requirements.txt`。

如果`PythonBubblesSample`用戶端發生錯誤，請使用 `pip` 安裝指定的套件：

```
pip install package-name==version-number
```

# 支援其他引擎
<a name="working-with_engines"></a>

您可以搭配 使用自己的自訂C\$1\$1引擎 SimSpace Weaver。我們目前正在開發下列引擎的支援。這些引擎各有不同的文件。

**重要**  
與此處列出的引擎整合是實驗性的。它們可供預覽。

**引擎**
+ [Unity](#working-with_engines_unity) （最低版本為 2022.3.19.F1)
+ [Unreal Engine](#working-with_engines_unreal) （最低版本 5.0)

## Unity
<a name="working-with_engines_unity"></a>

您必須先安裝Unity開發環境，才能使用 Unity 建置 SimSpace Weaver 模擬。如需詳細資訊，請參閱不同的指示：

```
sdk-folder\Unity-Guide.pdf
```

## Unreal Engine
<a name="working-with_engines_unreal"></a>

您必須從原始碼建置Unreal Engine專用伺服器。SimSpaceWeaverAppSdkDistributable 包含適用於 的 PathfindingSample 版本Unreal Engine。如需詳細資訊，請參閱不同的指示：

```
sdk-folder\Unreal-Engine-Guide.pdf
```

# 搭配 使用授權軟體 AWS SimSpace Weaver
<a name="working-with_byol"></a>

AWS SimSpace Weaver 可讓您使用您選擇的模擬引擎和內容來建置模擬。在使用 時 SimSpace Weaver，您需負責取得、維護和遵守您在模擬中使用的任何軟體或內容的授權條款。驗證您的授權合約可讓您在虛擬託管環境中部署軟體和內容。

# 使用 管理您的 資源 AWS CloudFormation
<a name="working-with_cloudformation"></a>

您可以使用 AWS CloudFormation 來管理您的 AWS SimSpace Weaver 資源。 CloudFormation 是一項獨立的 AWS 服務，可協助您以程式碼形式指定、佈建和管理 AWS 基礎設施。 CloudFormation 使用 建立 JSON 或 YAML 檔案，稱為*[範本](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html#cfn-concepts-templates template)*。您的範本會指定基礎設施的詳細資訊。 CloudFormation 使用您的範本將基礎設施佈建為單一單位，稱為*[堆疊](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html#w2ab1b5c15b9)*。刪除堆疊時，您可以同時 CloudFormation 刪除堆疊中的所有項目。您可以使用標準原始碼管理程序來管理範本 （例如，在 [Git](https://git-scm.com/) 等版本控制系統中追蹤範本）。如需 的詳細資訊 CloudFormation，請參閱[https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide)》。

**您的模擬資源**  
在 中 AWS，*資源*是您可以使用的實體。範例包括 Amazon EC2 執行個體、Amazon S3 儲存貯體或 IAM 角色。您的 SimSpace Weaver 模擬是 資源。在組態中，您通常會以 的形式指定 AWS 資源`AWS::service::resource`。對於 SimSpace Weaver，您可以將模擬資源指定為 `AWS::SimSpaceWeaver::Simulation`。如需 中模擬資源的詳細資訊 CloudFormation，請參閱*AWS CloudFormation 《 使用者指南*》中的[SimSpace Weaver](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-simspaceweaver-simulation.html)一節。

**如何 CloudFormation 搭配 使用 SimSpace Weaver？**  
您可以建立 CloudFormation 範本，指定您要佈建 AWS 的資源。您的範本可以指定整個架構、架構的一部分，或小型解決方案。例如，您可以為 SimSpace Weaver 解決方案指定 架構，其中包含 Amazon S3 儲存貯體、IAM 許可、Amazon Relational Database Service 或 Amazon DynamoDB 中的支援資料庫，以及您的 `Simulation` 資源。然後，您可以使用 CloudFormation 將所有這些資源佈建為單位，並同時佈建。

**Example 範本，可建立 IAM 資源並啟動模擬**  
下列範例範本會建立 IAM 角色和許可， SimSpace Weaver 這些角色和許可需要在您的帳戶中執行動作。 SimSpace Weaver 應用程式開發套件指令碼會在您建立專案 AWS 區域 時，於特定 中建立角色和許可，但您可以使用 CloudFormation 範本將模擬部署至另一個 AWS 區域 ，而無需再次執行指令碼。例如，您可以這樣做來設定備份模擬，以用於災難復原。  
在此範例中，原始模擬名稱為 `MySimulation`。結構描述的儲存貯體已存在於 AWS 區域 中，其中 CloudFormation 將建置堆疊。儲存貯體包含已正確設定在其中執行模擬的結構描述版本 AWS 區域。請記住，結構描述會指定應用程式 zip 檔案的位置，這是與模擬相同 AWS 區域 中的 Amazon S3 儲存貯體。當 CloudFormation 建置堆疊 AWS 區域 時，應用程式 zip 儲存貯體和檔案必須已存在於 中，否則模擬不會啟動。請注意，此範例中的儲存貯體名稱包含 AWS 區域，但這無法判斷儲存貯體的實際位置。您必須確定儲存貯體實際位於 AWS 區域 （您可以在 Amazon S3 主控台、使用 Amazon S3 APIs 或 中的 Amazon S3 命令來檢查儲存貯體屬性 AWS CLI)。  
此範例使用 中的一些內建函數和參數 CloudFormation 來執行變數替換。如需詳細資訊，請參閱*AWS CloudFormation 《 使用者指南*》中的[內部函數參考](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html)和[虛擬參數參考](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html)。  

```
AWSTemplateFormatVersion: 2010-09-09
Resources:
  WeaverAppRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: SimSpaceWeaverAppRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            Service:
              - simspaceweaver.amazonaws.com
          Action:
            - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: SimSpaceWeaverAppRolePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
            - Effect: Allow
              Action:
                - logs:PutLogEvents
                - logs:DescribeLogGroups
                - logs:DescribeLogStreams
                - logs:CreateLogGroup
                - logs:CreateLogStream
              Resource: *
            - Effect: Allow
              Action:
                - cloudwatch:PutMetricData
              Resource: *
            - Effect: Allow
              Action:
                - s3:ListBucket
                - s3:PutObject
                - s3:GetObject
              Resource: *
  MyBackupSimulation:
    Type: AWS::SimSpaceWeaver::Simulation
    Properties:
      Name: !Sub 'mySimulation-${AWS::Region}'
      RoleArn: !GetAtt WeaverAppRole.Arn
      SchemaS3Location:
        BucketName: !Sub 'weaver-mySimulation-${AWS::AccountId}-schemas-${AWS::Region}'
        ObjectKey: !Sub 'schema/mySimulation-${AWS::Region}-schema.yaml'
```

# 搭配 使用快照 AWS CloudFormation
<a name="working-with_cloudformation_snapshots"></a>

[快照](working-with_snapshots.md)是模擬的備份。下列範例會從快照而非結構描述啟動新的模擬。此範例中的快照是從 SimSpace Weaver 應用程式 SDK 專案 simulation 建立。 會 CloudFormation 建立新的模擬資源，並使用快照中的資料來初始化它。新的模擬可以具有`MaximumDuration`與原始模擬不同的 。

我們建議您製作並使用原始模擬應用程式角色的副本。如果您刪除模擬的堆疊，則可以刪除原始模擬 CloudFormation 的應用程式角色。

```
Description: "Example - Start a simulation from a snapshot"
Resources:
  MyTestSimulation:
    Type: "AWS::SimSpaceWeaver::Simulation"
    Properties:
      MaximumDuration: "2D"
      Name: "MyTestSimulation_from_snapshot"
      RoleArn: "arn:aws:iam::111122223333:role/weaver-MyTestSimulation-app-role-copy"   
      SnapshotS3Location:
        BucketName: "weaver-mytestsimulation-111122223333-artifacts-us-west-2"
        ObjectKey: "snapshot/MyTestSimulation_22-12-15_12_00_00-230428-1207-13.zip"
```

# 快照
<a name="working-with_snapshots"></a>

您可以隨時建立*快照*來備份模擬實體資料。 會在 Amazon S3 儲存貯體中 SimSpace Weaver 建立 .zip 檔案。您可以使用快照建立新的模擬。使用快照中存放的實體資料 SimSpace Weaver 初始化新模擬的狀態結構、啟動建立快照時正在執行的空間和服務應用程式，並將時鐘設定為適當的 tick。從快照而非結構描述檔案 SimSpace Weaver 取得模擬的組態。您的應用程式 .zip 檔案必須位於 Amazon S3 中與原始模擬相同的位置。您必須分別啟動任何自訂應用程式。

**主題**
+ [快照的使用案例](#working-with_snapshots_use-cases)
+ [使用 SimSpace Weaver 主控台來使用快照](working-with_snapshots_console.md)
+ [使用 AWS CLI 處理快照](working-with_snapshots_cli.md)
+ [搭配 使用快照 AWS CloudFormation](working-with_cloudformation_snapshots.md)
+ [有關快照的常見問答集](working-with_snapshots_faq.md)

## 快照的使用案例
<a name="working-with_snapshots_use-cases"></a>

### 返回先前的狀態並探索分支案例
<a name="working-with_snapshots_use-case_branching"></a>

您可以建立模擬的快照，將其儲存為特定狀態。然後，您可以從該快照建立多個新的模擬，並探索可從該狀態分支的不同案例。

### 災難復原和安全性最佳實務
<a name="working-with_snapshots_use-cases_best-practice"></a>

我們建議您定期備份模擬，特別是對於執行超過 1 小時或使用多個工作者的模擬。備份可協助您從災難和安全事件中復原。快照可讓您備份模擬。快照需要您的應用程式 .zip 檔案與之前位於 Amazon S3 的相同位置。如果您需要能夠將應用程式 .zip 檔案移至另一個位置，則必須使用自訂備份解決方案。

如需其他最佳實務的詳細資訊，請參閱 [使用 時的最佳實務 SimSpace Weaver](best-practices.md)和 [的安全最佳實務 SimSpace Weaver](security_best-practices.md)。

### 延長模擬的持續時間
<a name="working-with_snapshots_use-cases_extend-duration"></a>

您的*模擬資源*是模擬中的表示法 SimSpace Weaver。所有模擬資源都有一個`MaximumDuration`設定。模擬資源到達其 時會自動停止`MaximumDuration`。的最大值`MaximumDuration`為 `14D`(14 天）。

如果您需要模擬的持續時間超過其模擬資源`MaximumDuration`的 ，您可以在模擬資源到達其 之前建立快照`MaximumDuration`。您可以使用快照啟動新的模擬 （建立新的模擬資源）。 會從快照 SimSpace Weaver 初始化實體資料、啟動之前執行的相同空間和服務應用程式，以及還原時鐘。您可以啟動自訂應用程式，並執行任何其他自訂初始化。您可以在啟動時，將新模擬資源`MaximumDuration`的 設定為不同的值。

# 使用 SimSpace Weaver 主控台來使用快照
<a name="working-with_snapshots_console"></a>

您可以使用 SimSpace Weaver 主控台來建立模擬的快照。

**Topics**
+ [建立快照](#working-with_snapshots_console_create)
+ [從快照啟動模擬](#working-with_snapshots_console_start)

## 使用 主控台建立快照
<a name="working-with_snapshots_console_create"></a>

**建立快照**

1. 登入 AWS 管理主控台 並連線至 [SimSpace Weaver 主控台](https://console.aws.amazon.com/simspaceweaver)。

1. 從導覽窗格中選擇**模擬**。

1. 選取模擬名稱旁的選項按鈕。必須**啟動**模擬**的狀態**。

1. 在頁面頂端，選擇**建立快照**。

1. 在**快照設定**下，針對**快照目的地**，輸入 SimSpace Weaver 您要建立快照之儲存貯體或儲存貯體和資料夾的 Amazon S3 URI。如果您想要瀏覽可用的儲存貯體並選取位置，可以選擇**瀏覽 S3**。
**重要**  
Amazon S3 儲存貯體必須與 AWS 區域 模擬位於相同的 中。
**注意**  
SimSpace Weaver 在您選取的快照目的地內建立`snapshot`資料夾。 會在該`snapshot`資料夾中 SimSpace Weaver 建立快照 .zip 檔案。

1. 選擇**建立快照**。

## 使用主控台從快照啟動模擬
<a name="working-with_snapshots_console_start"></a>

若要從快照啟動模擬，您的快照 .zip 檔案必須存在於模擬可存取的 Amazon S3 儲存貯體中。您的模擬使用您在啟動模擬時所選取之應用程式角色中定義的許可。來自原始模擬的所有應用程式 .zip 檔案都必須存在於與建立快照時相同的位置。

**從快照啟動模擬**

1. 登入 AWS 管理主控台 並連線至 [SimSpace Weaver 主控台](https://console.aws.amazon.com/simspaceweaver)。

1. 從導覽窗格中選擇**模擬**。

1. 在頁面頂端，選擇**開始模擬**。

1. 在**模擬設定**下，輸入模擬的名稱和選用描述。您的模擬名稱在 中必須是唯一的 AWS 帳戶。

1. 針對**模擬開始方法**，選擇**在 Amazon S3 中使用快照**。

1. 針對**快照的 Amazon S3 URI**，輸入快照檔案的 Amazon S3 URI，或選擇**瀏覽 S3** 以瀏覽並選取檔案。
**重要**  
Amazon S3 儲存貯體必須與 AWS 區域 模擬位於相同的 中。

1. 針對 **IAM 角色**，選取模擬將使用的應用程式角色。

1. 在**持續時間上限**中，輸入模擬資源應執行的時間上限。最大值為 `14D`. 如需最長持續時間的詳細資訊，請參閱 [。](https://docs.aws.amazon.com/simspaceweaver/latest/APIReference/API_StartSimulation.html)

1. 在**標籤 - *選用***下，如果您想要**新增標籤**，請選擇新增標籤。

1. 選擇**開始模擬**。

# 使用 AWS CLI 處理快照
<a name="working-with_snapshots_cli"></a>

您可以使用 AWS CLI 從命令提示字元呼叫 SimSpace Weaver APIs。您必須正確 AWS CLI 安裝和設定 。如需詳細資訊，請參閱《 第 [AWS 2 版使用者指南》中的安裝或更新最新版本的 CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。 *AWS Command Line Interface *

**Topics**
+ [建立快照](#working-with_snapshots_cli_create)
+ [從快照啟動模擬](#working-with_snapshots_cli_start)

## 使用 AWS CLI 建立快照
<a name="working-with_snapshots_cli_create"></a>

**建立快照**
+ 在**命令提示**字元中，呼叫 `CreateSnapshot` API。

  ```
  aws simspaceweaver create-snapshot --simulation simulation-name —destination s3-destination
  ```

  **參數**  
模擬  
已啟動模擬的名稱。您可以使用 `aws simspaceweaver list-simulations` 查看模擬的名稱和狀態。  
目的地  
指定快照檔案目的地 Amazon S3 儲存貯體和選用物件金鑰字首的字串。您的物件金鑰字首通常是儲存貯體中的資料夾。 會在此目的地的`snapshot`資料夾內 SimSpace Weaver 建立快照。  
Amazon S3 儲存貯體必須與 AWS 區域 模擬位於相同的 中。

  **範例**

  ```
  aws simspaceweaver create-snapshot —simulation MyProjectSimulation_23-04-29_12_00_00 —destination BucketName=weaver-myproject-111122223333-artifacts-us-west-2,ObjectKeyPrefix=myFolder
  ```

如需 `CreateSnapshot` API 的詳細資訊，請參閱 *AWS SimSpace Weaver API 參考*中的 [CreateSnapshot](https://docs.aws.amazon.com/simspaceweaver/latest/APIReference/API_CreateSnapshot.html)。

## 使用 從快照 AWS CLI 啟動模擬
<a name="working-with_snapshots_cli_start"></a>

**從快照啟動模擬**
+ 在**命令提示**字元中，呼叫 `StartSimulation` API。

  ```
  aws simspaceweaver start-simulation --name simulation-name --role-arn role-arn --snapshot-s3-location s3-location
  ```

  **參數**  
name  
新模擬的名稱。模擬名稱在您的 中必須是唯一的 AWS 帳戶。您可以使用 `aws simspaceweaver list-simulations` 查看現有模擬的名稱。  
role-arn  
模擬將使用的應用程式角色的 Amazon Resource Name (ARN)。  
snapshot-s3-location  
指定快照檔案之 Amazon S3 儲存貯體和物件金鑰的字串。  
Amazon S3 儲存貯體必須與 AWS 區域 模擬位於相同的 中。

  **範例**

  ```
  aws simspaceweaver start-simulation —name MySimulation —role-arn arn:aws:iam::111122223333:role/weaver-MyProject-app-role —snapshot-s3-location BucketName=weaver-myproject-111122223333-artifacts-us-west-2,ObjectKey=myFolder/snapshot/MyProjectSimulation_23-04-29_12_00_00-230429-1530-27.zip
  ```

如需 `StartSimulation` API 的詳細資訊，請參閱*AWS SimSpace Weaver 《 API 參考*》中的 [StartSimulation](https://docs.aws.amazon.com/simspaceweaver/latest/APIReference/API_StartSimulation.html)。

# 有關快照的常見問答集
<a name="working-with_snapshots_faq"></a>

**我的模擬是否在快照期間繼續執行？**  
您的模擬資源會在快照期間繼續執行，而且您會繼續收到當時的帳單費用。時間會計入模擬的最長持續時間。您的應用程式在快照進行時不會收到刻度。如果您的時鐘狀態是在`STARTED`快照建立開始時，您的時鐘仍會指出`STARTED`狀態。快照完成後，您的應用程式會再次收到刻度。如果您的時鐘狀態為 `STOPPED`，則您的時鐘狀態將保持 `STOPPED`。請注意，即使其時鐘`STARTED`狀態為 ，狀態為 的模擬仍會執行`STOPPED`。

**如果快照正在進行中且我的模擬達到其最長持續時間，會發生什麼情況？**  
您的模擬將完成快照，然後在快照程序結束時立即停止 （成功或失敗）。我們建議您事先測試快照程序，以了解快照程序需要多久、您可以預期的快照檔案大小，以及是否應成功完成。

**如果我停止的模擬正在進行快照，會發生什麼情況？**  
當您停止模擬時，進行中的快照會立即停止。它不會建立快照檔案。

**如何停止進行中的快照？**  
停止進行中的快照的唯一方法是停止模擬。**您無法在停止模擬後重新啟動模擬。**

**完成快照需要多長時間？**  
建立快照所需的時間取決於您的模擬。我們建議您事先測試快照程序，以了解模擬需要多長時間。

**我的快照檔案會有多大？**  
快照檔案的大小取決於您的模擬。我們建議您事先測試快照程序，以了解檔案對您的模擬而言的大小。

# 簡訊
<a name="working-with_messaging"></a>

訊息 API 可簡化模擬中應用程式與應用程式的通訊。傳送和接收訊息APIs 是 SimSpace Weaver 應用程式 SDK 的一部分。訊息目前會盡最大努力來傳送和接收訊息。SimSpace Weaver 會嘗試在下一個模擬刻度上傳送/接收訊息，但沒有交付、訂購或抵達時間保證。

**主題**
+ [訊息的使用案例](#working-with_messaging_use-cases)
+ [使用傳訊 APIs](working-with_messaging_using.md)
+ [何時使用簡訊](working-with_messaging_when-to-use.md)
+ [使用簡訊時的提示](working-with_messaging_tips.md)
+ [訊息錯誤和疑難排解](working-with_messaging_troubleshooting.md)

## 訊息的使用案例
<a name="working-with_messaging_use-cases"></a>

**在模擬應用程式之間通訊**  
使用訊息 API 在模擬中的應用程式之間進行通訊。使用它來變更遠距離實體的狀態、變更實體行為，或將資訊廣播到整個模擬。

**確認收到訊息**  
傳送的訊息包含訊息標頭中寄件者的相關資訊。使用此資訊在收到訊息時傳送確認回覆。

**將自訂應用程式收到的資料轉送至模擬中的其他應用程式**  
訊息無法取代用戶端如何連線到在 中執行的自訂應用程式 SimSpace Weaver。不過，簡訊確實允許使用者將資料從接收用戶端資料的自訂應用程式轉送到沒有外部連線的其他應用程式。訊息流程也可以反向運作，允許沒有外部連線的應用程式將資料轉送至自訂應用程式，然後轉送至用戶端。

# 使用傳訊 APIs
<a name="working-with_messaging_using"></a>

訊息 APIs 包含在 SimSpace Weaver 應用程式 SDK 中 （最低版本 1.16.0)。C\$1\$1、Python 以及與 Unreal Engine 5 和 Unity 整合支援傳訊。

處理訊息交易的函數有兩種： `SendMessage`和 `ReceiveMessages`。所有傳送的訊息都包含目的地和承載。`ReceiveMessages` API 會傳回目前在應用程式傳入訊息佇列中的訊息清單。

------
#### [ C\$1\$1 ]

**傳送訊息**

```
AWS_WEAVERRUNTIME_API Result<void> SendMessage(
    Transaction& txn,
    const MessagePayload& payload,
    const MessageEndpoint& destination,
    MessageDeliveryType deliveryType = MessageDeliveryType::BestEffort
    ) noexcept;
```

**接收訊息**

```
AWS_WEAVERRUNTIME_API Result<MessageList> ReceiveMessages(
    Transaction& txn) noexcept;
```

------
#### [ Python ]

**傳送訊息**

```
api.send_message(
 txn, # Transaction
 payload, # api.MessagePayload
 destination, # api.MessageDestination
 api.MessageDeliveryType.BestEffort # api.MessageDeliveryType
)
```

**接收訊息**

```
api.receive_messages(
 txn, # Transaction
) -> api.MessageList
```

------

**主題**
+ [傳送訊息](#working-with_messaging_using_send)
+ [接收訊息](#working-with_messaging_using_receive)
+ [回覆寄件者](#working-with_messaging_using_reply)

## 傳送訊息
<a name="working-with_messaging_using_send"></a>

訊息包含交易 （類似其他 Weaver API 呼叫）、承載和目的地。

### 訊息承載
<a name="working-with_messaging_using_send_payload"></a>

訊息承載是高達 256 個位元組的彈性資料結構。我們建議以下作為建立訊息承載的最佳實務。

**建立訊息承載**

1. 建立定義訊息內容的資料結構 （例如 C\$1\$1 `struct`中的 )。

1. 建立訊息承載，其中包含要在訊息中傳送的值。

1. 建立 `MessagePayload` 物件。

### 訊息目的地
<a name="working-with_messaging_using_send_destination"></a>

訊息的目的地由 `MessageEndpoint` 物件定義。這包括端點類型和端點 ID。目前唯一支援的端點類型是 `Partition`，可讓您將訊息定址到模擬中的其他分割區。端點 ID 是您目標目的地的分割區 ID。

您只能在訊息中提供 1 個目的地地址。如果您想要同時將訊息傳送到多個分割區，請建立並傳送多個訊息。

如需如何從位置解析訊息端點的指引，請參閱 [使用簡訊時的提示](working-with_messaging_tips.md)。

### 傳送訊息
<a name="working-with_messaging_using_send_send"></a>

您可以在建立目的地和承載物件之後使用 `SendMessage` API。

------
#### [ C\$1\$1 ]

```
Api::SendMessage(transaction, payload, destination, MessageDeliveryType::BestEffort);
```

------
#### [ Python ]

```
api.send_message(txn, payload, destination, api.MessageDeliveryType.BestEffort)
```

------

**傳送訊息的完整範例**  
下列範例示範如何建構和傳送一般訊息。此範例會傳送 16 則個別訊息。每個訊息都包含值為 0 和 15 的承載，以及目前的模擬刻度。

**Example**  

```
// Message struct definition
struct MessageTickAndId
{
    uint32_t id;
    uint32_t tick;
};

Aws::WeaverRuntime::Result<void> SendMessages(Txn& txn) noexcept
{
     // Fetch the destination MessageEndpoint with the endpoint resolver
    WEAVERRUNTIME_TRY(
        Api::MessageEndpoint destination,
        Api::Utils::MessageEndpointResolver::ResolveFromPosition(
        txn,
            "MySpatialSimulation",
            Api::Vector2F32 {231.3, 654.0}
        )
    );
    Log::Info("destination: ", destination);

    WEAVERRUNTIME_TRY(auto tick, Api::CurrentTick(txn));

    uint16_t numSentMessages = 0;
    for (std::size_t i=0; i<16; i++)
    {
        // Create the message that'll be serialized into payload
        MessageTickAndId message {i, tick.value};
        
        // Create the payload out of the struct
        const Api::MessagePayload& payload = Api::Utils::CreateMessagePayload(
            reinterpret_cast<const std::uint8_t*>(&message), 
            sizeof(MessageTickAndId)
        );
        
        // Send the payload to the destination
        Result<void> result = Api::SendMessage(txn, payload, destination);
        if (result.has_failure())
        {
            // SendMessage has failure modes, log them
            auto error = result.as_failure().error();
            std::cout<< "SendMessage failed, ErrorCode: " << error << std::endl;
            continue;
        }
        
        numSentMessages++;
    }

    std::cout << numSentMessages << " messages is sent to endpoint" 
       << destination << std::endl;
    return Aws::WeaverRuntime::Success();
}
```

```
# Message data class
@dataclasses.dataclass
class MessageTickAndId:
    tick: int = 0
    id: int = 0
    
# send messages
def _send_messages(self, txn):
    tick = api.current_tick(txn)
    num_messages_to_send = 16

    # Fetch the destination MessageEndpoint with the endpoint resolver
    destination = api.utils.resolve_endpoint_from_domain_name_position(
       txn,
       "MySpatialSimulation",
       pos
   )
    Log.debug("Destination_endpoint = %s", destination_endpoint)

   for id in range(num_messages_to_send):
       # Message struct that'll be serialized into payload
        message_tick_and_id = MessageTickAndId(id = id, tick = tick.value)
        
       # Create the payload out of the struct
        message_tick_and_id_data = struct.pack(
           '<ii',
           message_tick_and_id.id,
           message_tick_and_id.tick
       )
        payload = api.MessagePayload(list(message_tick_and_id_data))

        # Send the payload to the destination
        Log.debug("Sending message: %s, endpoint: %s",
           message_tick_and_id,
           destination
       )
        api.send_message(
           txn,
           payload,
           destination,
           api.MessageDeliveryType.BestEffort
       )

    Log.info("Sent %s messages to %s", num_messages_to_send, destination)
    return True
```

## 接收訊息
<a name="working-with_messaging_using_receive"></a>

SimSpace Weaver 會將訊息傳送到分割區的傳入訊息佇列。使用 `ReceiveMessages` API 取得包含佇列訊息的`MessageList`物件。使用 `ExtractMessage` API 處理每個訊息，以取得訊息資料。

**Example**  

```
Result<void> ReceiveMessages(Txn& txn) noexcept
{
     // Fetch all the messages sent to the partition owned by the app
    WEAVERRUNTIME_TRY(auto messages, Api::ReceiveMessages(txn));
    std::cout << "Received" << messages.messages.size() << " messages" << std::endl;
    for (Api::Message& message : messages.messages)
    {
        std::cout << "Received message: " << message << std::endl;

         // Deserialize payload to the message struct
        const MessageTickAndId& receivedMessage 
            = Api::Utils::ExtractMessage<MessageTickAndId>(message);
        std::cout << "Received MessageTickAndId, Id: " << receivedMessage.id 
            <<", Tick: " << receivedMessage.tick << std::endl;
    }

    return Aws::WeaverRuntime::Success();
}
```

```
# process incoming messages
def _process_incoming_messages(self, txn):
    messages = api.receive_messages(txn)
    for message in messages:
        payload_list = message.payload.data
        payload_bytes = bytes(payload_list)
        message_tick_and_id_data_struct 
           = MessageTickAndId(*struct.unpack('<ii', payload_bytes))

        Log.debug("Received message. Header: %s, message: %s", 
                    message.header, message_tick_and_id_data_struct)

    Log.info("Received %s messages", len(messages))
    return True
```

## 回覆寄件者
<a name="working-with_messaging_using_reply"></a>

每個收到的訊息都包含訊息標頭，其中包含訊息原始寄件者的相關資訊。您可以使用 message.header.source\$1endpoint 傳送回覆。

**Example**  

```
Result<void> ReceiveMessages(Txn& txn) noexcept
{
     // Fetch all the messages sent to the partition owned by the app
    WEAVERRUNTIME_TRY(auto messages, Api::ReceiveMessages(txn));
    std::cout << "Received" << messages.messages.size() << " messages" << std::endl;
    for (Api::Message& message : messages.messages)
    {
        std::cout << "Received message: " << message << std::endl;

         // Deserialize payload to the message struct
        const MessageTickAndId& receivedMessage 
            = Api::Utils::ExtractMessage<MessageTickAndId>(message);
        std::cout << "Received MessageTickAndId, Id: " << receivedMessage.id 
            <<", Tick: " << receivedMessage.tick << std::endl;
        
        // Get the sender endpoint and payload to bounce the message back
        Api::MessageEndpoint& sender = message.header.source_endpoint;
        Api::MessagePayload& payload = message.payload;
        Api::SendMessage(txn, payload, sender);
    }

    return Aws::WeaverRuntime::Success();
}
```

```
# process incoming messages
def _process_incoming_messages(self, txn):
    messages = api.receive_messages(txn)
    for message in messages:
        payload_list = message.payload.data
        payload_bytes = bytes(payload_list)
        message_tick_and_id_data_struct 
           = MessageTickAndId(*struct.unpack('<ii', payload_bytes))

        Log.debug("Received message. Header: %s, message: %s", 
                    message.header, message_tick_and_id_data_struct)
       # Get the sender endpoint and payload 
       # to bounce the message back
       sender = message.header.source_endpoint
       payload = payload_list
       api.send_message(
           txn,
           payload_list,
           sender,
           api.MessageDeliveryType.BestEffort

    Log.info("Received %s messages", len(messages))
    return True
```

# 何時使用簡訊
<a name="working-with_messaging_when-to-use"></a>

中的傳訊 SimSpace Weaver 提供另一種模式，用於在模擬應用程式之間交換資訊。訂閱提供從特定應用程式或模擬區域讀取資料的提取機制；訊息提供推送機制，可將資料傳送至特定應用程式或模擬區域。

以下是兩個使用案例，其中使用傳訊推送資料比透過訂閱提取或讀取資料更有幫助。

**Example 1：將命令傳送至另一個應用程式以變更實體位置**  

```
// Message struct definition
struct MessageMoveEntity
{
     uint64_t entityId;
    std::array<float, 3> destinationPos;
};

// Create the message 
MessageMoveEntity message {45, {236.67, 826.22, 0.0} };

// Create the payload out of the struct
const Api::MessagePayload& payload = Api::Utils::CreateMessagePayload(
    reinterpret_cast<const std::uint8_t*>(&message), 
    sizeof(MessageTickAndId)
);

// Grab the MessageEndpoint of the recipient app.
Api::MessageEndpoint destination = ...

// One way is to resolve it from the domain name and position
WEAVERRUNTIME_TRY(
    Api::MessageEndpoint destination,
    Api::Utils::MessageEndpointResolver::ResolveFromPosition(
    txn,
        "MySpatialSimulation",
        Api::Vector2F32 {200.0, 100.0}
    )
);

// Then send the message 
Api::SendMessage(txn, payload, destination);
```
在接收端，應用程式會更新實體的位置，並將其寫入 State Fabric。  

```
Result<void> ReceiveMessages(Txn& txn) noexcept
{
    WEAVERRUNTIME_TRY(auto messages, Api::ReceiveMessages(txn));
    for (Api::Message& message : messages.messages)
    {
        std::cout << "Received message: " << message << std::endl;
         // Deserialize payload to the message struct
        const MessageMoveEntity& receivedMessage 
            = Api::Utils::ExtractMessage<MessageMoveEntity>(message);
            
        ProcessMessage(txn, receivedMessage);
    }

    return Aws::WeaverRuntime::Success();
}

void ProcessMessage(Txn& txn, const MessageMoveEntity& receivedMessage)
{
     // Get the entity corresponding to the entityId
    Entity entity = EntityFromEntityId (receivedMessage.entityId);
    
    // Update the position and write to StateFabric
    WEAVERRUNTIME_TRY(Api::StoreEntityIndexKey(
            txn,
            entity,
            k_vector3f32TypeId, // type id of the entity
            reinterpret_cast<std::int8_t*>(&receivedMessage.destinationPos),
            sizeof(receivedMessage.destinationPos)));
    
}
```

**Example 2：將建立實體訊息傳送至空間應用程式**  

```
struct WeaverMessage
{
    const Aws::WeaverRuntime::Api::TypeId messageTypeId;
};

const Aws::WeaverRuntime::Api::TypeId k_createEntityMessageTypeId = { 1 };

struct CreateEntityMessage : WeaverMessage
{
    const Vector3 position;
   const Aws::WeaverRuntime::Api::TypeId typeId;
}; 


CreateEntityMessage messageData { 
    k_createEntityMessageTypeId,                           
    Vector3{ position.GetX(), position.GetY(), position.GetZ() },
    Api::TypeId { 0 }
}

WEAVERRUNTIME_TRY(Api::MessageEndpoint destination, Api::Utils::MessageEndpointResolver::ResolveFromPosition(
    transaction, "MySpatialDomain", DemoFramework::ToVector2F32(position)
));

Api::MessagePayload payload = Api::Utils::CreateMessagePayload(
    reinterpret_cast<const uint8_t*>(&messageData),
    sizeof(CreateEntityMessage));
        
Api::SendMessage(transaction, payload, destination);
```
在接收端，應用程式會在 State Fabric 中建立新的實體，並更新其位置。  

```
Result<void> ReceiveMessages(Txn& txn) noexcept
{
    WEAVERRUNTIME_TRY(auto messageList, Api::ReceiveMessages(transaction));
    WEAVERRUNTIME_TRY(auto tick, Api::CurrentTick(transaction));
    for (auto& message : messageList.messages)
    {
        // cast to base WeaverMessage type to determine MessageTypeId
        WeaverMessage weaverMessageBase = Api::Utils::ExtractMessage<WeaverMessage>(message);
        if (weaverMessageBase.messageTypeId == k_createEntityMessageTypeId)
        {
            CreateEntityMessage createEntityMessageData =
                Api::Utils::ExtractMessage<CreateEntityMessage>(message);
        CreateActorFromMessage(transaction, createEntityMessageData));
        }
        else if (weaverMessageBase.messageTypeId == k_tickAndIdMessageTypeId)
        {
            ...
        }
    }
}

void ProcessMessage(Txn& txn, const CreateEntityMessage& receivedMessage)
{
    // Create entity
    WEAVERRUNTIME_TRY(
        Api::Entity entity,
        Api::CreateEntity(transaction, receivedMessage.typeId)
    );
    
    // Update the position and write to StateFabric
    WEAVERRUNTIME_TRY(Api::StoreEntityIndexKey(
        transaction,
        entity,
        receivedMessage.typeId,
        reinterpret_cast<std::int8_t*>(&receivedMessage.position),
        sizeof(receivedMessage.position)));
}
```

# 使用簡訊時的提示
<a name="working-with_messaging_tips"></a>

## 從位置或應用程式名稱解析端點
<a name="working-with_messaging_tips_resolve-endpoint"></a>

您可以使用 `AllPartitions`函數來取得空間界限，以及判斷訊息分割區 ID 和訊息目的地所需的網域 IDs。不過，如果您知道要傳送訊息的位置，但不知道其分割區 ID，您可以使用 MessageEndpointResolver 函數。

```
/**
* Resolves MessageEndpoint's from various inputs
**/
class MessageEndpointResolver
{
    public:
    /**
    * Resolves MessageEndpoint from position information
    **/
    Result<MessageEndpoint> ResolveEndpointFromPosition(
        const DomainId& domainId,
        const weaver_vec3_f32_t& pos);

    /**
    * Resolves MessageEndpoint from custom app name
    **/
    Result<MessageEndpoint> ResolveEndpointFromCustomAppName(
        const DomainId& domainId,
        const char* agentName);
};
```

## 序列化和還原序列化訊息承載
<a name="working-with_messaging_tips_serialize-payload"></a>

您可以使用下列函數來建立和讀取訊息承載。如需詳細資訊，請參閱本機系統應用程式 SDK 程式庫中的 MessagingUtils.h。

```
/**
* Utility function to create MessagePayload from a custom type
*
* @return The @c MessagePayload.
*/
template <class T>
AWS_WEAVERRUNTIME_API MessagePayload CreateMessagePayload(const T& message) noexcept
{
    const std::uint8_t* raw_data = reinterpret_cast<const std::uint8_t*>(&message);

    MessagePayload payload;
    std::move(raw_data, raw_data + sizeof(T), std::back_inserter(payload.data));

    return payload;
}

/**
* Utility function to convert MessagePayload to custom type
*/
template <class T>
AWS_WEAVERRUNTIME_API T ExtractMessage(const MessagePayload& payload) noexcept
{
    return *reinterpret_cast<const T*>(payload.data.data());
}
```

# 訊息錯誤和疑難排解
<a name="working-with_messaging_troubleshooting"></a>

使用簡訊 APIs 時，您可能會遇到下列錯誤。

## 端點解析錯誤
<a name="working-with_messaging_troubleshooting_endpoint-resolution"></a>

這些錯誤可能會在應用程式傳送訊息之前發生。

### 網域名稱檢查
<a name="working-with_messaging_troubleshooting_dns-check"></a>

傳送訊息至無效的端點會導致下列錯誤：

```
ManifoldError::InvalidArgument {"No DomainId found for the given domain name" }
```

當您嘗試傳送訊息至自訂應用程式，且該自訂應用程式尚未加入模擬時，可能會發生這種情況。使用 `DescribeSimulation` API 確認您的自訂應用程式已啟動，再傳送訊息給它。此行為在 SimSpace Weaver Local和 中是相同的 AWS 雲端。

### 位置檢查
<a name="working-with_messaging_troubleshooting_position-check"></a>

嘗試解決具有有效網域名稱但位置無效的端點會導致下列錯誤。

```
ManifoldError::InvalidArgument {"Could not resolve endpoint from domain : DomainId { value: domain-id } and position: Vector2F32 { x: x-position, y: y-position}" }
```

我們建議在 SimSpace Weaver 應用程式 SDK `MessageEndpointResolver`中包含的`MessageUtils`程式庫中使用 。

## 訊息傳送錯誤
<a name="working-with_messaging_troubleshooting_message-sending"></a>

當應用程式傳送訊息時，可能會發生下列錯誤。

### 超過每個應用程式、每個刻度的訊息傳送限制
<a name="working-with_messaging_troubleshooting_send-limit"></a>

每個模擬刻度每個應用程式可傳送的訊息數量目前限制為 128 個。相同刻度的後續呼叫將會失敗，並顯示下列錯誤：

```
ManifoldError::CapacityExceeded {"At Max Outgoing Message capacity: {}", 128}
```

SimSpace Weaver 會嘗試在下一個刻度傳送未傳送的訊息。降低傳送頻率以解決此問題。合併小於 256 位元組限制的訊息承載，以降低傳出訊息的數量。

此行為在 SimSpace Weaver Local和 中是相同的 AWS 雲端。

### 超過訊息承載大小限制
<a name="working-with_messaging_troubleshooting_size-limit"></a>

在 SimSpace Weaver Local和 中，訊息承載大小的目前限制為 256 個位元組 AWS 雲端。傳送承載大於 256 個位元組的訊息會導致下列錯誤：

```
ManifoldError::CapacityExceeded {"Message data too large! Max size: {}", 256}
```

SimSpace Weaver 會檢查每個訊息，並僅拒絕超過限制的訊息。例如，如果您的應用程式嘗試傳送 10 則訊息，而 1 則檢查失敗，則只會拒絕 1 則訊息。 會 SimSpace Weaver 傳送其他 9 則訊息。

此行為在 SimSpace Weaver Local和 中是相同的 AWS 雲端。

### 目的地與來源相同
<a name="working-with_messaging_troubleshooting_dst-src-same"></a>

應用程式無法傳送訊息至他們擁有的分割區。如果應用程式傳送訊息到其擁有的分割區，您會收到下列錯誤。

```
ManifoldError::InvalidArgument { "Destination is the same as source" }
```

此行為在 SimSpace Weaver Local和 中是相同的 AWS 雲端。

### 盡最大努力傳訊
<a name="working-with_messaging_troubleshooting_best-effort"></a>

SimSpace Weaver 不保證訊息交付。服務會嘗試在後續模擬刻度上完成訊息傳遞，但訊息可能會遺失或延遲。