Author Topic: Saving data if crash?  (Read 1453 times)

So guys
You know I'm working on creating a new city rpg

I came up with this for database
But it won't save if the server crashes

How do I make it save all the KeyData when the server crashes?

Code: [Select]
//+--------------------------------------+
//| #title: Molodion                              |
//| #purpose: saves data and variables   |
//| #author: Mold                        |
//+--------------------------------------+

function Molodion::onAdd(%this)
{
    if(%this.name = "")
        %this.name = %this.getName();
    if(%this.savepath $= "")
    {
        echo(%this.name @ " needs a savepath.");
        %this.schedule(0,delete);
        return;
    }
    
    %this.keycount = 0;
    %this.valuecount = 0;
    //%this. = 0;

    if(%this.autoloadkeys && isFile(%this.savepath @ "keyregister.cs"))
    {
        %file = new FileObject();
        %file.openForRead(%this.savepath @ "keyregister.cs");
        while(!%file.isEOF())
        {
            %line = %file.readline();
            %this.loadKeyData(%line);
        }
    }
}

function Molodion::registerValue(%this, %valname, %standard)
{
    if(%valname $= "")
        return;
    if(%standard $= "")
        return;
    if(%this.registeredValue[%valname])
        return;
    
    %this.valueName[%this.valuecount] = %valname;
    %this.value[%this.valuecount] = %standard;
    %this.valuecount++;
    %this.registeredValue[%valname] = 1;
}

function Molodion::loadKeyData(%this, %keyID)
{
    if(isObject(%this.KeyData[%keyID]))
        return;
        
    if(isFile(%this.savepath @ "key_" @ %keyID @ ".dat"))
    {
        %this.KeyData[%keyID] = new scriptObject(){class = "Molodata";};
        %file = new fileObject();
        %file.openForRead(%this.savepath @ "key_" @ %keyID @ ".dat");
        while(!%file.isEOF())
        {
            %line = %file.readline();
            %ValueName = getWord(%line, 0);
            %Value = removeWord(%line, 0);
            %this.KeyData[%keyID].Value[%ValueName] = %Value;
        }
        for(%i=0;%i<%this.valuecount;%i++)
        {
            if(%this.KeyData[%keyID].Value[%this.Valuename[%i]] $= "")
                %this.KeyData[%keyID].Value[%this.Valuename[%i]] = %this.Value[%i];
        }
        echo("key " @ %keyID @ " loaded.");    
    }
}

function Molodion::createKeyData(%this, %keyID)
{
    if(isObject(%this.KeyData[%keyID]))
        return;
    if(isFile(%this.savepath @ "key_" @ %keyID @ ".dat"))
    {
        %this.loadKeyData(%keyID);
        return;
    }
    
    %this.KeyData[%keyID] = new scriptObject(){class = "Molodata";};
    for(%i=0;%i<%this.valuecount;%i++)
    {
        %this.KeyData[%keyID].Value[%this.Valuename[%i]] = %this.Value[%i];
    }
    echo("key " @ %keyID @ " created.");
    %this.saveKeyData(%keyID);
    
    %this.registeredKeysCount = 0;
    if(isFile(%this.savepath @ "keyregister.cs"))
    {
        %file = new fileObject();
        %file.openForRead(%this.savepath @ "keyregister.cs");
        while(!%file.isEOF())
        {
            %registeredKey[%this.registeredKeysCount] = %file.readLine();
            %this.registeredKeysCount++;
        }
        %file.close();
        %file.delete();
        fileDelete(%this.savepath @ "keyregister.cs");
    }
    %registeredKey[%this.registeredKeysCount] = %keyID;
    %this.registeredKeysCount++;
    
    %file = new fileObject();
    %file.openForWrite(%this.savepath @ "keyregister.cs");
    for(%i=0;%i<%this.registeredKeysCount;%i++)
    {
        %file.writeLine(%registeredKey[%i]);
    }
    %file.close();
    %file.delete();
}

function Molodion::saveKeyData(%this, %keyID)
{
    if(!isObject(%this.KeyData[%keyID]))
        return;
        
    if(isFile(%this.savepath @ "key_" @ %keyID @ ".dat"))
        fileDelete(%this.savepath @ "key_" @ %keyID @ ".dat");
        
    %file = new fileObject();
    %file.openForWrite(%this.savepath @ "key_" @ %keyID @ ".dat");
    for(%i=0;%i<%this.valuecount;%i++)
    {
        %line = %this.ValueName[%i];
        %line = %line SPC %this.KeyData[%keyID].Value[%this.ValueName[%i]];
        %file.writeLine(%line);
    }
    %file.close();
    %file.delete();
    echo("key " @ %keyID @ " saved.");    
}

function Molodion::deleteKeyData(%this, %keyID)
{
    if(!isObject(%this.KeyData[%keyID]))
        return;
    %this.KeyData[%keyID].delete();
    if(isFile(%this.savepath @ "key_" @ %keyID @ ".dat"))
        fileDelete(%this.savepath @ "key_" @ %keyID @ ".dat");
    echo("key " @ %keyID @ " deleted.");    
}

function Molodion::resetKeyData(%this, %keyID)
{
    if(!isObject(%this.KeyData[%keyID]))
        return;
        
    for(%i=0;%i<%this.valuecount;%i++)
    {
        %this.KeyData[%keyID].Value[%this.Valuename[%i]] = %this.Value[%i];
    }
    echo("key " @ %keyID @ " reset.");
    %this.saveKeyData(%keyID);
}

You can't, your best bet would be to save every x amount of minutes.

Depending on how much data you're saving at a time / frequency, you can have it save when you modify data. But actually do take into consideration amount and frequency so you don't have server lag with the script.

Depending on how much data you're saving at a time / frequency, you can have it save when you modify data. But actually do take into consideration amount and frequency so you don't have server lag with the script.
This is why an atomic setup is better for Blockland. Sure it is annoying to have lots of single files for each key (such as a BLID), but you only have to save the specific keys that were changed.

This is why an atomic setup is better for Blockland. Sure it is annoying to have lots of single files for each key (such as a BLID), but you only have to save the specific keys that were changed.
Is it good to load all the keys on startup?

Is it good to load all the keys on startup?
Would it be possible for you to load individual keys when that user connects?

Would it be possible for you to load individual keys when that user connects?
Of course, but I have to modify data of offline users, e.g. shops

Of course, but I have to modify data of offline users, e.g. shops
Only have it modify data it needs to and only do it when it needs to do it.
For example, save the small bits of information (like a players stats) when it updates, and when they leave.

Just be warned that the fileObject.openForWrite, fileObject.openForAppend, and fileObject.openForRead methods are very slow. I did some benchmarking tests and they cause a huge performance drop in repetitive tasks. If you're going to be reading and writing to files often it's best to simply leave the file open and not close it until you're completely done.

Just be warned that the fileObject.openForWrite, fileObject.openForAppend, and fileObject.openForRead methods are very slow. I did some benchmarking tests and they cause a huge performance drop in repetitive tasks. If you're going to be reading and writing to files often it's best to simply leave the file open and not close it until you're completely done.
What happens if I don't close it?
Is the file corrupted?

Not sure really, but I know that you're supposed to close it when you're done so be sure to close it at some point.

Not sure really, but I know that you're supposed to close it when you're done so be sure to close it at some point.
How do I define 'when I'm done'?

If all you're worried about is crashes, the file automatically closes when blockland does with no adverse effects that I can see

Could you make file objects in an array fashion to work with the data indefinitely?
$FileObjectArray::[%bl_id] = new fileObject();

Then just open all the relevant files with only those file objects?

Could you make file objects in an array fashion to work with the data indefinitely?
$FileObjectArray::[%bl_id] = new fileObject();

Then just open all the relevant files with only those file objects?

Sure, as long as you clean everything up properly. Also, you can't have a [ after ::. You could do something like this though: $FileObjectArray["::" @ %bl_id]