4. Error Handling

To handle errors in P2P communication, your application must detect errors using two different methods. Use the NetZ::GetFatalError function to get errors that occur during processing by the NEX library, and use the SystemError::GetLast function to get errors that occur during P2P function calls.

When using NetZ::GetFatalError, the application must retrieve the corresponding error code and display it on the screen. The errors that you get when using SystemError::GetLast are generally supposed to be eliminated in the development stage. Your application should retrieve and display an error code only when it is unable to proceed.

4.1. Handling Internal NEX Library Errors During P2P Processing and Displaying Error Codes [Required]

The application must handle this class of errors, and display the error code on the screen. If a NetZ instance has been generated, you can use the NetZ::GetFatalError function to get P2P communication errors occurring in the NEX library.

Under the following conditions, the application must check for errors using the NetZ::GetFatalError function once per frame. You do not need to check for errors more frequently than this (such as every time you call a NEX API).

  • A NetZ instance has been generated.
  • The NetZ instance is not being destroyed (NetZ::Terminate or delete was called).

Use QFAILED to check the qResult returned by the NetZ::GetFatalError function, or compare with false to determine whether the qResult indicates failure.

The following code example shows the error-handling method using NetZ::GetFatalError.

Code 4.1 Sample Handling of Non-Recoverable Errors in P2P Communication

// - A NetZ instance has been generated.
// - The NetZ instance is not being destroyed.
// - Check for errors every frame.
NetZ* pNetZ = NetZ::GetInstance();
if (pNetZ)
{
    qResult fatal = pNetZ->GetFatalError();
    if ( QFAILED(fatal.GetReturnCode()) ) //  if ( fatal == false ) is also possible.
    {
        // A fatal error has occurred.

        // Get the error code.
        qUnsignedInt32 errcode = ErrorCodeConverter::ConvertToNetworkErrorCode(fatal);


        // Discard the NetZ instance immediately.


        // Display the error code on the screen.

    }
}
Table 4.1 Errors That May Be Generated by NetZ::GetFatalError
Return Value of NetZ::GetFatalError Description of Error
QSUCCESS(Core, Success) Value indicating success, returned when no error has occurred.
QERROR(DOCore, InvalidState) The DuplicatedObject is in an invalid state.
QERROR(DOCore, FaultRecoveryFatal) The DuplicatedObject failed to begin fault recovery.
QERROR(DOCore, FaultRecoveryJobProcessFailed) The DuplicatedObject failed during fault recovery.
QERROR(DOCore, StationInconsistency) The station count continues in a state different from the session master
QERROR(Transport, ReliableSendBufferFullFatal) The buffer used for reliable communication is out of space.
QERROR(Transport, NoBuffer) Receive data caused the direct stream receive buffer to overflow.

4.1.1. What to Do When the Reliable Buffer Is Not Large Enough

There is currently no way for the application to avoid the errors that can be retrieved from NetZ::GetFatalError. Overuse of reliable sending during development results in QERROR(Transport, ReliableSendBufferFullFatal) errors, even if there are no problems with the communication environment. You can avoid this problem by taking the following steps.

  • Use reliable communication less frequently.
  • Switch from reliable communication to unreliable communication. (Confirm receipt yourself if necessary when using unreliable communication.)

Note

For safety, the DirectStream::Send function only returns QERROR(Transport, ReliableSendBuffer) before the system reaches its limit, and does not generate a NetZ fatal error.

The buffer typically overflows because of frequent reliable communications related to transferring duplicated objects, or because of reliable communications inside NEX when the NetZ::GetFatalError function returns QERROR(Transport, ReliableSendBufferFullFatal). Because the amount of communication data inside NEX is relatively small, chances are high that the cause is the frequent reliable transfer of duplicated objects, or connectivity problems.

4.2. Handling Errors From Calls to the SystemError::GetLast Function and Displaying the Error Code [Required If Game Progress Is Otherwise Impossible]

If this error prevents progress in the game, your application must handle it and display the error code on the screen.

Some NEX functions return false or a null pointer when they fail to run, or when an asynchronous request fails. The NEX API design enables the application to find out what the error is when this happens, using the SystemError::GetLast function. This error is typically eliminated during development, because it is usually caused by a programming error in the application.

The SystemError::GetLast function only gets errors that occur in the same thread that called one of these functions. It does not retrieve errors that occurred in other threads.

You can use the SystemError::GetErrorString function to get an easier-to-understand string representation of the error. This is useful for debugging. You do not need to display this string on the screen in retail builds.

Code 4.2 Sample Handling of Errors Generated by Session::JoinSession

CallContext cc;
if (Session::JoinSession(&cc, lstURL) == false)
{
    // API call fails in `JoinSession.`

    // Get the error set by `Session::JoinSession.`
    qUnsignedInt32 last = SystemError::GetLast();

    // For debugging purposes.
    qChar msg[128];
    SystemError::GetErrorString(last, msg, 128);
    SAMPLE_LOG("JoinSession is failed. System last error:%u, Error:%ls", last, msg);

    // Display the error code on the screen.
    qUnsignedInt32 errcode = ErrorCodeConverter::ConvertToNetworkErrorCode(last);
}

CONFIDENTIAL