# ProudNet Utility

## Using collections

STL, ATL, etc. already provide collection classes (<mark style="color:orange;">std.map</mark>, <mark style="color:orange;">std.vector</mark>, <mark style="color:orange;">CFastArray</mark>, <mark style="color:orange;">CAtlArray</mark>, <mark style="color:orange;">CAtlMap</mark>, etc.). However, ProudNet provides a set of classes that work well in situations where both STL and ATL are not available, or where high performance is required.

| Class             | Function         | Description                                                                                                                                                     |
| ----------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Array Class       | Proud.CFastArray | Internally, it uses a [**Fast heap**](/proudnet.eng/proudnet/pn_utility.md#fast-heap).                                                                          |
| Linked List Class | Proud.CFastList  | It uses Fast Heap internally. Unlike CFastArray, the class can be used with constructors, destructors, and copy allocation operators.                           |
| Map Class         | Proud.CFastMap   | It uses a hash algorithm for (Key,Value) pairs. It is very similar in usage to CAtlMap, and can use the same iterators and some of the same methods as STL.map. |
| Set Class         | Proud.CFastSet   | Unlike CFastMap, it is a class that only owns the key, the rest is the same as CFastMap.                                                                        |

<br>

## Quick Memory Manager

ProudNet has a built-in high-performance memory manager, which developers can use to accelerate the processing power of their applications.

The following memory managers are supported by ProudNet.

### -  Lookaside allocator

The <mark style="color:orange;">lookaside allocator</mark> applies the usual memory pool technique. If you need to allocate and deallocate the same amount of memory frequently, you may want to use the <mark style="color:orange;">lookaside allocator</mark>.

The main mechanisms are described below.

> * When allocating a new memory block, new system memory is allocated.
> * When freeing a block of memory, the freed block is returned to the <mark style="color:orange;">lookaside allocator</mark>.
> * When reallocating memory blocks, the memory blocks returned by the <mark style="color:orange;">lookaside allocator</mark> are recycled.

This process runs at a very high speed. It is much faster than memory allocation in the OS environment.

But there are also disadvantages.

> * &#x20;A <mark style="color:orange;">lookaside allocator</mark> can only allocate memory that is always the same size.
> * All memory blocks allocated by the <mark style="color:orange;">lookaside allocator</mark> must be freed before the <mark style="color:orange;">lookaside allocator</mark> is destroyed.

Here is how to use the <mark style="color:orange;">lookaside allocator</mark>.

> * First, create an object with the <mark style="color:orange;">Proud.CLookasideAllocator.New</mark> method.\
>   You can also create it as a global object.
> * Allocate a block of memory with the <mark style="color:orange;">Proud.CLookasideAllocator.Alloc</mark> method.
> * Freeing is done with <mark style="color:orange;">Proud.CLookasideAllocator.Free</mark>. Realloc does not exist.
> * Destroy the <mark style="color:orange;">Proud.CLookasideAllocator</mark> object after freeing all memory blocks.

### - Fast Heap

ProudNet's <mark style="color:orange;">Fast heap</mark> is slightly slower than the <mark style="color:orange;">Lookaside allocator</mark>, but much faster than memory allocation/release in the OS environment, and can allocate/release memory blocks of different sizes.

The implementation class for ProudNet's Fast heap is <mark style="color:orange;">Proud.CFastHeap</mark>. <mark style="color:orange;">Proud.CFastHeap</mark> also allows you to remove <mark style="color:orange;">Proud.CFastHeap</mark> objects after all memory blocks have been destroyed.

\
Here is how to use <mark style="color:orange;">Fast heap</mark>.

> * First, create a <mark style="color:orange;">Fast heap</mark> object with the <mark style="color:orange;">Proud.CFastHeap.New</mark> method. You can also create it as a global object.
> * Allocate a block of memory with the <mark style="color:orange;">Proud.CFastHeap.Alloc</mark> method.
> * Freeing is done with <mark style="color:orange;">Proud.CFastHeap.Free</mark>. Memory blocks can be reallocated with <mark style="color:orange;">CFastHeap.Realloc</mark>.
> * Destroy the <mark style="color:orange;">Proud.CFastHeap</mark> object after freeing all memory blocks.

## Specify as default allocator for C++ class

An easy way to accelerate a <mark style="color:orange;">fast heap</mark> or <mark style="color:orange;">lookaside allocator</mark> in a C++ class is to override C++'s <mark style="color:orange;">operator new</mark>, <mark style="color:orange;">delete</mark> methods.

This ensures that when C++ classes are created and destroyed with the new, delete operators, the <mark style="color:orange;">fast heap</mark> or <mark style="color:orange;">lookaside allocator</mark> is used instead of the system's memory heap.

\
In the example below, when the class instantiates with the <mark style="color:orange;">operator new</mark> or <mark style="color:orange;">delete</mark>, we let the high-performance memory manager allocate/free memory on our behalf. There are different advantages and disadvantages to each, so choose and use accordingly.

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example</summary>

```cpp
class Example
{
    static CLookasideAllocatorPtr gAlloc; // Alternatively, you can use CFastHeap.
public:
    void* operator new(size_t size)
    {
        return gAlloc->Alloc(size);
    }
    void operator delete(void* ptr, size_t size)
    {
        gAlloc->Free(ptr);
    }
};
 
CLookasideAllocatorPtr Example::gAlloc(CLookasideAllocator::New()); // Alternatively, you can use CFastHeap.
```

</details>

## Smart Pointer

ProudNet has a smart pointer <mark style="color:orange;">Proud.RefCount</mark> class.

A smart pointer guarantees the existence of a created object as long as there are variables referring to it, and only destroys it when the variables referring to it no longer exist.

It also serves to eliminate the problem of referencing objects that have already been destroyed due to developer-created bugs (dangling) or not destroying objects in time (leak).

Each time a smart pointer variable is copied, the object reference count increases by 1. In the picture below, the Object Instance exists until the reference count becomes 0.

<figure><img src="/files/pDZp0nHLOm5Q5BBI3iYn" alt=""><figcaption><p>Relationship between smart pointers and objects</p></figcaption></figure>

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example code</summary>

```cpp
class A {...};
 
void Foo()
{
    // A object is created
    Proud::RefCount<A> a(new A);
    
    // Variable B is shared with variable A. A's reference count becomes 2.
    Proud::RefCount<A> b = a;
    
    // The variable A is freed. However, A is not destroyed because its reference count is still 1.
    a = Proud::RefCount<A>();
    
    // The variable B is freed. A is destroyed because there is no longer a variable referencing it. (i.e. delete is called)
    b = Proud::RefCount<A>();
}
```

</details>

There are times when you have multiple <mark style="color:orange;">smart pointers</mark> referencing an object and you want to force the object to be destroyed.

For example, if a <mark style="color:orange;">smart pointer</mark> is referencing an object that holds an open file handle, there will be times when you need to destroy the object that holds that file handle immediately.

However, if a <mark style="color:orange;">smart pointer</mark> is referencing that object here and there, you may run into trouble because you do not know when the object is destroyed. For these cases, you can use the <mark style="color:orange;">Dispose Pattern</mark> to explicitly destroy an object that is referenced in multiple places.

### - Dispose Pattern

<mark style="color:orange;">Dispose Pattern</mark> is a program pattern for achieving the effect of explicitly destroying an object referenced by one or more <mark style="color:orange;">smart pointers</mark> without knowing exactly when the object will be destroyed.

To use the <mark style="color:orange;">Dispose Pattern</mark> on an object that will be treated as a smart class, the object must have a "self-state" as a member variable, which means that the object has already been destroyed and is unusable.\
If the self-state is 'already destroyed', then we should raise an error when referencing the object, and otherwise make it perform normally.

Below is an example of using the <mark style="color:orange;">Dispose Pattern</mark>.

{% hint style="info" %} <mark style="color:orange;">Dispose Pattern</mark> is also covered in programming languages with <mark style="color:orange;">smart pointer</mark> and <mark style="color:orange;">Garbage Collector</mark>, such as Java and C#.
{% endhint %}

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example code</summary>

```cpp
class A
{
    // If true, it means that this object is in the disposed state.
    bool m_disposed;
    public:
    
    A()
    {
        // Newly created objects are not disposed of.
        m_disposed = false;
    }
 
    ~A()
    {
        Dispose();
    }
 
    void Dispose()
    {
        if(m_disposed == false)
        {
            // Performs actual operations related to object destruction.
            // For example, close the file handle you were holding.
            ...
        
            m_disposed = true;
        }
    }
};
 
typedef Proud::RefCount<A> APtr;
 
void Foo()
{
    APtr a(new A); // Create an object
    APtr b = a;     // Two smart pointer variables share an object
    
    a->Dispose();   // Forcibly destroys the object.
    
    // Now both A and B objects are destroyed.
    // Therefore, the object being referenced by a,b should not be accessed.
    ...
}
```

</details>

## Thread Utility

ProudNet offers several thread utility classes.

<table><thead><tr><th width="275">Classes</th><th>Description</th></tr></thead><tbody><tr><td>Proud.Thread </td><td>Easily create and destroy threads.</td></tr><tr><td>Proud.CriticalSection</td><td>You can create a critical section.</td></tr><tr><td>Proud.CriticalSectionLock</td><td>You can lock and unlock.</td></tr></tbody></table>

## String Class

ProudNet provides string classes <mark style="color:orange;">Proud.String</mark>, <mark style="color:orange;">Proud.StringA</mark> that make handling strings as easy as the string classes in ATL or STL.

{% hint style="warning" %}
Programs that use the .Net Framework have a symbol called System.string.\
So if you are mixing .Net Frameworks, you may need to specify the namespace of either System or Proud.
{% endhint %}

\
For example, see below.

```cpp
Proud::String a;  // Empty string
a = L"123";         // Putting a value in a string.
puts(a);            // A itself provides the string buffer directly.
a += L"abc";        // Adding another string to a string
if(L"123abc" == a)  // How to compare the contents of strings
{
    a.Replace(L"123", "def");   // Replace string contents
}
```

### - String creation function(format)

<mark style="color:orange;">Proud.StringT</mark> provides a string creation function like <mark style="color:orange;">sprintf()</mark>.

```cpp
Proud::String a;
a.Format(L"%d %d %s", 1, 2, L"hahaha");
// Now a = "1 2 hahaha".
```

### - [Unicode-to-Multibyte Interconversion](/proudnet.eng/proudnet-note/notes.md#unicode-to-multibyte-interconversion)

### -  String processing performance

#### Copy-on-write

```cpp
// Proud.StringT's copy-on-write feature only leaves a copy of the string if it is absolutely necessary. 
// Before that, they will share string data with each other.
 
Proud::String a = L"abc"; // a owns the string 'abc'
Proud::String b = a; // b shares the same string data as a
Proud::String c = b; // Now a,b,c all share the same string data
c = L"bcd"; // a,b still share the string data ‘abc', but c no longer shares it and owns ‘bcd' separately
b = c; // b gives up sharing ‘abc' with a and shares ’bcd' with c.
```

#### Measuring String Length

<mark style="color:orange;">Proud.StringT.GetLength</mark> returns the pre-measured length of the string immediately upon call, which is different from <mark style="color:orange;">strlen()</mark>.

{% hint style="warning" %} <mark style="color:orange;">Proud.StringT</mark> does not have a thread safe like int or float.\
Therefore, it is not safe to access the same string object from multiple threads at the same time (unless all threads are read only).

This is the same as for string classes in ATL or STL.
{% endhint %}

## Timer Queue

<mark style="color:orange;">Timer Queue</mark> is a module that performs tick event on a <mark style="color:orange;">thread pool</mark> and provides an API called Windows Timer Queue on Windows XP, 2000 and later operating systems.

Run a function you specify at a certain time, but the function runs on one of the threads in the <mark style="color:orange;">thread pool</mark>. If all the threads are running something (in a running state), the execution of the function is put on hold until one of the threads finishes its past work.

The user function calling from the <mark style="color:orange;">Timer Queue</mark> will be selected from one of the threads in the <mark style="color:orange;">thread pool</mark>, and if there is a thread with nothing to do (idle state), it will be selected to execute the user function, even if the user function that was running earlier has not finished executing.

Suppose you have the following task list.

The black arrow is 0.1 seconds and A,B,C,D,E are the action items that need to be done every 0.1 seconds. A,D will be done in less than 0.1 seconds, B will be done in exactly 0.1 seconds, and C,E will not be done in 0.1 seconds.

<figure><img src="/files/3XNZxs8teQrKk7vMRAeF" alt=""><figcaption><p>Action items that need to run at regular intervals</p></figcaption></figure>

In the [**server main loop**](/proudnet.eng/proudnet-note/notes/main_loop.md#server-main-loop) approach, these work items are performed as shown in the following figure. Because it executes all work items in one thread, D,E does not start in time.

<figure><img src="/files/wIguyEncXDWXLfUzgxDi" alt=""><figcaption><p>When executing work items in one thread</p></figcaption></figure>

However, in the <mark style="color:orange;">Timer Queue</mark> approach, another thread is mobilized to execute D, and E is running in time on the thread that completed C earlier.

<figure><img src="/files/gZ6RzA3q7SvgATE2Odd5" alt=""><figcaption><p>When executing work items in a timer queue method</p></figcaption></figure>

Execute the necessary tasks on time, but mobilize more threads if necessary.

<mark style="color:orange;">Timer Queue</mark> is primarily used in server programs due to the fact that user functions can be running on more than one thread at the same time.

While it enables parallelism, it comes with its own set of risks, so determine if you really need this feature before using it.

{% hint style="danger" %}
If <mark style="color:orange;">Timer Queue</mark> is used incorrectly, the number of threads in the server process may increase explosively, which may have an adverse effect on performance.\
If there is no compelling reason to use <mark style="color:orange;">Timer Queue</mark>, use <mark style="color:orange;">Proud.CTimerThread</mark> or [**handle timer loop, RMI, and events on the server**](/proudnet.eng/proudnet/using_pn/server_client/using_server.md#handling-timer-loop-rmi-and-events).
{% endhint %}

### - How to use a timer queue

You need to access the <mark style="color:orange;">Proud.CTimerQueue</mark> class, which is a singleton.

You can set the function to be called at a certain time and how often it will be called in a <mark style="color:orange;">Proud::NewTimerParam</mark> structure and pass it as an argument to <mark style="color:orange;">Proud.CTimerQueue.NewTimer</mark> and you will receive a <mark style="color:orange;">Proud.CTimerQueueTimer</mark> object.\
And until you destroy the <mark style="color:orange;">Proud.CTimerQueueTimer</mark> object, the user function you specify will be executed at regular intervals.

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example code</summary>

```cpp
VOID NTAPI UserFunction(void* context, BOOLEAN TimerOrWaitFired)
{
    int *pCallCount = static_cast<int *>(context);
 
    // User Functions
    std::cout << "UserFunction : " << ++(*pCallCount) << std::endl;
}
 
int _tmain(int argc, TCHAR* argv[])
{
    // NewTimerParam structure variable declaration.
    NewTimerParam p1;
 
    // Declare a variable for counting in your test
    int callCount = 0;
 
    // Setting up user functions.
    p1.m_callback = UserFunction;
 
    // Set the pointer to receive as a parameter.
    p1.m_pCtx = &callCount;
 
    // Set the callback to start after 1 second.
    p1.m_DueTime = 1000;
 
    // Set to callback every 0.1 seconds.
    p1.m_period = 100;
 
    // Have a user function called every 0.1 seconds on a pool of threads at a certain time.
    Proud::CTimerQueueTimer* ret = Proud::CTimerQueue::GetSharedPtr()->NewTimer(p1);
 
    std::cout << "PRESS ANY KEY TO EXIT" << std::endl;
 
    // Wait for the user callback to be called
    _getch();
 
    // Destroy the timer object. After destroying it, the user function is no longer called.
    delete ret;
}
```

</details>

## Leaving a log

When developing an online game, you may need the ability to leave various execution records (logs). ProudNet provides the ability to leave logs for this purpose.

<figure><img src="/files/D0D2mSoRKtI2n9NXPD5w" alt=""><figcaption><p>Windows also has the ability to log events.</p></figcaption></figure>

ProudNet's logging function runs asynchronously, so the method returns as soon as you call the method to leave a log. Additionally, a separate thread writes the actual log to a file or database.

### - Logging to a file

The <mark style="color:orange;">Proud::CLogWriter</mark> class allows you to write logs to a file.

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example code</summary>

```cpp
// Create a CLogWriter.
CAutoPtr<Proud::CLogWriter> logwriter;
logwriter.Attach(Proud::CLogWriter::New(L"log.txt"));
 
// Let's write a log. It provides two WriteLine functions
logwriter->WriteLine( Proud::TraceID::TID_System, L"This is the system log. );
logwriter->WriteLine( "This is the %dth log.", 1 );
 
// Let's replace it with a new log file. If the creation of the new file fails, it will be exceptioned with Proud::Exception.
logwriter->SetFileName(L"log2.txt);
```

</details>

### - Logging to a database

The <mark style="color:orange;">Proud::CDbLogWriter</mark> class allows you to write logs to the DB.

To use this, you must create a LogTable in advance by running <mark style="color:orange;">LogTable.sql</mark> in the <mark style="color:orange;">Sample/DbmsSchema</mark> folder. To build a DBMS, refer to the procedure in Building a Sample Database.

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example code</summary>

```cpp
// A function to receive and handle errors.
class CTestLogWriterDelegate : public ILogWriterDelegate
{
    virtual void OnLogWriterException(Proud::AdoException& Err) override
    {
        // ...
    }
};
 
CTestLogWriterDelegate g_dblogDelegate;
 
void main()
{
    // ...
    // Fill in the CDbLogParameter with a value.
    Proud::CDbLogParameter dbparam;
    dbparam.m_dbmsConnectionString = L"Data Source=localhost;Database=Log-Test;Trusted_Connection=yes";
    dbparam.m_loggerName = L"LoggerName";
    dbparam.m_dbLogTableName = L"DbLog";
 
    // Create a CDbLogWriter.
    CAutoPtr<Proud::CDbLogWriter> dbLogWriter;
    dbLogWriter.Attach(Proud::CDbLogWriter::New(dbparam, &g_dblogDelegate));
    
    // Let's add a new field that ProudNet doesn't provide.
    // Caution!!! If you want to add your own fields, you need to create them in the Log-Test Table in the DBMS.
    // If you create a TestField in the DBMS and the datatype is int, you can create a CPropNode and put it in the WriteLine like the syntax below.
    Proud::CProperty newnode;
    Proud::String TestField = L"TestField";
    Proud::CVariant TestValue = 123;
    newnode.Add(TestField, TestValue);
    dbLogWriter->WriteLine(L"The contents of the log.", &newnode);
    
    // ...
}
```

</details>

## Latency Measurement Features

ProudNet provides latency measurement in the form of StopWatch.

If it is available, you should use it instead of the server's <mark style="color:orange;">GetLastPing</mark> or <mark style="color:orange;">GetRecentPing</mark>, as it is more accurate than traditional latency measurement functions.

### (1) Start measuring latency

Calling <mark style="color:orange;">StartRoundTripLatencyTest</mark> starts the object and relay for measuring latency.

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example code</summary>

```cpp
StartRoundTripLatencyTestParameter testParameter;
testParameter.testDuration = 40 * 1000; // A variable that specifies how long to wait for StopRoundTripLatencyTest to be called in the middle of a RoundTripLatencyTest. The unit is milliseconds. It defaults to 500 ms.
testParameter.pingIntervalMs = 400; // Variable that specifies how often to ping during the RoundTripLatencyTest. The unit is milliseconds. It defaults to 300 ms.
ErrorType startError = netClient->StartRoundTripLatencyTest(HostID_Server, testParameter);
switch(startError)
{
    case ErrorType_Ok:
        std::cout << "success" << std::endl;
        break;
    case ErrorType_InvalidHostID:
        std::cout << "If the HostID is itself or is not a connected peer" << std::endl;
    break;
}
```

</details>

### (2) End of latency measurement

If you want to stop the test before the previously specified testDuration, call the <mark style="color:orange;">StopRoundTripLatencyTest</mark> function. If you do not call <mark style="color:orange;">StopRoundTripLatencyTest</mark> until the testDuration has passed, the measurement will automatically stop.

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example code</summary>

```cpp
ErrorType stopError = StopRoundTripLatencyTest(HostID_Server);
switch(stopError)
{
    case ErrorType_Ok:
        std::cout << "success" << std::endl;
        break;
    case ErrorType_InvalidHostID:
        std::cout << "If it is not a connected peer" << std::endl;
        break;
}
```

</details>

### (3) Getting latency measurements

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="27a1">➡️</span> Example code</summary>

```cpp
RoundTripLatencyTestResult testResult;
ErrorType getError = GetRoundTripLatency(HostID_Server, testResult);
switch(getError)
{
    case ErrorType_Ok:
        std::cout << "Success" << std::endl;
        std::cout << "Ping-pong average over the measurement period : " << testResult.latencyMs 
<< ", Ping-pong standard deviation over the measurement period : " << testResult.standardDeviationMs 
<< ", Number of ping-pongs executed during the measurement period : " << testResult.totalTestCount << std::endl;
        break;
    case ErrorType_InvalidHostID:
        std::cout << "If you are not a connected peer" << std::endl;
        break;
    case ErrorType_ValueNotExist:
        std::cout << "If the ping-pong never happened" << std::endl; // In this case, the totalTestCount of the RoundTripLatencyTestResult is 0.
        break;
}
```

</details>

## PIDL Compiler Add-on

This is an add-on for Visual Studio that allows you to easily set up Custom Build from ProudNet IDL (PIDL) files.

### - Setting

1\. Run <mark style="color:orange;">\<installation path>\ProudNet\util\PIDL-addon.vsix</mark>.&#x20;

<figure><img src="/files/67OzpmxB6vo0YiWriGFg" alt=""><figcaption></figcaption></figure>

####

2\. Select the Visual Studio you want to install the add-on to and proceed to Install.

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

3\. When installation is completed successfully, it will be displayed as shown below.

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

### - Delete

You can uninstall it through the <mark style="color:orange;">Tools</mark> → <mark style="color:orange;">Extensions and Updates</mark> menu.

{% hint style="info" %}
For Visual Studio 2010, click <mark style="color:orange;">Tools</mark> → <mark style="color:orange;">Extension Manager</mark>
{% endhint %}

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

### - Add PIDL File Window

Call the Add PIDL window.\ <mark style="color:orange;">Select Project</mark> → <mark style="color:orange;">right click</mark> → select <mark style="color:orange;">Add new PIDL file</mark>&#x20;

<figure><img src="/files/1sfRFk7GL5myehPakhi2" alt=""><figcaption></figcaption></figure>

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

> 1. Enter a PIDL file name.
> 2. Displays the path where the PIDL file will be added.
> 3. Add an external PIDL file.
> 4. Create a new PIDL file.
> 5. Exit the Add PIDL window.

### - Add a PIDL file

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

> 1. Enter the name of the PIDL file to add
> 2. Click New PIDL

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

A PIDL file is added, as shown above, and the Custom Build settings for that file are by default. If they differ from the default settings, you can change them via the Change File Properties feature.

### - PIDL File Properties Window

Call the PIDL Properties window.

<mark style="color:orange;">Select PIDL file</mark> → <mark style="color:orange;">right click</mark> → <mark style="color:orange;">select Properties</mark>

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

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

> 1. View/change the Custom Build Tool settings in the PIDL file.\
>    \ <mark style="color:orange;">PIDL Compiler Location</mark>: Set the PIDL compiler location.\ <mark style="color:orange;">PIDL Compiler Location is Relative</mark>: The absolute/relative value of the entered path.\ <mark style="color:orange;">Output Directory (All Languages)</mark>: Set the output path.\ <mark style="color:orange;">Output Directory is Relative (All Languages)</mark>: The absolute/relative value of the entered path.

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

> 1. Language-specific settings windows: These can be created for each of the C++, C#, Java, and Unreal Script languages.<br>
> 2. Language-specific settings window: \
>    \ <mark style="color:orange;">Generate Code:</mark> C++ default Yes, other languages False (can be set as needed)\ <mark style="color:orange;">C++ Implementation File Extension</mark>: C++ only.


---

# 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/pn_utility.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.
