# Utilization of Client

## Handling Timer Loop, RMI, and Events

Depending on the [**Client's main loop**](https://docs.proudnet.com/proudnet.eng/proudnet-note/notes/main_loop#undefined)**,** the client can call <mark style="color:orange;">FrameMove</mark> at regular intervals to receive accumulated RMI and process event handling. You are not required to call <mark style="color:orange;">FrameMove</mark> every second, but if you do not call it for too long, RMI received from the client will accumulate and increase memory usage.

## Getting various information

<mark style="color:orange;">Client</mark> can get information about P2P groups, the IPs of clients with P2P connections, their connection status with the server, and whether they are doing P2P relay with clients with P2P connections.<br>

<table data-full-width="false"><thead><tr><th width="209">C++ Functions</th><th width="237">C# Functions</th><th>Description</th></tr></thead><tbody><tr><td>Proud.CNetClient.GetGroupMembers</td><td>Nettention.Proud.NetClient.NativeNetClient.GetGroupMembers</td><td>Gets all users in the group corresponding to the HostID given as a parameter.</td></tr><tr><td>Proud.CNetClient.GetIndirectServerTimeMs</td><td>Nettention.Proud.NetClient.NativeNetClient.GetIndirectServerTimeMs</td><td>Gets the server time of the peer with the HostID entered as a parameter.</td></tr><tr><td>Proud.CNetClient.GetLastUnreliablePingMs</td><td>Nettention.Proud.NetClient.GetLastUnreliablePingMs</td><td>Gets the last ping time of the peer with the HostID entered as a parameter.</td></tr><tr><td>Proud.CNetClient.GetLocalHostID</td><td>Nettention.Proud.NetClient.GetLocalHostID</td><td>Get the client's local HostID.</td></tr><tr><td>Proud.CNetClient.GetLocalJoinedP2PGroups</td><td>Nettention.Proud.NetClient.GetLocalJoinedP2PGroups</td><td>Get a list of all joined P2P groups.</td></tr><tr><td>Proud.CNetClient.GetP2PServerTimeMs</td><td>Nettention.Proud.NetClient.NativeNetClient.GetP2PServerTimeMs</td><td>Gets the time of the P2P connected server in milliseconds.</td></tr><tr><td>Proud.CNetClient.GetPeerInfo</td><td>Nettention.Proud.NetClient.GetPeerInfo</td><td>Gets information about the peers connected to the client.</td></tr><tr><td>Proud.CNetClient.GetPeerReliableUdpStats</td><td>Nettention.Proud.NetClient.NativeNetClient.GetPeerReliableUdpStats</td><td>Get P2P reliable messaging system operation statistics (for performance measurement or debugging).</td></tr><tr><td>Proud.CNetClient.GetRecentUnreliablePingMs</td><td>Nettention.Proud.NetClient.GetRecentUnreliablePingMs</td><td>Returns the most recently taken ping time in milliseconds.</td></tr><tr><td>Proud.CNetClient.GetServerAddrPort</td><td>Nettention.Proud.NetClient.NativeNetClient.GetServerAddrPort</td><td>Get the address of the connected server.</td></tr><tr><td>Proud.CNetClient.GetServerConnectionState</td><td>Nettention.Proud.NetClient.GetServerConnectionState</td><td>Gets the status of the socket connection to the server.</td></tr><tr><td>Proud.CNetClient.GetServerTimeMs</td><td>Nettention.Proud.NetClient.NativeNetClient.GetServerTimeMs</td><td>Get the current time on the server.</td></tr><tr><td>Proud.CNetClient.GetServerTimeDiffMs</td><td>Nettention.Proud.NetClient.NativeNetClient.GetServerTimeDiffMs</td><td>Find the time difference between the client and server.</td></tr></tbody></table>

## Send and receive custom data during the server connection process

* When you populate custom field parameters in <mark style="color:orange;">Connect</mark>, its contents are passed to <mark style="color:orange;">OnConnectionRequest</mark>.
* If you populate custom parameters for the reply in <mark style="color:orange;">OnConnectionRequest</mark>, its contents are passed to <mark style="color:orange;">OnJoinServerComplete</mark>.

<figure><img src="https://content.gitbook.com/content/Ceg6wWD81CFYby05yPX5/blobs/L6cVa5KVDjJ3ZbYbqSxv/client_connect_server.png" alt=""><figcaption><p>Client-to-server connection process</p></figcaption></figure>

## Getting a hole-punched address

1. First, complete the P2P communication.
2. Get the client's information with <mark style="color:orange;">GetPeerInfo</mark> or <mark style="color:orange;">GetClientInfo</mark>.
3. The <mark style="color:orange;">udpAddrFromServer</mark> of the information obtained is the hole-punched address.

{% hint style="success" %}
**Reference**\
[**P2P Communication**](https://docs.proudnet.com/proudnet.eng/proudnet/using_pn/p2p)
{% endhint %}

## Getting the server's time

In ProudNet, you can get the time of the server for time synchronization between hosts.

<table data-full-width="false"><thead><tr><th width="205">C++ Functions</th><th width="240">C# Functions</th><th>Description</th></tr></thead><tbody><tr><td>Proud.CNetClient.GetServerTimeMs</td><td>Nettention.Proud.NetClient.GetServerTimeMs</td><td>Calculate the latency to the server to get the actual time on the server.</td></tr><tr><td>Proud.CNetClient.GetP2PServerTimeMs</td><td>Nettention.Proud.NativeNetClient.GetP2PServerTimeMs</td><td>A method of obtaining latency with a server and calculating and averaging the latency of other P2P-connected clients. Get the actual time of the server more accurately.</td></tr></tbody></table>

## Breaking a callback

<mark style="color:orange;">FrameMove</mark> will call all accumulated events and incoming RMI in unison.

ProudNet has the ability to return accumulated events and received RMI during processing within a single <mark style="color:orange;">FrameMove</mark> call section, if the user wishes. It then allows the remaining accumulated events and incoming RMI to be processed in the next <mark style="color:orange;">FrameMove</mark> call.

\
To terminate any remaining accumulated events and incoming RMI, you can call <mark style="color:orange;">HolsterMoreCallbackUntilNextFrameMove</mark> in the routine that is processing the RMI or the routine that is processing the event.

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

```cpp
DEFRMI_TestS2C_Foo(CMyClient)
{
    ...
    /* When you call this, CNetClient.FrameMove returns immediately, 
     ignoring any remaining accumulated events and RMI received. */
    HolsterMoreCallbackUntilNextFrameMove();
}
 
void CMyClient::OnLeaveServer(...)
{
    ...
        /* When you call this, CNetClient.FrameMove returns immediately, 
         ignoring any remaining accumulated events and RMI received. */
        HolsterMoreCallbackUntilNextFrameMove();
}
```

{% endtab %}

{% tab title="C#" %}

```csharp
simpleStub.Test = (remote, rmiContext, text) => {
    ...
    /* When you call this, CNetClient.FrameMove returns immediately, 
     ignoring any remaining accumulated events and RMI received. */
    netClient.HolsterMoreCallbackUntilNextFrameMove();
}

netClient.LeaveServerHandler = (errInfo) => {
    ...
    /* When you call this, CNetClient.FrameMove returns immediately, 
     ignoring any remaining accumulated events and RMI received. */
    netClient.HolsterMoreCallbackUntilNextFrameMove();
}

```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
**Reference**

[**Main loop**](https://docs.proudnet.com/proudnet.eng/proudnet-note/notes/main_loop)
{% endhint %}

<details>

<summary>Pending a callback</summary>

When various events and RMI received are called by <mark style="color:orange;">Proud.CNetClient.FrameMove</mark>, there is a feature that allows you to have the desired callback happen again at a later time, which is called **pending the callback**.\
If you suspend a callback, the pending callback goes to the back of the accumulated receive queue, and the callback occurs again the next time you call <mark style="color:orange;">CNetClient.FrameMove</mark>.

For example, if you put Callback B on hold, the callback will run as shown below.

FrameMove => Callback A => Callback B (Hold!) => return

FrameMove => Callback B(Replay what was on hold) => ... => return

If this callback feature is not understood and misused, it can be misinterpreted to mean that received RMIs or events do not arrive in the correct order, or that an infinite callback occurs. Therefore, caution is advised in its use.

To postpone the callback, you can call <mark style="color:orange;">Proud.INetClientEvent.PostponeThisCallback</mark> or <mark style="color:orange;">Proud.IRmiStub.PostponeThisCallback</mark> in a routine that is listening for RMI or a routine that is listening for events.

```cpp
DEFRMI_TestS2C_Foo(CMyClient)
{
    ...
    /* When you call this, CNetClient.FrameMove returns immediately, 
     ignoring any remaining accumulated events and RMI received. */
    PostponeThisCallback();
}
 
void CMyClient::OnLeaveServer(...)
{
    ...
    /* When you call this, CNetClient.FrameMove returns immediately, 
     ignoring any remaining accumulated events and RMI received. */
    PostponeThisCallback();
}
```

</details>

***

## :arrow\_left: [**Back**](https://docs.proudnet.com/proudnet.eng/proudnet/using_pn/server_client)


---

# 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.eng/proudnet/using_pn/server_client/using_client.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.
