Skip to content

File ggponet.cpp

File List > GGPOUE4 > Public > include > ggponet.cpp

Go to the documentation of this file

/* -----------------------------------------------------------------------
 * GGPO.net (http://ggpo.net)  -  Copyright 2009 GroundStorm Studios, LLC.
 *
 * Use of this software is governed by the MIT license that can be found
 * in the LICENSE file.
 */

#include "ggponet.h"
#include "UObject/UObjectGlobals.h"

#define ARRAYSIZEOF(a) sizeof(a) / sizeof(a[0])

//UGGPONetworkAddress

UGGPONetworkAddress* UGGPONetworkAddress::CreateNetworkAddress(UObject* Outer, const FName Name, const FString Address)
{
    UGGPONetworkAddress* Result = NewObject<UGGPONetworkAddress>(Outer, Name);
    // Same type, apparently?
    const wchar_t* address = (wchar_t*)*Address;

    wchar_t WideIpBuffer[128];
    uint32 WideIpBufferSize = (uint32)ARRAYSIZEOF(WideIpBuffer);
    // Check and get port
    if (swscanf(address, L"%[^:]:%hd", WideIpBuffer, &Result->Port) != 2) {
        Result->bValidAddress = false;
    }
    else
    {
        // Get address
#ifdef _WIN32
        wcstombs_s(nullptr, Result->IpAddress, ARRAYSIZEOF(Result->IpAddress), WideIpBuffer, _TRUNCATE);
#else
        // FIXME: Implement this case.
#endif
    }

    return Result;
}
UGGPONetworkAddress* UGGPONetworkAddress::CreateLocalAddress(UObject* Outer, const FName Name, int32 LocalPort)
{
    UGGPONetworkAddress* Result = NewObject<UGGPONetworkAddress>(Outer, Name);

    Result->bValidAddress = true;
    Result->Port = (uint16)LocalPort;
    strcpy(Result->IpAddress, "127.0.0.1");

    return Result;
}

void UGGPONetworkAddress::GetIpAddress(char OutAddress[32]) const
{
    std::memcpy(OutAddress, IpAddress, sizeof(IpAddress));
}

bool UGGPONetworkAddress::IsValidAddress() const
{
    return bValidAddress;
}
FString UGGPONetworkAddress::GetIpAddressString() const
{
    auto address = FString(ANSI_TO_TCHAR(IpAddress));
    return address;
}
int32 UGGPONetworkAddress::GetPort() const
{
    return Port;
}

bool UGGPONetworkAddress::IsSameAddress(const UGGPONetworkAddress* Other) const
{
    if (bValidAddress != Other->bValidAddress)
        return false;
    if (!std::equal(std::begin(IpAddress), std::end(IpAddress), std::begin(Other->IpAddress)))
        return false;
    if (Port != Other->Port)
        return false;

    return true;
}

// UGGPONetwork

UGGPONetwork* UGGPONetwork::CreateNetwork(UObject* Outer, const FName Name, int32 NumPlayers, int32 PlayerIndex, int32 LocalPort, TArray<FString> RemoteAddresses)
{
    UGGPONetwork* Result = NewObject<UGGPONetwork>(Outer, Name);

    Result->LocalPlayerIndex = PlayerIndex - 1;
    int32 remoteIndex = 0;
    for (int32 i = 0; i < NumPlayers; i++)
    {
        // Only the port matters for local player
        if (i == Result->LocalPlayerIndex)
        {
            // Create a GGPO Network Address and add to the addresses
            UGGPONetworkAddress* address = UGGPONetworkAddress::CreateLocalAddress(
                Outer,
                FName(FString::Printf(TEXT("P%dIPAddress"), i + 1)),
                LocalPort);
            Result->Addresses.Add(address);
        }
        else
        {
            // If we ran out of remote addresses, clear the addresses and break
            if (remoteIndex >= RemoteAddresses.Num())
            {
                Result->Addresses.Empty();
                break;
            }

            // Create a GGPO Network Address and add to the addresses
            UGGPONetworkAddress* address = UGGPONetworkAddress::CreateNetworkAddress(
                Outer,
                FName(FString::Printf(TEXT("P%dIPAddress"), i + 1)),
                RemoteAddresses[remoteIndex]);
            Result->Addresses.Add(address);
            remoteIndex++;
        }
    }

    return Result;
}

bool UGGPONetwork::AllValidAddresses() const
{
    // If there are no players, this isn't valid
    if (Addresses.Num() == 0)
        return false;

    for (int32 i = 0; i < Addresses.Num(); i++)
    {
        // If an address is invalid, return false
        UGGPONetworkAddress* address = Addresses[i];
        if (!address->IsValidAddress())
            return false;
    }

    return AllUniqueAddresses();
}
bool UGGPONetwork::AllUniqueAddresses() const
{
    for (int32 i = 0; i < Addresses.Num(); i++)
    {
        for (int32 j = i + 1; j < Addresses.Num(); j++)
        {
            // If the address is the same, return false
            if (Addresses[i]->IsSameAddress(Addresses[j]))
                return false;
        }
    }

    return true;
}

UGGPONetworkAddress* UGGPONetwork::GetAddress(int32 Index) const
{
    if (Index < 0 || Index >= Addresses.Num())
        return nullptr;

    return Addresses[Index];
}
int32 UGGPONetwork::NumPlayers() const
{
    return Addresses.Num();
}
int32 UGGPONetwork::GetPlayerIndex() const
{
    return LocalPlayerIndex;
}
int32 UGGPONetwork::GetLocalPort() const
{
    // Just in case
    if (LocalPlayerIndex <= -1)
        return 7000;

    return Addresses[LocalPlayerIndex]->GetPort();
}