Save/Load game system
by Skylar Kelty · 11/13/2006 (4:36 pm) · 11 comments
This is due to be re-done so that it isnt a checkpoint system and uses player.gettransforms to save the player position.
This version works, but only just.
It saves:
-> Mission name
-> Player Name
-> Checkpoint
It needs my UAC resource, if you don't want that im sure you can pull it out
It can be expanded by those who are experienced scriptors, I will also expand it later.
Script, client-side, lets say client/scripts/sgsys.cs (remember to exec):
Checkpoint stuff, also client side, lets say client/scripts/cp.cs (remember; exec!):
triggers, server-side, triggers.cs:
server-side game.cs changes:
add to the end of the file:
Change function GameConnection::spawnPlayer(%this) to this:
Gui, client-side, say client/ui/sgsys.gui (exec!):
getxmldata, client side, anywhere really say client/scripts/anywhere.cs (exec?):
Engine stuff:
game/sgsys.cpp:
sgsys.h:
game/cp.cpp:
game/cp.h:
recompile!
You need a checkpoints simgroup in the mission, with checkpoints as spawnspheres and separate checkpoint triggers like this:
This version works, but only just.
It saves:
-> Mission name
-> Player Name
-> Checkpoint
It needs my UAC resource, if you don't want that im sure you can pull it out
It can be expanded by those who are experienced scriptors, I will also expand it later.
Script, client-side, lets say client/scripts/sgsys.cs (remember to exec):
function SGSYS::save(%this)
{
if(!checkloggedin()){
canvas.popdialog(savedlg);
return;
}
%name = $savegamename;
%username = $loggedinusername;
%missionname = $currentmissionname;
%playername = $pref::Player::Name;
%checkpoint = cp.getcurrent();
%file = new FileObject();
%file.openforwrite("~/data/users/" @ %username @ "/savedgames/" @ %name @ ".xml");
%file.writeLine("Savedgame data for " @ %username);
%file.writeLine("");
%file.writeLine("<name>");
%file.writeLine(%name);
%file.writeLine("</name>");
%file.writeLine("");
%file.writeLine("<missionname>");
%file.writeLine(%missionname);
%file.writeLine("</missionname>");
%file.writeLine("");
%file.writeLine("<playername>");
%file.writeLine(%playername);
%file.writeLine("</playername>");
%file.writeLine("");
%file.writeLine("<checkpoint>");
%file.writeLine(%checkpoint);
%file.writeLine("</checkpoint>");
%file.close();
%file.delete();
$savegamename = "";
Canvas.popdialog(savedlg);
}
function SGSYS::load(%this)
{
if(!checkloggedin()){
canvas.popdialog(savedlg);
return;
}
%name = $loadgamename;
%username = $loggedinusername;
%file = new FileObject();
%file.openforRead("~/data/users/" @ %username @ "/savedgames/" @ %name @ ".xml");
while( !%file.isEOF() )
{
%line = %file.readline();
%sgsysresults = %sgsysresults @ %line;
}
%file.close();
%file.delete();
%missionname = getxmldata(%sgsysresults, "missionname", 0);
%playername = getxmldata(%sgsysresults, "playername", 0);
%checkpoint = getxmldata(%sgsysresults, "checkpoint", 0);
Canvas.popdialog(loaddlg);
%this.startsavedgame(%name, %missionname, %playername, %checkpoint);
$loadgamename = "";
}
function SGSYS::startsavedgame(%this, %name, %missionname, %playername, %checkpoint)
{
if($Game::Running == true)
disconnect();
$checkpointtoload = %checkpoint;
Canvas.setContent(LoadingGui);
LOAD_MapName.setText( "Loading SavedGame" );
LOAD_MapDescription.setText( "<font:Arial:16>Please wait while " @ %name @ " is loaded");
Canvas.repaint();
createServer("SinglePlayer", %missionname);
%conn = new GameConnection(ServerConnection);
RootGroup.add(ServerConnection);
%conn.setConnectArgs(%playername);
%conn.setJoinPassword($Client::Password);
%conn.connectLocal();
}Checkpoint stuff, also client side, lets say client/scripts/cp.cs (remember; exec!):
function cp::getcurrent(%this)
{
return $lastcheckpoint;
}
function cp::setcurrent(%this, %name)
{
$lastcheckpoint = %name;
}triggers, server-side, triggers.cs:
datablock TriggerData(CheckpointTrigger)
{
tickPeriodMS = 100;
};
function CheckpointTrigger::onEnterTrigger(%this,%trigger,%obj)
{
//%this.getName
%name = %trigger.getname();
// Bad, should be a commandtoclient
cp.setcurrent(%name);
Parent::onEnterTrigger(%this,%trigger,%obj);
}
function CheckpointTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
Parent::onLeaveTrigger(%this,%trigger,%obj);
}
function CheckpointTrigger::onTickTrigger(%this,%trigger)
{
Parent::onTickTrigger(%this,%trigger);
}server-side game.cs changes:
add to the end of the file:
function getCheckPoint()
{
// No if's beacuse we assume everything is okay,
// it saved okay so it must still be fine
%checkpoint = $checkpointtoload - 1;
%groupName = "MissionGroup/CheckPoints";
%group = nameToID(%groupName);
%index = %checkpoint;
%spawn = %group.getObject(%index);
return %spawn.getTransform();
}Change function GameConnection::spawnPlayer(%this) to this:
function GameConnection::spawnPlayer(%this)
{
// Combination create player and drop him somewhere
if($issavedgame == "1"){
%spawnPoint = getCheckPoint();
} else {
%spawnPoint = pickSpawnPoint();
}
%this.createPlayer(%spawnPoint);
}Gui, client-side, say client/ui/sgsys.gui (exec!):
//--- OBJECT WRITE BEGIN ---
new GuiControl(savedlg) {
Profile = "GuiDefaultProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "0 0";
Extent = "640 480";
MinExtent = "8 8";
Visible = "1";
helpTag = "0";
new GuiWindowCtrl() {
Profile = "GuiWindowProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "178 104";
Extent = "343 238";
MinExtent = "8 2";
Visible = "1";
text = "Save Game";
maxLength = "255";
resizeWidth = "1";
resizeHeight = "1";
canMove = "1";
canClose = "1";
canMinimize = "1";
canMaximize = "1";
minSize = "50 50";
new GuiMLTextCtrl() {
Profile = "GuiMLTextProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "149 63";
Extent = "64 14";
MinExtent = "8 2";
Visible = "1";
lineSpacing = "2";
allowColorChars = "0";
maxChars = "-1";
text = "Name:";
};
new GuiTextEditCtrl() {
Profile = "GuiTextEditProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "113 83";
Extent = "119 18";
MinExtent = "8 2";
Visible = "1";
Variable = "$savegamename";
maxLength = "255";
historySize = "0";
password = "0";
tabComplete = "0";
sinkAllKeyEvents = "0";
password = "0";
passwordMask = "*";
};
new GuiButtonCtrl() {
Profile = "GuiButtonProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "103 154";
Extent = "140 30";
MinExtent = "8 2";
Visible = "1";
text = "Save";
groupNum = "-1";
buttonType = "PushButton";
command = "SGSYS.save();";
};
};
};
new GuiControl(loaddlg) {
Profile = "GuiDefaultProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "0 0";
Extent = "640 480";
MinExtent = "8 8";
Visible = "1";
helpTag = "0";
new GuiWindowCtrl() {
Profile = "GuiWindowProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "178 104";
Extent = "343 238";
MinExtent = "8 2";
Visible = "1";
text = "Load Game";
maxLength = "255";
resizeWidth = "1";
resizeHeight = "1";
canMove = "1";
canClose = "1";
canMinimize = "1";
canMaximize = "1";
minSize = "50 50";
new GuiMLTextCtrl() {
Profile = "GuiMLTextProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "149 63";
Extent = "64 14";
MinExtent = "8 2";
Visible = "1";
lineSpacing = "2";
allowColorChars = "0";
maxChars = "-1";
text = "Name:";
};
new GuiTextEditCtrl() {
Profile = "GuiTextEditProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "113 83";
Extent = "119 18";
MinExtent = "8 2";
Visible = "1";
Variable = "$loadgamename";
maxLength = "255";
historySize = "0";
password = "0";
tabComplete = "0";
sinkAllKeyEvents = "0";
password = "0";
passwordMask = "*";
};
new GuiButtonCtrl() {
Profile = "GuiButtonProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "103 154";
Extent = "140 30";
MinExtent = "8 2";
Visible = "1";
text = "Save";
groupNum = "-1";
buttonType = "PushButton";
command = "SGSYS.load();";
};
};
};
//--- OBJECT WRITE END ---getxmldata, client side, anywhere really say client/scripts/anywhere.cs (exec?):
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;
}Engine stuff:
game/sgsys.cpp:
// Includes
#include "game/sgsys.h"
#include "console/console.h"
F32 SGSYS::currentversion = 1.1;
IMPLEMENT_CO_DATABLOCK_V1(SGSYS);
IMPLEMENT_CONSOLETYPE(SGSYS)
IMPLEMENT_GETDATATYPE(SGSYS)
IMPLEMENT_SETDATATYPE(SGSYS)
SGSYS::SGSYS()
{
}
void SGSYS::consoleInit()
{
Con::addVariable("$pref::SGSYS::currentversion", TypeF32, ¤tversion);
}sgsys.h:
#include "game/gameBase.h"
class SGSYS : public GameBaseData
{
typedef GameBaseData Parent;
public:
SGSYS();
DECLARE_CONOBJECT(SGSYS);
static void consoleInit();
static F32 currentversion;
};
DECLARE_CONSOLETYPE(SGSYS)game/cp.cpp:
// Includes
#include "game/cp.h"
#include "console/console.h"
IMPLEMENT_CO_DATABLOCK_V1(cp);
IMPLEMENT_CONSOLETYPE(cp)
IMPLEMENT_GETDATATYPE(cp)
IMPLEMENT_SETDATATYPE(cp)
cp::cp()
{
}game/cp.h:
#include "game/gameBase.h"
class cp : public GameBaseData
{
typedef GameBaseData Parent;
public:
cp();
DECLARE_CONOBJECT(cp);
};
DECLARE_CONSOLETYPE(cp)recompile!
You need a checkpoints simgroup in the mission, with checkpoints as spawnspheres and separate checkpoint triggers like this:
new SimGroup(CheckPoints) {
new SpawnSphere(1) {
Position = "34.1473 -152.619 108.67";
rotation = "0 0 1 130.062";
scale = "0.940827 1.97505 1";
dataBlock = "SpawnSphereMarker";
Radius = "10";
sphereWeight = "1";
indoorWeight = "1";
outdoorWeight = "1";
locked = "False";
homingCount = "0";
lockCount = "0";
};
new SpawnSphere(2) {
Position = "42.7715 -225.175 165.694";
rotation = "0 0 1 130.062";
scale = "0.940827 1.97505 1";
dataBlock = "SpawnSphereMarker";
Radius = "10";
sphereWeight = "1";
indoorWeight = "1";
outdoorWeight = "1";
locked = "False";
homingCount = "0";
lockCount = "0";
};
};
new Trigger(1) {
Position = "23.0141 -134.828 102.986";
rotation = "1 0 0 0";
scale = "1 1 1";
dataBlock = "CheckpointTrigger";
polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
};
new Trigger(2) {
Position = "23.0141 -134.828 102.986";
rotation = "1 0 0 0";
scale = "1 1 1";
dataBlock = "CheckpointTrigger";
polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000";
};About the author
Recent Blogs
• AFXSpellCooldowns• TGEA material.cs Generator
• User Account System
• Check for update
• DOM, SG and future resources
#2
Just got the UAC and Save\Load in but I have console error:
Compiling starter.fps/client/scripts/anywhere.cs...
starter.fps/client/scripts/anywhere.cs Line: 14 - Syntax error.
This is line 14:
Still working on it, could be something I've done wrong somewhere else. I'll post if I find my mistake elsewhere.
Edited because what I'd written didn't make sense. Not sure if this helps...
11/30/2006 (5:55 pm)
Hi James,Just got the UAC and Save\Load in but I have console error:
Compiling starter.fps/client/scripts/anywhere.cs...
starter.fps/client/scripts/anywhere.cs Line: 14 - Syntax error.
This is line 14:
%result = strreplace(%result, """, "\"");
Still working on it, could be something I've done wrong somewhere else. I'll post if I find my mistake elsewhere.
Edited because what I'd written didn't make sense. Not sure if this helps...
#4
05/23/2007 (12:32 am)
Updated One bug fix
#5
So I was wondering if anyone has adapted this to the RTS Kit at all. If anyone can PM me what they did or provide some instruction on the RTS Resource forum I would appreciate it.
Thanks
Nicholas
07/29/2007 (10:17 am)
Heyas,So I was wondering if anyone has adapted this to the RTS Kit at all. If anyone can PM me what they did or provide some instruction on the RTS Resource forum I would appreciate it.
Thanks
Nicholas
#6
01/12/2008 (10:30 pm)
Cool! :-)
#7
07/27/2008 (11:13 am)
Hey has this been updated yet with the player.gettransform ?
#9
08/09/2008 (4:30 pm)
cool
#10
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11552
01/05/2009 (10:20 am)
has anyone converted this to SQlite or integrated this with the UAC tutorial? www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11552
#11
03/02/2009 (11:34 pm)
Cool!..I can I can use this with my special project at school..tnx 4 this wonderful stuff. 
Torque 3D Owner Thanhda Tie
Digital Shock Inc.