> For the complete documentation index, see [llms.txt](https://docs.proudnet.com/proudnet.cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.proudnet.com/proudnet.cn/proudnet/using_pn/rmi.md).

# RMI

ProudNet是一個自主開發的<mark style="color:orange;">Remote Method Invocation(RMI)</mark>系統，比現有的IDL格式或RMI系統更快、更輕量，並且僅支援遊戲開發中「函數呼叫回傳值」的非同步RMI。

## RMI 函數組

一組零個或多個 RMI 函數，採用 PIDL 檔案中全域語法區塊的形式。

```cpp
global SimpleC2S
{
    ...;
}
```

當從 Proxy 呼叫 RMI 函數時，它會立即返回。 而Proxy端無法等待並接收RMI函數執行結果。

<br>

## RMI 方法參數屬性

方法參數包含屬性定義，每個參數可以使用多個屬性。

{% hint style="info" %} <mark style="color:orange;">in :</mark> 這意味著它是輸入格式參數並且必須使用。 目前版本不支援“out”。
{% endhint %}

{% tabs %}
{% tab title="C++" %}

```cpp
// 例如，如果您聲明如下 RMI 方法 
Test([in] Proud::String a,[in] int b,[in] float c);

// 產生以下 C++ 程式碼。
Test(Proud::HostID remote, Proud::RmiContext& rmiContext, const Proud::String& a, const int& b, const float& c);

```

{% endtab %}

{% tab title="C#" %}

```csharp
// 當用作 cs 檔案時，Proud::String 被替換為 System.String
rename cs(Proud::String, System.String);

...

// 例如，如果您聲明如下 RMI 方法 
Test([in] Proud::String a,[in] int b,[in] float c);

// 產生以下 C# 程式碼：
Test(Nettention.Proud.HostID remote,Nettention.Proud.RmiContext rmiContext, String a, int b, float c);

```

{% endtab %}
{% endtabs %}

在大多數情況下，僅 <mark style="color:orange;">in</mark> 屬性用於 RMI 方法的參數。

### - byval 屬性

這表示參數是<mark style="color:orange;">by value</mark>傳遞的，當使用它時，C++ 代理程式和存根中的參數格式中會省略 & 符號。 它適用於小型參數類型，例如 int 或 float。

{% tabs %}
{% tab title="C++" %}

```cpp
// 如果你像這樣宣告 RMI 函數，
Foo([in] int a);

// 函數參數透過參考傳遞給建立的 C++ 代理程式和存根。 
// 下面的const int& a就是它。
SimpleC2S.Foo = [](Proud::HostID from, Proud::RmiContext& rmiContext, const int& a) = { ... };

// 如果您透過像這樣新增 byval 屬性來宣告 RMI 函數，
Foo([in, byval] int a);

// 它是以這樣的按值的形式創建的。
SimpleC2S.Foo = [](Proud::HostID from, Proud::RmiContext& rmiContext, int a) = { ... };

```

{% endtab %}
{% endtabs %}

### - mutable 屬性

這意味着該因子不是<mark style="color:orange;">const type</mark>，如果使用它，在C++proxy和stub中的因子形式中省略了const關鍵詞。 此選項適用於您想要更改 RMI stub 中收到的參數的值 。

{% tabs %}
{% tab title="C++" %}

<pre class="language-cpp"><code class="lang-cpp">// 如果您像這樣新增可變屬性
Foo([in, mutable] int a);

<strong>// 這會將其更改為可變變數。 const 將會消失。
</strong>SimpleC2S.Foo = [](Proud::HostID from, Proud::RmiContext&#x26; rmiContext, int&#x26; a) = { ... };

</code></pre>

{% endtab %}
{% endtabs %}

## 不同語言的程式之間進行通信

有時您可能希望兩個程式透過 ProudNet 進行通信，但使用不同的程式語言。\
在這種情況下，PIDL編譯器會產生兩種或多種語言的代理程式和存根，然後每個程式都可以使用它需要的內容。

ProudNet 的包裝模組中已經為 C++ 以外的語言提供了 int、double 和 string 等基本類型。 然而，在不同的語言中，這些基本類型的名稱往往不同。 例如，在 C# 中，字串類別是 <mark style="color:orange;">System.String</mark>，而在 C++ 中，字串類別是 <mark style="color:orange;">std::string</mark>, <mark style="color:orange;">std::wstring</mark>, <mark style="color:orange;">ATL::CString</mark>, <mark style="color:orange;">Proud::String</mark>。

為了解決這個問題，如果使用者願意，PIDL 編譯器提供了僅針對特定語言變更產生的代理程式和存根中的變數類型的功能。

下面是一個用法範例。

{% tabs %}
{% tab title="PIDL" %}

```cpp
rename cs(TypeA,TypeB);     // 1
 
rename cpp(TypeC,TypeD);    // 2
 
global XXX 2000
{
    Foo([in]TypeA a);  // 3
    Goo([in]TypeC c);  // 4
}
```

{% endtab %}
{% endtabs %}

## RMI訊息範圍

每個 RMI 函數宣告都有一種訊息類型。\
ProudNet的訊息類型是由使用者在60,000或更少的範圍內決定的，這個範圍是由使用者在建立<mark style="color:orange;">.pidl</mark>檔案時決定的。

對於低於 <mark style="color:orange;">1.7.42965-master</mark> 的版本，您應該使用 1,300 到 60,000 範圍內的值。

每個 RMI 的訊息類型值範例如下。

```cpp
global SampleRMI 2000
{
    Foo1(...); // Assigned Message Type ID = 2001
    Foo2(...); // Assigned Message Type ID = 2002
    Foo3(...); // Assigned Message Type ID = 2003
}
```

每個函數都會將訊息類型值加一。 我們將指派給最後宣告的 RMI 函數的類型值稱為訊息範圍。 在上面的範例中，2,000 到 2,003 是 SampleRMI 的訊息範圍。

如果將建立的代理程式和存根附加到 <mark style="color:orange;">Proud.CNetClient</mark> , <mark style="color:orange;">Proud.CNetServer</mark> , <mark style="color:orange;">Proud.CLanClient</mark> , <mark style="color:orange;">Proud.CLanServer</mark>，則每個 RMI 函數群組的訊息範圍將保留給 <mark style="color:orange;">Proud.CNetClient</mark> , <mark style="color:orange;">Proud.CNetServer</mark> , <mark style="color:orange;">Proud.CLanClient</mark> , <mark style="color:orange;">Proud.CLanServer</mark>。

\
如果要附加的代理程式和存根的訊息範圍重疊，<mark style="color:orange;">AttachProxy()</mark> 或 <mark style="color:orange;">AttachStub()</mark> 將引發例外狀況。

{% hint style="info" %}
C# 中的 CNetClient -> <mark style="color:orange;">NetClient</mark>

C# 中的 CNetServer -> <mark style="color:orange;">NetServer</mark>
{% endhint %}

***

## 活用

{% content-ref url="/pages/SKVX5YhjdnUhzHciXEiZ" %}
[如何使用RMI](/proudnet.cn/proudnet/using_pn/rmi/using_rmi.md)
{% endcontent-ref %}
