# 詞彙表

## :books: Burst Time

Burst time主要分爲<mark style="color:orange;">CPU burst time</mark>和<mark style="color:orange;">Device burst time</mark>。

### **- CPU burst time**

運行特定例程只運算 CPU 的時間 。 <mark style="color:orange;">CPU burst time</mark> 線程的 CPU 核心佔用率爲 100 。

### **- Device burst time**

這是CPU在執行特定例程時等待其他處理完成的時間。<mark style="color:orange;">Device burst time</mark>中執行緒的CPU核心使用率為0。\
CPU 等待其他處理完成的典型情況包括讀取/寫入檔案、執行資料庫查詢或等待其他主機的服務回應。

## :books: C++ Singleton

Singleton和全局變量在C++語言中存在差異。 全局變量在運行 <mark style="color:orange;">WinMain()</mark> 或 <mark style="color:orange;">main()</mark> 時不會在即將退出時被破壞， 而會在子調用函數中被破壞 。 全局變量的破壞順序只能在一個C++文件的編譯結果中保證,不同C++文件的編譯結果之間的破壞順序不能保證。<br>

但是 C++ singleton 在 <mark style="color:orange;">WinMain()</mark> 或 <mark style="color:orange;">main()</mark> 返回之前被調用 。 此外，實例的創建者會在第一次訪問 singleton 的瞬間被調用，破壞的順序也會被調用者反向調用。 因此，它確保了比全局變量更安全的生成/破壞規則。

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> C++ singleton 實現示例</summary>

```cpp
class A
{
    A(){}
public:
    static A& Instance()
    {
        static A inst;
        return inst;
    }
    void Goo() {}
};
 
 
 
void Foo()
{
    A::Instance().Goo();
}
```

</details>

{% hint style="warning" %}
上述實現存在如下風險:如果在短時間內同時從多個線程訪問singleton，則生成器可能會有2次以上的呼叫。

在解決這些問題的同時，我們建議使用無critical section負載的類<mark style="color:orange;">Proud.CSingleton</mark>訪問。
{% endhint %}

## :books: DB Constraints

要進入字段的值如果不滿足特定條件，就指不讓進入。

PrimaryKey Unique Index 其他等等(>,<,=,!=)，Constraints由Unique Index, Trigger 等實現。

## :books: Fast Heap

ProudNet的Fastheap雖然比[**Lookaside allocator**](/proudnet.cn/proudnet/pn_utility.md#lookaside-allocator)稍微慢一些，但比OS環境下的存儲器分配/解除速度更快，可以分配/解除各種大小的存儲器塊。

ProudNet 的 <mark style="color:orange;">Fast heap</mark> 的實現類是 <mark style="color:orange;">Proud.CFastHeap</mark>。 <mark style="color:orange;">Proud.CFastHeap</mark> 和 <mark style="color:orange;">Lookaside allocator</mark> 一樣， 只有在所有存儲塊被破壞之後才能移除 <mark style="color:orange;">Proud.CFastHeap</mark> 對象。

<mark style="color:orange;">Fast heap</mark>的使用方法如下。

> * 首先以<mark style="color:orange;">Proud.CFastHeap.New</mark>方法生成fastheap對象。 創建全局對象也可以。
> * 用 <mark style="color:orange;">Proud.CFastHeap.Alloc</mark> 方法分配內存塊 。
> * 解除爲<mark style="color:orange;">Proud.CFastHeap.Free</mark>。 可以用<mark style="color:orange;">CFastHeap.Realloc</mark>重新分配內存塊。
> * 解除所有存儲塊後，破壞 <mark style="color:orange;">Proud.CFastHeap</mark> 對象。

## :books: P2P 組

如果兩個客戶端A和B要進行P2P通信，則A和B必須屬於至少一個P2P組。 多人可以在一個聊天視窗中互相聊天，也可以透過建立多個聊天視窗來進行多人聊天。 但是，您無法在您不在的聊天視窗中聊天。

ProudNet在網絡聊天工具中，每個聊天窗口對應P2P組。

但是，創建聊天窗口或進入其他聊天窗口的權限只有服務器纔有。 P2P 組標識符也是 <mark style="color:orange;">Proud.HostID</mark> 類型。

## :books: PIDL

PIDL是爲RMI自制的編譯器。

在特定文件中定義協議後設置，會自動創建對象文件。\
此時生成的客體與Server和Client一起使用，因此生成Common(公用)Project進行管理非常方便。

## :books: Reliable 訊息

Reliable消息（或reliable send）是指發送方發送的消息內容和順序始終由接收方統一接收。 例如,發送信息A、B、C、D、E後,接收方也會按照A、B、C、D、E的順序無損失地接收數據。

雖然具有可信度(reliablility)的優點,但偶爾接收的時間可能比[**Unreliable 信息**](#unreliable)慢。

## :books: RMI

<mark style="color:orange;">RMI(Remote Method Invocation, 遠程方法呼叫)</mark>是指呼叫其他網絡或其他程序中的函數,通過機器代替人進行定義收發例程和信息(Message)結構的編碼工作,起到將讓開發者感到吃力的編程工作(信息結構定義、發送函數、接收函數製作)簡化爲函數呼叫形式的作用。

發送消息時，調用 RMI 函數的一方稱爲 Proxy，調用方稱爲 Stub。

<figure><img src="/files/ICNmLYQBghM7CNE65E3e" alt=""><figcaption><p>RMI概念</p></figcaption></figure>

<figure><img src="/files/RKSBo94YNVznHXsquKBz" alt=""><figcaption><p>RMI概念2</p></figcaption></figure>

### - 不使用 RMI 時

```cpp
// Message header ID definitions
#define Message_Knight_Move_ID 12
#define Message_Knight_Attack_ID 13
 
// Message format definitions
struct Message
{
    int m_msgID;
};
struct Message_Knight_Move:public Message
{
    int m_id;
    float m_x,m_y,m_z;
};
struct Message_Knight_Attack:public Message
{
    int m_id;
    int m_target;
    int m_damage;
};
 
// A function which send a formatted message
void Knight_Move(int id,float x,float y,float z)
{
    Message_Knight_Move msg;
    msg.m_msgID=Message_Knight_Move_ID;
 
    msg.m_id=id;
    msg.m_x=x;
    msg.m_y=y;
    msg.m_z=z;
 
    Send(msg);
}
 
// A function which send a formatted message
void Knight_Attack(int id,int target,int damage)
{
    Message_Knight_Attack msg;
    msg.m_msgID=Message_Knight_Attack_ID;
 
    msg.m_id=id;
    msg.m_target=target;
    msg.m_damage=damage;
 
    Send(msg);
}
 
// Identified a received message 
// and call an appropriate function for message handling
void DoReceivedMessage(Message* msg)
{
    switch(msg->m_msgID)
    {
    case Message_Knight_Move_ID:
    {
        Message_Knight_Move* msg2=
            (Message_Knight_Move*)msg;
 
        Do_Knight_Move(
            msg2->m_id,
            msg2->m_x,
            msg2->m_y,
            msg2->m_z);
    }
    break;
    // ... cases for other message types
    case Message_Knight_Attack_ID:
    {
        Message_Knight_Attack* msg2=
            (Message_Knight_Attack*)msg;
 
        Do_Knight_Attack(
            msg2->m_id,
            msg2->m_target,
            msg2->m_damage);
    }
    break;
    // ... cases for other message types
    }
}c
```

但是使用RMI可以整理成以下短代碼。

```cpp
Knight_Move([in] int id,[in] float x,[in] float y,[in] float z);
Knight_Attack([in] int id,[in] int target,[in] int damage);
```

以上格式爲<mark style="color:orange;">IDL(Interface Description Language)</mark>格式，編譯後生成C++或C#源。 創建的源文件由消息結構聲明、發送函數、接收處理函數等組成，即使開發者不直接創建網絡處理程序，PIDL編譯器也會自動生成。

在創建的文件中，將函數調用轉換爲消息發送到網絡的模塊稱爲proxy，分析通過網絡接收到的消息並調用用戶函數的模塊稱爲stub。

當從主機A調用RMI函數X時，實際上調用X的proxy，proxy將其切換爲網絡消息並將其發送到主機B。 然後主機B接收消息併發送到stub，stub分析後調用用戶創建的函數X。

<figure><img src="/files/a9aCsDMgFH9co1VZ57I9" alt=""><figcaption><p>RMI 處理順序</p></figcaption></figure>

因爲看起來具有與主機A呼叫主機B上的函數相似的形狀,所以具有<mark style="color:orange;">Remote Method Invocation(遠程方法呼叫)</mark>的意義。

## :books: Stored Procedure

<mark style="color:orange;">Stored Procedure</mark>是由DBMS本身可放入的SQL語句製作的程序函數。\
訪問數據庫時，查詢語句字符串由應用程序直接創建並扔出，但如果可能，提前創建<mark style="color:orange;">Stored Procedure</mark>保存查詢語句例程，應用程序直接調用<mark style="color:orange;">Stored Procedure</mark>在性能和穩定性(數據庫鎖定策略等)上更有效。

<br>

## :books: **Unreliable** 訊息

<mark style="color:orange;">Unreliable 信息</mark>(或unreliable send)可以根據通信線的長度和狀態,接收發送方發送的消息內容和順序不同。

例如，發送消息A、B、C、D、E時，接收方有時會收到A、B、C、D、E，但可能會收到兩次相同的信息（A，B，B，C，C，D和E），或者消息在中間丟失（A,B,D），或者消息會按順序不同到達。(A,C,B,E,D)

但是消息內部的數據不會被破壞。 雖然Unreliable消息具有這些缺點，但送達時間比[**Reliable 信息**](#reliable)快。

## :books: UUID 或 GUID

Unique or global universal identifier (<mark style="color:orange;">UUID</mark>或<mark style="color:orange;">GUID</mark>)是16字節大小的數據塊,生成的GUID在概率上是全世界唯一的。

ProudNet DB將UUID分配給每個Gamer、Hero、WorldObject。 雖然因爲UUID是16bytes,所以可以認爲大小比較大,但是UUID具有在地球上不重複的優點,所以在幾個重要案例中很有用。 最具代表性的是服務器整合、玩家賬號移動、玩家ID變更等。

{% hint style="success" %}
**參考**\
[**全域唯一識別碼**](https://ko.wikipedia.org/wiki/%EC%A0%84%EC%97%AD_%EA%B3%A0%EC%9C%A0_%EC%8B%9D%EB%B3%84%EC%9E%90)&#x20;
{% endhint %}

## :books: 競爭狀態 (Race Condition)

在工學領域,<mark style="color:orange;">競爭狀態(race condition)</mark>是指同時進行兩個以上輸入或操作的狀態。 在這種情況下,有無法得出正常結果的危險,這被稱爲<mark style="color:orange;">競爭危險</mark>。

在計算機科學中，<mark style="color:orange;">競爭狀態</mark>是指多個過程試圖同時獲取共享資源的狀態，當同時獲取時，可能會出現破壞數據一致性的結果。 爲了防止這種情況的發生，需要過程協作技術。

{% hint style="success" %}
**參考**

[**競爭狀態 - Wiki**](https://ko.wikipedia.org/wiki/%EA%B2%BD%EC%9F%81_%EC%83%81%ED%83%9C)
{% endhint %}

## :books: 數據量化

當通過網絡交換浮動小數點單位的大值時，可能會出現減少數據包量的詭計。\
例如，如果角色位置x值僅在100到200之間確定，小數點後兩位數的精度可以忽略不計， 此值可轉換爲 100 \* 100 = 10000 或更少的值， 並節省 double (8 字節) 爲 word (2 字節) 。

這個技巧稱為<mark style="color:orange;">量化(quantization)</mark>。

該類提供了量化和量化的相反給付功能。

```cpp
Proud::CQuantizer q(-10000,10000,65535); // - 將10000~10000之間的值以65535等分精度進行量化的功能
double a = 3423.38274f;
int b = q.Quantize(a);      // 量子化
double c= q.Dequantize(b);  // 從量子化值中恢復實際值
```

## :books: Listening Port

由<mark style="color:orange;">主機地址</mark>和<mark style="color:orange;">端口</mark>組成，服務器必須有一個<mark style="color:orange;">listening port</mark>才能接收客戶端的訪問。

<mark style="color:orange;">主機地址</mark>是互聯網上的地址，由111.222.111.222或mycomputer.mydomain.com 格式組成。 <mark style="color:orange;">Port</mark>的值介於1，000到65500之間。\
只要兩個或兩個以上的程序不使用相同的<mark style="color:orange;">listening port</mark>,就可以任意指定。

## :books: Marshaling

將RMI呼叫轉換爲信息或從信息中提取用於呼叫RMI的值稱爲<mark style="color:orange;">marshaling</mark>。\
ProudNet提供int或float等基本類型的Marshaling功能。

<br>

## :books: Multicast

將一條信息一次性傳遞給多個主播的<mark style="color:orange;">multicast</mark>，\
將消息只傳遞給一個主機叫做<mark style="color:orange;">unicast</mark>。

<figure><img src="/files/2L2z0IwDOQl38bEiG9a2" alt=""><figcaption></figcaption></figure>

## :books: Thread Pool

生成1條線程後，清除的過程會產生大量的通量，因此，如果運行中的線程較多，操作系統可能會超負荷運行。

因此，要保持儘可能少的線程，儘量減少線程的去除和生成過程，爲此，需要設置由一定數量組成的1個線程集合，只在必要時導入使用，必要時返回集合。 這個過程叫做<mark style="color:orange;">thread pool</mark>。

即，<mark style="color:orange;">thread pool</mark>是指由<mark style="color:orange;">多個線程預先準備好的多個線程</mark>組成的<mark style="color:orange;">一個集合</mark>。

### - 例子

> 客戶端A、B、C被服務器容納的狀態下，分別因RMI或事件在<mark style="color:orange;">Proud.CNetServer</mark>內的queue中等待的狀態。<br>
>
> A1,A2,A3 -> 客戶端 A 的事件或 RMI\
> B1,B2,B3 -> 客戶端B的事件或RMI線程池共有兩個線程。\
> \
> \
> 這時根據規則執行如下。<br>
>
> * A1、A2、A3不能同時運行。
> * B1、B2、B3和C1、C2、C3同樣不是同時運行的。
> * A1、A2、A3之一和B1、B2、B3之一、C1、C2、C3之一可以同時運行。
> * 由於線程池中只有2個線程，A、B、C中的2個線程被篩選並回饋，但回饋程序首先完成線程的線程對未篩選的客戶端進行RMI或事件回饋。

<figure><img src="/files/rLQZfMlBtGDkQTETE1Kc" alt=""><figcaption><p>線程池實例</p></figcaption></figure>

## :books: 推測導航(dead reckoning)

ProudNet爲了表現遊戲角色的流暢位置,提供<mark style="color:orange;">推測導航(dead reckoning)</mark>工具。

<mark style="color:orange;">推測導航</mark>大致以以下方式操作。

> * 將移動角色的位置和速度從主機A傳送到主機B。 此時傳輸週期爲每秒2\~10次。
> * 傳輸週期最好是動態的。 只有當角色的加速度較大時，縮短傳輸週期才能同步更精確的運動。 加速度大的情況是,角色的速度急劇變化時或角色撞到其他物體,移動方向急劇變化時等。 （見下表）
> * 在主機B中，通過pinging從主機A獲得消息到達所需的時間（延遲）。
> * 當主機B接收到角色的位置、速度信息時，用以下公式預測主機A角色的實際位置。\
>   \
>   **P:** 預測位&#x7F6E;**, V:** 接收速&#x5EA6;**, T:** 延&#x9072;**, P0:** 接收位置\ <mark style="color:orange;">**P = (V \* T) + P0**</mark>

到這裏可以預測角色的位置，但租用計算出的位置值會導致角色的位置斷斷續續的問題。\
使用 <mark style="color:orange;">Proud.CPositionFollower</mark> 來解決這個問題。

\ <mark style="color:orange;">Proud.CPositionFollower</mark>的作用是移動追蹤者(follower)使其在規定時間內到達移動目標位置。 特別是製作成可以直線追蹤移動的目標位置,可以減少其他主機角色位置的突出現象。

下面將描述實現<mark style="color:orange;">推測導航</mark>的其餘步驟。

> * 在主機 B 中，將預測的位置和速度值輸入到 <mark style="color:orange;">Proud.CPositionFollower</mark> 對象中。 此時輸入目標位置、速度。
> * 在主機B中，獲取<mark style="color:orange;">Proud.CPositionFollower</mark>客體的示蹤劑位置，對主機A的角色位置進行渲染。

<figure><img src="/files/FazfuOAYIAKoo2xwxwrU" alt=""><figcaption></figcaption></figure>

### - 導航示例

P（t=0，1，2）是預測點，紅線是<mark style="color:orange;">Proud.CPositionFollower</mark>校正的角色位置。\
通常，最好將主機A中角色的位置發送週期和跟蹤者在<mark style="color:orange;">Proud.CPositionFollower</mark>中到達目標位置的時間限制設定爲相同，角色位置發送週期因情況而異。

**建議示例**

<table data-full-width="true"><thead><tr><th width="341">情況</th><th>發送的數據類型</th><th width="151" align="center">平均發送週期</th><th>快速增加的加速度示例</th></tr></thead><tbody><tr><td>大型戰RPG遊戲(MMORPG)玩家角色</td><td>位置(xyz),速度(xyz),觀望方向(z)</td><td align="center">0.3</td><td>角色的移動方向轉換，站立，圓點，波普</td></tr><tr><td>飛機或車輛</td><td>位置(xyz),速度(xyz),加速度(xyz), 觀望方向(xyz)</td><td align="center">0.3</td><td>障礙物碰撞、急轉彎</td></tr><tr><td>第一人稱射擊遊戲(FPS)玩家角色</td><td>位置(xyz), 觀望方向(xyz)</td><td align="center">0.03</td><td>角色移動方向改變後，狙擊槍發射瞬間</td></tr></tbody></table>

{% hint style="info" %}
發送週期短時，可能會有發送量過大的危險，建議使用[**發送量自動調節功能 (Throttling)**](/proudnet.cn/proudnet/using_pn/tong-xun-xun-xi.md#throttling)。
{% endhint %}

### - 曲線型跟蹤器(Spline based follower)

<mark style="color:orange;">Proud.CPositionFollower</mark>不僅提供直線，還提供曲線追擊目標的follower。 它是一種三階函數形式的<mark style="color:orange;">曲線型跟蹤器(spline based follower)</mark>。 這顯示了它們以比直線型follower更光滑的形式追趕。 但是，並不總是呈現光滑的面貌，所以最好在遊戲玩法上邊測試邊選擇。<br>

爲了獲得<mark style="color:orange;">曲線型跟蹤器</mark>，請使用以下方法。

> * Proud.CPositionFollower.GetSplineFollowerPosition
> * Proud.CPositionFollower.GetSplineFollowerVelocity

角度的校正處理使用以下方法。

> * <mark style="color:orange;">Proud.CPositionFollower</mark>: 位置補正作用
> * <mark style="color:orange;">Proud.CAngleFollower</mark>: 角度的校準作用

## :books: 打孔 (Hole Punching)

路由器還具有路由器的特性,以製作Routing Table的P2P通信爲目的,事先與對方交換數據包,在各自的路由器上製作Routing Table。\
確切的名稱是 <mark style="color:orange;">STUN (Simple Traversal of User Datagram Protocol Through Network Address Translators)</mark>。

打孔方法如下：

* Full Cone NAT
* Restricted Cone
* Port Restricted Cone
* Symmetric Cone


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.proudnet.com/proudnet.cn/proudnet-note/dictionary.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
