Game Development Community

How do I persistant gamebase object over two server instances?

by Johnathan Moore · in Torque 3D Professional · 01/25/2014 (9:08 pm) · 10 replies

Hello.
I intend on using two server instances. World map, and Battle.
I have a gamebase child class "Hero". Which has RPG things, like how well they can juggle.

By what method can I pass the class data (pack update stuff) between them? Preferably avoiding using the client as an intermeidary. Although, not that important.
I can think of writing a net event to create a duplicate object and destroy the old one?
Thanks for your attention.

#1
01/26/2014 (7:20 am)
TCPObject might help with this one - but it'd be all custom engine-side code.

If the two server instances are on the same machine you might write the data out to a file and then when the client connects to the "battle" instance read that data back in - primitive and prone to timing issues, but you can always add a few short delays in script I suppose.

Hell, if they both have access to a network share the file copy thing would work even if they were on different machines - but timing becomes more problematic.
#2
01/26/2014 (6:40 pm)
That seems like what I need.
I can just create some globalish storage if they're both localhost.

http://docs.garagegames.com/torque-3d/reference/classTCPObject.html

However, I've read this doc briefly and it says the data is stored as a sting, and has to be terminated with the string terminal character. i.e. it's actually relevent to the flow of data I assume.

Therefore, I would have to invent some kind of encoding to ensure neither of the 8 bits in each U16 happens to be a string terminal. Or other loaded character >.<

Anyway thanks for that info. I'll check relatives, else use TCPObject.
#3
01/27/2014 (2:58 am)
This is clearly designed for carrying strings. Surely there must be a way already implemented. It's a pain having to cut out bytes.

I was just going to send the normal characters. Then anouther listing points where special characters were cut out.
#4
01/27/2014 (3:46 am)
I just finished a project for LegionsOverdrive using TCPobject another way and this interests me for something in the future so I took a stab at it quickly.

This will give you 2 way communication between 2 local servers(or online really ).. you kinda invent your own protocol between the 2 Sender Objects send() functions and the 2 Receiver Objects onLine() functions and hook into your scripts that way. If you dont need it instant and use a quick loading screen I guess this can help.. you could pass their IP and when the second server gets the client it builds their player/loadout the way you want.

The port stuff is hardcoded , you could come up with something better with server querys about current port used if you need to do this all the time... i think.

//exec("mods/interTCPcommsTest.cs");

$pref::Net::BindAddress = "127.0.0.1";

$worldZoneListenPort = 50000;
$battleZoneListenPort = 50001;

//instructions::
//-run createWorldZoneTCPSender() on one server
//-run createBattleZonecommsListener() on the other server
//-worldZoneTCPSender.connect("127.0.0.1:"@$battleZoneListenPort) on the first server.
//-watch the echos for some test automation/example protocol

function createWorldZoneTCPSender()
{
    %obj = new TCPObject(worldZoneTCPSender);
}

function createBattleZonecommsListener()
{
    %obj = new TCPObject(battleZonecommsListener);   
    %obj.listen($battleZoneListenPort);
}

//tell world one to connect to the battle one
function worldZoneTCPSender::connectToSomewhere(%this, %addy)
{
	testConnection.connect(%addy);
}

//when battle gets the request , create its permenant receiver

function BattleZonecommsListener::onConnectRequest(%this,%address,%id)
{
	%obj = new TCPObject( battleZonecommsReceiver, %id)  
	{
	};
}

//when the first connects to the second , tell them the port and to connect back and create a new object to receive from it

function worldZoneTCPSender::onConnected (%this)
{
	echo("I connected to the server");

	%obj = new TCPObject(worldZonecommsListener);
	%obj.listen($worldZoneListenPort);

	worldZoneTCPSender.send("connect" SPC $worldZoneListenPort @ "n");
}

//when the firsts listener gets its request from the second , create its permenant receiver
function worldZonecommsListener::onConnectRequest(%this,%address,%id)
{
	%obj = new TCPObject( worldZonecommsReceiver, %id)  
	{
	};
}

function battleZoneTCPSender::onConnected(%this)
{
	battleZoneTCPSender.schedule(100,send,"go aheadn");
}


//when they receives messages , do stuff.. in this test case create another TCP object connect back. You have 2 way communication now.
//This is where you set up your own little protcol and hook into the rest of your scripts.

function battleZonecommsReceiver::onLine(%this, %line)
{
	echo(%line);

	if(getWord(%line,0) $= "connect")
	{

		%obj = new TCPObject(battleZoneTCPSender);

		battleZoneTCPSender.connect("127.0.0.1:"@getWord(%line,1));

	}

	//etc

	//etc

	//etc

}

function worldZonecommsReceiver::onLine(%this, %line)
{
	echo(%line);

	if(%line $= "go ahead")
	{
        echo("im sending some player data");
        testSendPlayerDataToBuild("PlayerId485485", "fireballLvl8","modelMage");
	}

	//etc

	//etc

	//etc

}


function testSendPlayerDataToBuild(%data1, %data2, %data3)
{
	worldZoneTCPSender.send(%data1 @ "n");
	worldZoneTCPSender.send(%data2 @ "n");
	worldZoneTCPSender.send(%data3 @ "n");
}
#5
01/27/2014 (3:49 am)
For some unknown reason it stripped out all the "\" from the \ n on the send lines , gotta add those back in.
#6
01/27/2014 (4:11 am)

Thanks for help.
I'd like to point out that you are sending all your data as strings here however. While it would work for my case, it's not reaaally very efficiant :/, or I'm just being picky.

For example this
testSendPlayerDataToBuild(2, 234293, 2);

The first data is 2bytes as it is one (UTF8?)char which is one byte, but +1 for \n.

However the second, in c++ could be represented as U16 or two bytes.
But as a string it is 6 bytes (+1 for \n).

So it's fine for strings, but not for other datatypes. Because if one of the bytes is 0x00, it is the same as the "end string" character.
#7
01/27/2014 (4:13 am)
This means my 100 different U16 stats for my characters would be 700 bytes instead of 200. Over 3 times the size....
#8
01/27/2014 (4:16 am)
Yeah I don't know C++ , I bet you can be way more efficient in there. You make it sound like its not going to happen every few seconds or anything though.. it might not be so bad.

edit:: or that below : )
#9
01/27/2014 (4:16 am)
As a sidenote. I think it's weird calling it transport control object when it has this limitation.

What I'm going to do however is make a child class and replace this function which should quickly erase the string character stuff.
U32 TCPObject::onReceive(U8 *buffer, U32 bufferLen)
{
   // we got a raw buffer event
   // default action is to split the buffer into lines of text
   // and call processLine on each
   // for any incomplete lines we have mBuffer
   U32 start = 0;
   parseLine(buffer, &start, bufferLen);
   return start;
}
#10
01/27/2014 (6:31 am)
<edit>
Wow - did not even read that last post - actually just suggested that you do what you just said you were going to do.

Yet another option is to use a common database to store your game data then access the database server from all instances of Torque.