Game as Socket Server

Hey All,

I am CEO of a company that does simulations. I have put 3 engineers on this task and all have failed. I have placed a bet that my dumb CEO butt can figure this out before they can. If I get this written and checked in before they do, I get to hang embarrassing posters in their offices for a month.

I know limited C++ and Unreal Engine 4. I was a unity dev and a.i. researcher once upon a time. If anybody can help me get this rolled out, that would be awesome. I need to set it up so that my Unreal Game is a socket server that I can connect to from a python application (random python application). The game will send me data on a trigger and I can send it data. When it receives data, it does something, who cares, turns a box red. I just need bi-directional communication between the two.

Data shipping out of the unreal game will be primarily soured from a class that extends SceneCapture2D shipping out the pixel data at 30-60 fps along with some meta data. Data coming in will be very light.

Any assistance is greatly appreciated. I just need to get a functional P.O.C. to win the bet.

try Unreal Messaging:

Hrm, the closest I could find to what I want is this: A new, community-hosted Unreal Engine Wiki - Announcements - Epic Developer Community Forums

Unfortunately it doesn’t appear to work. I can’t get my client to connect. Here is some sample client code. Its python 3.5

import socket
import time

client code

def openConnection(TCP_PORT=8423):
TCP_IP = ‘127.0.0.1’
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if s.connect_ex((TCP_IP, TCP_PORT)):
    print("Failed")
else:
    print("Connected")
return s

def sendMessage(s, MESSAGE):
s.send(MESSAGE)

def receiveMessage(s):
BUFFER_SIZE = 1024
data_raw = s.recv(BUFFER_SIZE)
data = data_raw.decode(“utf-8”)
print("client received data: " + data)
return data_raw

def closeConnection(s):
s.close()

if name == ‘main’:
time.sleep(2)
socket = openConnection()
if(socket == None):
print(“failed to create”)
else:
sendMessage(socket, “Testing Connection”.encode(“utf-8”))
time.sleep(30)
#data = s.recv(1024)
closeConnection(socket)
# print ‘Received’, repr(data)

Actually I’m able to get it to work, but only on the first launch and connection. If I leave the game running and attempt to connect to the game again, it fails. The client says “Connected”, however it appears the game does not register the problem. I can stop the game in the view port, and restart it, launch the client code. The client will register a connection and that it sent something, however the game will not register anything was received.

EDIT: GOT IT WORKING, putting modified listening code below

Last item I need to figure out is how to send data to a connected client on the socket.

//// Fill out your copyright notice in the Description page of Project Settings.
//
#include “RoboSimStudio.h”
#include “NetworkActor.h”
#include <string>
//
//
//// Sets default values
ANetworkActor::ANetworkActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don’t need it.
PrimaryActorTick.bCanEverTick = false;
}
//
//// Called when the game starts or when spawned
void ANetworkActor::BeginPlay()
{
Super::BeginPlay();
//IP = 127.0.0.1, Port = 8890 for my Python test case
if (!StartTCPReceiver(“RamaSocketListener”, “127.0.0.1”, 8423))
{
UE_LOG(LogTemp, Warning, TEXT(“TCP Socket Listener Failed!”));
return;
}
}
//
//// Called every frame
void ANetworkActor::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
//
//Rama’s Start TCP Receiver
bool ANetworkActor::StartTCPReceiver(
const FString& YourChosenSocketName,
const FString& TheIP,
const int32 ThePort
)
{
//Rama’s CreateTCPConnectionListener
ListenerSocket = CreateTCPConnectionListener(YourChosenSocketName, TheIP, ThePort);

//Not created?
if (!ListenerSocket)
{
	UE_LOG(LogTemp, Error, TEXT("StartTCPReceiver&gt;&gt; Listen socket could not be created! ~&gt; %s %d"), *TheIP, ThePort);
	return false;
}
UE_LOG(LogTemp, Warning, TEXT("StartTCPReceiver&gt;&gt; Listen socket created! ~&gt; %s %d"), *TheIP, ThePort);

//TODO: Start the Listener! //thread this eventually
GetWorldTimerManager().SetTimer(ConnectionListenTimer, this, &ANetworkActor::TCPConnectionListener, 0.01f, true);

return true;

}
//Format IP String as Number Parts
bool ANetworkActor::FormatIP4ToNumber(const FString& TheIP, uint8(&Out)[4])
{
//IP Formatting
TheIP.Replace(TEXT(" “), TEXT(”“));
const TCHAR *delim;
delim = TEXT(”.");

TArray&lt;FString&gt; Parts;
TheIP.ParseIntoArray(Parts, delim, true);
if (Parts.Num() != 4)
	return false;

for (int32 i = 0; i &lt; 4; ++i)
{
	Out* = FCString::Atoi(*Parts*);
}
return true;

}
//Rama’s Create TCP Connection Listener
FSocket* ANetworkActor::CreateTCPConnectionListener(const FString& YourChosenSocketName, const FString& TheIP, const int32 ThePort, const int32 ReceiveBufferSize)
{
uint8 IP4Nums[4];
if (!FormatIP4ToNumber(TheIP, IP4Nums))
{
UE_LOG(LogTemp, Error, TEXT(“Invalid IP! Expecting 4 parts separated by .”));
return false;
}
//Create Socket
FIPv4Endpoint Endpoint(FIPv4Address(IP4Nums[0], IP4Nums[1], IP4Nums[2], IP4Nums[3]), ThePort);
FSocket* ListenSocket = FTcpSocketBuilder(*YourChosenSocketName)
.AsReusable()
.BoundToEndpoint(Endpoint)
.Listening(8);
//Set Buffer Size
int32 NewSize = 0;
ListenSocket->SetReceiveBufferSize(ReceiveBufferSize, NewSize);
//Done!
return ListenSocket;
}
//Rama’s TCP Connection Listener
void ANetworkActor::TCPConnectionListener()
{
//~~~~~~~~~~~~~
//UE_LOG(LogTemp, Warning, TEXT(“Checking socket…”));
if (!ListenerSocket)
{
UE_LOG(LogTemp, Error, TEXT(“Listener doesn’t exist, but should.”));
return;
}

//Remote address
TSharedRef&lt;FInternetAddr&gt; RemoteAddress = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)-&gt;CreateInternetAddr();
bool Pending;

// handle incoming connections
if (ListenerSocket-&gt;HasPendingConnection(Pending) && Pending)
{
	UE_LOG(LogTemp, Warning, TEXT("Connection Pending..."));
	//Already have a Connection? destroy previous
	if (ConnectionSocket)
	{
		ConnectionSocket-&gt;Close();
		ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)-&gt;DestroySocket(ConnectionSocket);
	}
	//New Connection receive!
	ConnectionSocket = ListenerSocket-&gt;Accept(*RemoteAddress, TEXT("TODO: Start Kick off Event"));

	if (ConnectionSocket != NULL)
	{
		//Global cache of current Remote Address
		RemoteAddressForConnection = FIPv4Endpoint(RemoteAddress);
		//UE_LOG "Accepted Connection! WOOOHOOOO!!!";
		UE_LOG(LogTemp, Warning, TEXT("Accepted Connection!"));
		//can thread this too
		GetWorldTimerManager().SetTimer(SocketListenTimer, this, &ANetworkActor::TCPSocketListener, 0.01f, true);
	}
}

}

FString ANetworkActor::StringFromBinaryArray(const TArray<uint8>& BinaryArray)
{
//Create a string from a byte array!
std::string cstr(reinterpret_cast<const char*>(BinaryArray.GetData()), BinaryArray.Num());
return FString(cstr.c_str());
}

//Rama’s TCP Socket Listener
void ANetworkActor::TCPSocketListener()
{
//~~~~~~~~~~~~~
if (!ConnectionSocket) return;

//Binary Array!
TArray&lt;uint8&gt; ReceivedData;
uint32 Size;
while (ConnectionSocket-&gt;HasPendingData(Size))
{
	ReceivedData.Init(0.0f, FMath::Min(Size, 65507u));

	int32 Read = 0;
	ConnectionSocket-&gt;Recv(ReceivedData.GetData(), ReceivedData.Num(), Read);

	UE_LOG(LogTemp, Warning, TEXT("Data Read! %d"), ReceivedData.Num());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (ReceivedData.Num() &lt;= 0)
{
	//No Data Received
	return;
}
const FString ReceivedUE4String = StringFromBinaryArray(ReceivedData);
//Logging
UE_LOG(LogTemp, Warning, TEXT("Total Data read! %d"), ReceivedData.Num());
UE_LOG(LogTemp, Warning, TEXT("As String!!!!! ~&gt; %s"), *ReceivedUE4String);

}