|
||
|
|||||||
| Script Support Get support for modifying RunUO Scripts, or writing your own! |
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 (permalink) |
|
Forum Administrator
Join Date: Aug 2002
Posts: 2,850
|
To save and load the world, RunUO uses serialization. Every item or mobile you script is required to have three different methods associated with that.
The first is very simple, a special serialization "constructor" called when the object is being loaded from the save files. Usually you can use a simple prototype: Code:
public MyClassName( Serial serial ) : base( serial )
{
}
The next two methods are for serializing and deserializing (saving and loading). These methods have one parameter each, a GenericWriter and GenericReader. They provide methods for reading and writing any data you have. Code:
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
Here's an example for two fields, a string and a number. Code:
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
writer.Write( m_StringField );
writer.Write( m_NumberField );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
m_StringField = reader.ReadString();
m_NumberField = reader.ReadInt();
break;
}
}
}
Code:
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 1 ); // version
writer.Write( m_StringField2 );
writer.Write( m_StringField );
writer.Write( m_NumberField );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 1:
{
m_StringField2 = reader.ReadString();
goto case 0;
}
case 0:
{
m_StringField = reader.ReadString();
m_NumberField = reader.ReadInt();
break;
}
}
}
Last edited by daat99; 01-12-2006 at 05:15 PM. |
|
|
|
|
|
#2 (permalink) |
|
Guest
Posts: n/a
|
a strange question.
how does this affect worldfile robustness? public override void Serialize( GenericWriter writer ) { base.Serialize( writer ); writer.Write( (int) 0 ); // version writer.Write( m_StringField ); writer.Write( m_NumberField ); } eg, however, in version 300 of the same script, public override void Deserialize( GenericReader reader ) { base.Deserialize( reader ); int version = reader.ReadInt(); switch ( version ) { case 300: { m_StringField = reader.ReadString(); m_NumberField = reader.ReadInt(); } case 299: case ... case 1: { m_StringField2 = reader.ReadString(); goto case 0; } case 0: { m_StringField = reader.ReadString(); m_NumberField = reader.ReadInt(); break; } } } basically, wouldn't maintenance be hell? ie: with every version change of a script, I need to keep a copy of the worldfile + script backedup in case I need to roll back, OR retain n'th case/switch in the deserialize function. or eg: I make a change to lots of scripts, I save a worldfile. version=10, something goes majorly wrong (some kind of error not previously discovered) that I need to revert the scripts (version=9) but retain the current worldfile (otherwise players will bitch about lost time). (in which case, since the worldfile is later, when read, version doesn't exist in the current worldfile, leading to all instances of the item becoming..? default? not loaded?) I think what I need to know is: how to manage change? |
|
|
|
#3 (permalink) |
|
Administrator
Join Date: Aug 2002
Location: Baltimore, MD
Age: 25
Posts: 4,845
|
You're right, the Serialize/Deserialize function are not equipped to handle Reversions to old scripts. If you need to revert, you'll have to delete all items of this type.
However, I don't see this is much of a problem... you should be damn sure it's not going to mess up so badly you have to totally revert the script before you decide to put it on your shard. And yes, a script with 300 version could be hard to manage, but realisitically how many versions will something have? Could you ever really add 300 properties to something? Also, it is possible for you to 'merge' versions.... You could have your world load as normal, but have your script save all of your items as version 0, then edit your script so the next time it loads, version 0 will contain everything. A "converter" of sorts if you want to change version #s.
__________________
Zippy, Razor Creator and RunUO Core Developer The RunUO Software Team "Intuition, like a flash of lightning, lasts only for a second. It generally comes when one is tormented by a difficult decipherment and when one reviews in his mind the fruitless experiments already tried. Suddenly the light breaks through and one finds after a few minutes what previous days of labor were unable to reveal." ~The Cryptonomicon |
|
|
|
|
|
#4 (permalink) |
|
Guest
Posts: n/a
|
zippy, that's of course if all things are ideal, in practice (which I know well enough after 1.5 years of admining,) especially when it comes down to multiple programmers/scriptors, or contributions, things are never perfect.
as a last resort, we can always revert to delete all objects of this type. or handle a bare minimum deserialization with switch case else, assuming int isn't found. how does deserialize feel about reading a non existent member variable? I think its possible to catch the exception and ignore it, and excess member variables should be as defaulted in the constructor? will deserialize still work let's say once I move my worldfiles and runuo to WinXp 64 (32bit cpu= 64bit, size of datatypes will change) ? I guess I have to experiment to see in what ways it can be broken and thus avoided. |
|
|
|
#5 (permalink) | |
|
Join Date: Dec 2002
Posts: 42
|
Quote:
Versioning isn't something that's used often in this environment. And if you do need it then simply add a class manager helper class to upsize downlevel objects. |
|
|
|
|
|
|
#6 (permalink) |
|
Join Date: Dec 2002
Posts: 42
|
Hmm - how do we do serialization for an entire object? Normally I'd flag the object with the [serialization] attribute rather than decompose it field by field like I see in the scripts.
I'm using structures and usage objects within my mobiles. |
|
|
|
|
|
#7 (permalink) |
|
Forum Administrator
Join Date: Aug 2002
Posts: 2,850
|
The standard way to serialize custom classes is through similar Serialize/Deserialize methods.
Code:
public class MyClass
{
private string m_Field1;
private int m_Field2;
...
public void Serialize( GenericWriter w )
{
w.Write( m_Field1 );
w.Write( m_Field2 );
}
public MyClass( GenericReader r )
{
m_Field1 = r.ReadString();
m_Field2 = r.ReadInt();
}
}
....
public class MyMobile : Mobile
{
private MyClass m_Class;
...
public override void Serialize( GenericWriter w )
{
...
m_Class.Serialize( w );
}
public override void Deserialize( GenericReader r )
{
...
m_Class = new MyClass( r );
}
}
|
|
|
|
|
|
#8 (permalink) |
|
Guest
Posts: n/a
|
Sorry for my ignorance but could someone please explain the Serialize() and Deserialize() more as far as what each does and why it does it? And also what is with the GenericWriter and GenericReader? I tried the links above in the first message but they were broken links.. so i'm still clueless as to what each one of them does.
Thanks for your replies |
|
|
|
#9 (permalink) |
|
Krioss , if i add some property to the class MyClass (like the example) .. i must modify something for the Serialize/Deserialize method.
how i could work ? I suppose i must change the public MyClass( GenericReader r ) adding a new parameter and i've something like this : public MyClass( GenericReader r ,int version) and in the method i insert a case for deserialize correctly ... it's right ? (obviously i changhe the version ion the MyMobyle class Serialize when i make the modify in MyClass) tnx :P
__________________
http://www.runuo.sm/forum |
|
|
|
|
|
|
#10 (permalink) |
|
Join Date: Dec 2002
Posts: 140
|
As far as I know serialize & deserialize are used to save/load all objects of the server.
Serialize: Writes the data of an object to the savegame file. Deserialize: Reads the data of an object from the savegame file. The data you must save is all new variables you created on that class. If you programmed incorrectly those, you'll get problems (reading error, incorrect data, etc.) when reinit your server from a savegame. You must load the variables in the same order you save it, otherwise it will get errors. Be careful when programming these two methods. Hope it helps |
|
|
|
|
|
#11 (permalink) |
|
<censored>
Join Date: Feb 2003
Location: NewYork
Age: 31
Posts: 581
|
ok lets say i have item x on my shard... this item is saved.. i add a new property to the item so i add a case 1 to the loader.. so now the old items in the world before the new variable was added will be loaded using case 0... my question is.... when these old items are loaded will they aquire this new variable and then be saved with it automatically? so next time the world goes to save these will all be case 1 items.. right?
thanks in advance... this area is pretty important so i wanna fully understand whats going on |
|
|
|
|
|
#12 (permalink) | |
|
Account Terminated
|
Quote:
|
|
|
|
|
|
|
#17 (permalink) |
|
Join Date: Feb 2003
Posts: 85
|
A little help on program flow:
An Item references a Mobile (say because he is the owner of the item). Now I serialize the Item so that it maintains the reference to the Mobile. i.e. writer.Write( myMobile ) The Mobile and Item are serialized as normal but what happens when I attempt to serialize the Mobile reference? Does it: A) serialize the Moblie again and if so what happens of deserialization now that you have 2 serializations of the same Mobile. OR B) somehow just know its a reference and stores only an identifier (e.g. serial) If I wasn't clear enough please say so and I will try and explain my problem again. Thanks |
|
|
|
|
|
#19 (permalink) |
|
Join Date: Feb 2003
Posts: 85
|
If, say, you have created your own custom serializable classes (as described by krrios earlier in this thread )
Would these also benefit from this? (if indeed they do handle references gracefully) or would you have to code your custom class to handle this? (i.e. create some sort of serial number ) |
|
|
|
|
|
#21 (permalink) |
|
Join Date: Feb 2003
Posts: 85
|
Basically Items, Mobiles and Guilds use method B described earlier while your own custom classes use method A. Correct?
Is there any way to make an item that is not physically present in the world but will be serialized ? e.g. by creating a new instance of the item and not moving it to the world ? |
|
|
|
|
|
#23 (permalink) | |
|
Quote:
[code:1]ArrayList mylist = new ArrayList(); mylist.Add( new MyClass( par1, par2 ) );[/code:1] How could I serialize/deserialize mylist? SoulStone. |
||
|
|
|
|
|
#24 (permalink) |
|
Join Date: Nov 2002
Posts: 636
|
there are some functions:
ReadItemList ReadMobileList etc. if there is a function like ReadClassList or something like that, you can use it. (i havent worked on runuo, so i dont know if it exists) if there isnt any, you can do something like this: Serialize: [code:1] w.Write((int)myList.Items.Count); //w is generic writer for (int k=0; k<myList.Items.Count; k++) { (MyClass)myList[k].Serialize(w) } [/code:1] Deserialize: [code:1] int length=r.ReadInt(); //r is generic reader for(int k=0; k<length; k++) { MyClass mc=new MyClass(r); myList.Add(mc); } [/code:1] |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|