A while ago I found a script to save the bricks from the console of a dedicated server, I liked it because this wouldn't mean I would lose bricks if I didn't see an area where was built in.
Now since I got this script I have already solved 2 bugs, one of them was events not being saved properly, events with an output text would get messed up and leave some numbers in place. Another had to do with ownership not being stored properly, so I made a second loop just to store ownership as I compared the savegame that was outputted by the script with the one I saved with my client.
Although the major ownership problems are now gone, I still sometimes have problems with ownership being messed up after loading a saved game.
Half of the built house would belong to the owner of the street and the other half would belong to the owner of the house. While the house is on a single baseplate.
Another problem is that event output is still not being solved properly. Although output texts don't change anymore, stuff like spawnexplosion->vehicle explosion will end up in spawnexplosion -> none after load.
And a third thing, which I'm not sure is really a saving issue are brick properties like collision, rendering and raycasting although there only are problems with these on JVS doors.
Could someone please review this script as I am not sure if it uses the right properties from the bricks.
And second, is there somewhere I can findout what properties an object has?
The brick saving script:
function dediSave(%name, %desc, %events, %ownership)
{
%path = "saves/" @ MissionInfo.saveName @ "/" @ %name @ ".bls";
if(!isWriteableFileName(%path))
{
error("Cannot save to file: ", %path);
return;
}
%file = new FileObject();
%file.openForWrite(%path);
%file.writeLine("This is a Blockland save file. You probably shouldn't modify it cause you'll screw it up.");
%file.writeLine("1"); // What does this mean?
%file.writeLine(%desc);
for(%i=0;%i<64;%i++)
%file.writeLine(getColorIDTable(%i));
%bricks = 0;
for(%i=0;%i<mainBrickGroup.getCount();%i++)
%bricks += mainBrickGroup.getObject(%i).getCount();
%file.writeLine("Linecount " @ %bricks);
for(%i=0;%i<mainBrickGroup.getCount();%i++)
{
%group = mainBrickGroup.getObject(%i);
for(%a=0;%a<%group.getCount();%a++)
{
%brick = %group.getObject(%a);
if (%ownership && %brick.isBasePlate() && !$Server::LAN)
{
%print = (%brick.getDataBlock().subCategory $= "Prints") ? getPrintTexture(%brick.getPrintID()) : ""; // Possibly better way to check?
%file.writeLine(%brick.getDataBlock().uiName @ "\" " @ %brick.getPosition() SPC %brick.getAngleID() SPC %brick.isBasePlate() SPC %brick.getColorID() SPC %print SPC %brick.getColorFXID() SPC %brick.getShapeFXID() SPC %brick.isRayCasting() SPC %brick.isColliding() SPC %brick.isRendering());
if(%events)
{
if(%brick.getName() !$= "")
%file.writeLine("+-NTOBJECTNAME " @ %brick.getName());
if(%brick.numEvents > 0)
{
for(%b=0;%b<%brick.numEvents;%b++)
{
%params = "";
%targetClass = %brick.eventTargetIdx[%b] >= 0 ? getWord(getField($InputEvent_TargetListfxDTSBrick_[%brick.eventInputIdx[%b]], %brick.eventTargetIdx[%b]), 1) : "fxDtsBrick";
%paramList = $OutputEvent_parameterList[%targetClass, %brick.eventOutputIdx[%b]];
for(%c=0;%c<4;%c++)
{
if(firstWord(getField(%paramList, %c)) $= "dataBlock")
%params = %params TAB %brick.eventOutputParameter[%b, %c + 1].uiName;
else
%params = %params TAB %brick.eventOutputParameter[%b, %c + 1];
}
%file.writeLine("+-EVENT" TAB %b TAB %brick.eventEnabled[%b] TAB %brick.eventInput[%b] TAB %brick.eventDelay[%b] TAB %brick.eventTarget[%b] TAB %brick.eventNT[%b] TAB %brick.eventOutput[%b] @ %params);
}
}
}
if(isObject(%brick.emitter))
%file.writeLine("+-EMITTER " @ %brick.emitter.emitter.uiName @ "\" " @ %brick.emitterDirection);
if(%brick.getLightID() >= 0)
%file.writeLine("+-LIGHT " @ %brick.getLightID().getDataBlock().uiName @ "\" "); // Not sure if something else comes after the name
if(isObject(%brick.item))
%file.writeLine("+-ITEM " @ %brick.item.getDataBlock().uiName @ "\" " @ %brick.itemPosition SPC %brick.itemDirection SPC %brick.itemRespawnTime);
if(isObject(%brick.audioEmitter))
%file.writeLine("+-AUDIOEMITTER " @ %brick.audioEmitter.getProfileID().uiName @ "\" "); // Not sure if something else comes after the name
if(isObject(%brick.vehicleSpawnMarker))
%file.writeLine("+-VEHICLE " @ %brick.vehicleSpawnMarker.uiName @ "\" " @ %brick.reColorVehicle);
%file.writeLine("+-OWNER " @ getBrickGroupFromObject(%brick).bl_id);
}
}
}
for(%i=0;%i<mainBrickGroup.getCount();%i++)
{
%group = mainBrickGroup.getObject(%i);
for(%a=0;%a<%group.getCount();%a++)
{
%brick = %group.getObject(%a);
if (%ownership && %brick.isBasePlate() && !$Server::LAN)
{
continue;
}
%print = (%brick.getDataBlock().subCategory $= "Prints") ? getPrintTexture(%brick.getPrintID()) : ""; // Possibly better way to check?
%file.writeLine(%brick.getDataBlock().uiName @ "\" " @ %brick.getPosition() SPC %brick.getAngleID() SPC %brick.isBasePlate() SPC %brick.getColorID() SPC %print SPC %brick.getColorFXID() SPC %brick.getShapeFXID() SPC %brick.isRayCasting() SPC %brick.isColliding() SPC %brick.isRendering());
if(%events)
{
if(%brick.getName() !$= "")
%file.writeLine("+-NTOBJECTNAME " @ %brick.getName());
if(%brick.numEvents > 0)
{
for(%b=0;%b<%brick.numEvents;%b++)
{
%params = "";
%targetClass = %brick.eventTargetIdx[%b] >= 0 ? getWord(getField($InputEvent_TargetListfxDTSBrick_[%brick.eventInputIdx[%b]], %brick.eventTargetIdx[%b]), 1) : "fxDtsBrick";
%paramList = $OutputEvent_parameterList[%targetClass, %brick.eventOutputIdx[%b]];
for(%c=0;%c<4;%c++)
{
if(firstWord(getField(%paramList, %c)) $= "dataBlock")
%params = %params TAB %brick.eventOutputParameter[%b, %c + 1].uiName;
else
%params = %params TAB %brick.eventOutputParameter[%b, %c + 1];
}
%file.writeLine("+-EVENT" TAB %b TAB %brick.eventEnabled[%b] TAB %brick.eventInput[%b] TAB %brick.eventDelay[%b] TAB %brick.eventTarget[%b] TAB %brick.eventNT[%b] TAB %brick.eventOutput[%b] @ %params);
}
}
}
if(isObject(%brick.emitter))
%file.writeLine("+-EMITTER " @ %brick.emitter.emitter.uiName @ "\" " @ %brick.emitterDirection);
if(%brick.getLightID() >= 0)
%file.writeLine("+-LIGHT " @ %brick.getLightID().getDataBlock().uiName @ "\" "); // Not sure if something else comes after the name
if(isObject(%brick.item))
%file.writeLine("+-ITEM " @ %brick.item.getDataBlock().uiName @ "\" " @ %brick.itemPosition SPC %brick.itemDirection SPC %brick.itemRespawnTime);
if(isObject(%brick.audioEmitter))
%file.writeLine("+-AUDIOEMITTER " @ %brick.audioEmitter.getProfileID().uiName @ "\" "); // Not sure if something else comes after the name
if(isObject(%brick.vehicleSpawnMarker))
%file.writeLine("+-VEHICLE " @ %brick.vehicleSpawnMarker.uiName @ "\" " @ %brick.reColorVehicle);
}
}
%file.close();
%file.delete();
echo("Saved: " @ %path);
}
<edit> I like to add, that saving with the client does solve the owner problem. But the client won't save everything that has been built. Everything outside of its viewed range will not have been saved.
<edit2> I have found the next by comparing a client savegame to the dedicated save game.
Client:
+-EVENT 0 1 onPlayerTouch 0 -1 _Ultra_Turrent spawnProjectile 200 0 0 -1 0 0 0 2
dediSave: Note that the -1 in the output parameters are gone.
+-EVENT 0 1 onPlayerTouch 0 -1 _Ultra_Turrent spawnProjectile 200 0 0 0 0 0 2
This code seems to generate those parameters:
%params = "";
%targetClass = %brick.eventTargetIdx[%b] >= 0 ? getWord(getField($InputEvent_TargetListfxDTSBrick_[%brick.eventInputIdx[%b]], %brick.eventTargetIdx[%b]), 1) : "fxDtsBrick";
%paramList = $OutputEvent_parameterList[%targetClass, %brick.eventOutputIdx[%b]];
for(%c=0;%c<4;%c++)
{
if(firstWord(getField(%paramList, %c)) $= "dataBlock")
%params = %params TAB %brick.eventOutputParameter[%b, %c + 1].uiName;
else
%params = %params TAB %brick.eventOutputParameter[%b, %c + 1];
}