Game Development Community

dev|Pro Game Development Curriculum

Simple online saving system (T3D)

by Bob Mann · 02/02/2011 (8:35 pm) · 6 comments

[This is my first resource.]
This is a simple system I was using for player data storage. Works upon clients connecting and checking clients info.
First we need to mod the server functions. Open game>core>scripts>server>clientConnections.cs and find the following:
function GameConnection::onConnectRequest( %client, %netAddress, %name )
{
   echo("Connect request from: " @ %netAddress);
   if($Server::PlayerCount >= $pref::Server::MaxPlayers)
      return "CR_SERVERFULL";

}

// REPLACE IT WITH THIS
function GameConnection::onConnectRequest(%client, %netAddress, %urname, %pass, %arg)
{
   echo("Connect request from: " @ %netAddress);
   if($Server::PlayerCount >= $pref::Server::MaxPlayers)
      return "CR_SERVERFULL";


   switch$(%arg)
	{
		case "0":
			%client.newacc(%urname, %pass);
		case "1":
			%client.login(%urname, %pass);
		default:
			%client.schedule(0, "delete", "Bad arg");
	}
		
}

Now make a new file or drop this some where. Make sure to change the file locations if needed!

//-----------------------------------------------------------------------------
// 	1. Optional for user IDs
//-----------------------------------------------------------------------------
$save::playercount = 0;

function getplayercount()
{
	$save::playercount = getFileCount( "/players/*.xml", false );
}

getplayercount();

echo("SAVE : GETTING PLAYER COUNT");

//-----------------------------------------------------------------------------
// 	XML Reading function thanks to James Thompson
//-----------------------------------------------------------------------------

function getxmldata(%string, %tag, %startChar)
{
	%startTag = "<" @ %tag @ ">";
	%endTag   = "</" @ %tag @ ">";
	%startTagOffset = strpos(%string, %startTag, %startChar);
	%startOffset = %startTagOffset + strlen(%startTag);
	%endTagOffset = strpos(%string, %endTag, %startOffset - 1);

	if(%endTagOffset < 0)
    		return "";

	%this.lastOffset = %endTagOffset;
	%result = getSubStr(%string, %startOffset, %endTagOffset - %startOffset);
	%result = strreplace(%result, "\"", "\"");
	%result = strreplace(%result, "&",  "&");
	return %result;
}

//-----------------------------------------------------------------------------
// 	2. New Accounts
//-----------------------------------------------------------------------------

function GameConnection::newacc(%client, %urname, %pass)
{
	if(getSubStr(%urname, 0, 1) $= "")
	{
		%client.schedule(0, "delete", "Login error: No username givin!");
		return;
	}
	
	if(getSubStr(%pass, 0, 1) $= "")
	{
		%client.schedule(0, "delete", "Login error: No password given");
		return;
	}
	
	if(isFile("/players/" @ %urname @ ".xml"))
	{
		%client.schedule(0, "delete", "Account error: Player exist");
		return;
	}


	%id = mFloor($save::playercount += 1);
	
	$save::playercount += 1;
		
	echo("New account call : USERNAME " @ %urname @ " :: PASS " @ %pass @ " :: END");
	
	%file = new FileObject();
	%file.openforWrite("/players/" @ %urname @ ".xml");
	
	//Start saveing vars

	%file.writeLine("<id>");
	%file.writeLine(%id);
	%file.writeLine("</id>");
	%file.writeLine("<username>");
	%file.writeLine(%urname);
	%file.writeLine("</username>");
	%file.writeLine("<password>");
	%file.writeLine(%pass);
	%file.writeLine("</password>");
	%file.writeLine("//end list");
		
	%file.close();
	%file.delete();
}

//-----------------------------------------------------------------------------
// 	3. Login
//-----------------------------------------------------------------------------

function GameConnection::login(%client, %urname, %pass)
{
	if(getSubStr(%urname, 0, 1) $= "")
	{
		%client.schedule(0, "delete", "Login error: No username givin!");
		return;
	}
	
	if(getSubStr(%pass, 0, 1) $= "")
	{
		%client.schedule(0, "delete", "Login error: No password given");
		return;
	}

	if(!isFile("/players/" @ %urname @ ".xml"))
	{
		%client.schedule(0, "delete", "Login error: Player dose not exist!");
		return;
	}

	%file = new FileObject();
	%file.openforRead("/players/" @ %urname @ ".xml");

	while(!%file.isEOF()) 
	{  
		%line = %file.readline();  
		%xml = %xml @ %line;  
	}
		
	%id = getxmldata(%xml, "id", 0);
	%username = getxmldata(%xml, "username", 0);
	%password = getxmldata(%xml, "password", 0);

	echo("Login attempt : Username: " @ username @ " :: Password " @ %password @ " :: Checking password!");
	
	if(%pass $= %password)
	{
		%client.id = %id;
		%client.urname = %username;
	}
	else
	{
		%client.schedule(0, "delete", "Login error: Password dose not match for " @ %urname @ "!");
		echo("LOGIN ATTEMPT FAILED!");
	}
	
	%file.close();
	%file.delete();
}

Now we need to make a few client side edits. I do encourage creativeness so make a GUI with the account info (two text edit controls and a checkbox). If you still need one heres one free of charge!

Now open up game>art>gui>joinServerDlg.gui and find this:
function JoinServerDlg::join(%this)
{
   cancelServerQuery();
   %index = JS_serverList.getSelectedId();

   // The server info index is stored in the row along with the
   // rest of displayed info.

   if( setServerInfo( %index ) )
   {
      %conn = new GameConnection(ServerConnection);
      %conn.setConnectArgs($pref::Player::Name);
      %conn.setJoinPassword($Client::Password);
      %conn.connect($ServerInfo::Address);
   }
}

//REPLACE WITH

function JoinServerDlg::join(%this)
{
   cancelServerQuery();
   %index = JS_serverList.getSelectedId();

   // The server info index is stored in the row along with the
   // rest of displayed info.

   if( setServerInfo( %index ) )
   {
      %urname = $urname;
      %pass = $pass;
      %arg = $arg;
      %conn = new GameConnection(ServerConnection);
      %conn.setConnectArgs(%urname, %pass, %arg);
      %conn.setJoinPassword($Client::Password);
      %conn.connect($ServerInfo::Address);
   }
}

Make sure all files you added are exec[ed] and you should have a simple working saving system. I recommend this on a dedicated server for testing.

About the author

Recent Blogs


#1
02/03/2011 (12:24 am)
In function 'function GameConnection::onConnectRequest', lines 17 to 25 can't be reached or executed because of the return line 15.

Nicolas Buquet
www.buquet-net.com/cv/
#2
02/03/2011 (6:41 am)
Looking at it I guess he forgot to move that to the end of the file....

Other than that though, looks good - I'll have to give it a shot.
#3
02/03/2011 (9:57 am)
Unsure what this does, looking at the code. Is this to save your game on a server (don't think so, but would like it), or is this a player login system?
#4
02/03/2011 (2:24 pm)
@David Janssens

Player login.
#5
02/04/2011 (8:22 am)
@Nicolas - @Richard: Actually the logic is correct. It will hit that return only nn the event the server is full or above capacity.

if($Server::PlayerCount >= $pref::Server::MaxPlayers)  
      return "CR_SERVERFULL";
#6
02/07/2011 (11:12 am)
Yeah, the logic is fine; might want to put brackets around it to make it absolutely clear, however.