Go Back   RunUO - Ultima Online Emulation > RunUO > Script Support

Script Support Get support for modifying RunUO Scripts, or writing your own!

Reply
 
Thread Tools Display Modes
Old 10-02-2002, 02:54 AM   #1 (permalink)
Forum Administrator
 
krrios's Avatar
 
Join Date: Aug 2002
Posts: 2,850
Default Serialization

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 )
{
}
All this does is call your parent class' serialization constructor.

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();
}
For the simplest of scripts, where no fields are serialized, that's all you need. You can see a "version" number is serialized; this is for backwards compatibility. If you ever modify the fields in your script, old worldfiles can still work.

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;
		}
	}
}
The "switch ( version )" construct allows us to branch from version to version, allowing you to write less code. Here's how we would add another string field to the same script:

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;
		}
	}
}
The version number has been changed from 0 to 1, and the field has been added to the Serialize method. If this script loads an old world file (one with the version number of 0), it does not try to read anything for "m_StringField2".

Last edited by daat99; 01-12-2006 at 05:15 PM.
krrios is offline   Reply With Quote
Old 11-26-2002, 05:38 AM   #2 (permalink)
loupgarou
Guest
 
Posts: n/a
Default

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?
  Reply With Quote
Old 11-26-2002, 06:34 AM   #3 (permalink)
Administrator
 
Zippy's Avatar
 
Join Date: Aug 2002
Location: Baltimore, MD
Age: 25
Posts: 4,845
Default

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

Zippy is offline   Reply With Quote
Old 11-27-2002, 04:04 AM   #4 (permalink)
loupgarou
Guest
 
Posts: n/a
Default

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.
  Reply With Quote
Old 12-05-2002, 11:27 PM   #5 (permalink)
 
Join Date: Dec 2002
Posts: 42
Default

Quote:
Originally Posted by loupgarou
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)
Physical storage at runtime changes, but nothing that affects the application programmer. CLS ensures they're handled correctly at runtime. An int will still be Int32, and it's up to the memory compactor to deal with the difference. Unmanaged code is another story.

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.
dubious_advocate is offline   Reply With Quote
Old 12-08-2002, 08:40 PM   #6 (permalink)
 
Join Date: Dec 2002
Posts: 42
Default

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.
dubious_advocate is offline   Reply With Quote
Old 12-30-2002, 01:44 PM   #7 (permalink)
Forum Administrator
 
krrios's Avatar
 
Join Date: Aug 2002
Posts: 2,850
Default

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 );
   }
}
krrios is offline   Reply With Quote
Old 01-01-2003, 06:58 PM   #8 (permalink)
infiniti
Guest
 
Posts: n/a
Default

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
  Reply With Quote
Old 01-03-2003, 06:30 PM   #9 (permalink)
 
Join Date: Oct 2002
Posts: 255
Send a message via ICQ to Tom Bombadil
Default

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
Tom Bombadil is offline   Reply With Quote
Old 01-29-2003, 11:50 AM   #10 (permalink)
 
Join Date: Dec 2002
Posts: 140
Default

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
mrkroket is offline   Reply With Quote
Old 03-02-2003, 02:07 PM   #11 (permalink)
<censored>
 
Fury's Avatar
 
Join Date: Feb 2003
Location: NewYork
Age: 31
Posts: 581
Default

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
Fury is offline   Reply With Quote
Old 03-02-2003, 02:43 PM   #12 (permalink)
Account Terminated
 
Join Date: Sep 2002
Age: 26
Posts: 3,846
Send a message via ICQ to Phantom Send a message via AIM to Phantom Send a message via MSN to Phantom
Default

Quote:
Originally Posted by Fury
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
Thats the idea of version'ing they will update themselfs to version 1.
Phantom is offline   Reply With Quote
Old 03-02-2003, 10:19 PM   #13 (permalink)
<censored>
 
Fury's Avatar
 
Join Date: Feb 2003
Location: NewYork
Age: 31
Posts: 581
Default

thats what i thought but wanted to be sure.. thank you
Fury is offline   Reply With Quote
Old 03-14-2003, 07:21 PM   #14 (permalink)
Account Terminated
 
Join Date: Sep 2002
Age: 26
Posts: 3,846
Send a message via ICQ to Phantom Send a message via AIM to Phantom Send a message via MSN to Phantom
Default

No but you could write a function that updates the old items, but yes they would get the new variable IF you set the variable.

hard question to answer :-)
Phantom is offline   Reply With Quote
Old 04-25-2003, 11:37 PM   #15 (permalink)
 
Join Date: Sep 2002
Posts: 622
Send a message via ICQ to raistlin Send a message via AIM to raistlin
Default

so changing my playermoblies in this way would delete all my players chars?
Is there anyway to get around this?
raistlin is offline   Reply With Quote
Old 05-15-2003, 02:37 PM   #16 (permalink)
 
Join Date: Apr 2003
Posts: 19
Default

Really Thanks for this Help on Serialisation !
But i have a question :
How to seriale a table of mobile ....? i want to serial a mobile[255]....
Thx
Zog-Zog is offline   Reply With Quote
Old 07-08-2003, 07:42 AM   #17 (permalink)
 
Join Date: Feb 2003
Posts: 85
Default

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
Khronos is offline   Reply With Quote
Old 07-08-2003, 08:17 AM   #18 (permalink)
 
Join Date: Dec 2002
Posts: 140
Default

B I think. A is a waste of space.
mrkroket is offline   Reply With Quote
Old 07-08-2003, 09:40 AM   #19 (permalink)
 
Join Date: Feb 2003
Posts: 85
Default

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 )
Khronos is offline   Reply With Quote
Old 07-08-2003, 12:57 PM   #20 (permalink)
Forum Administrator
 
krrios's Avatar
 
Join Date: Aug 2002
Posts: 2,850
Default

Only object instances (items, mobiles, guilds) are stored as serials.
krrios is offline   Reply With Quote
Old 07-09-2003, 03:53 AM   #21 (permalink)
 
Join Date: Feb 2003
Posts: 85
Default

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 ?
Khronos is offline   Reply With Quote
Old 07-09-2003, 04:20 AM   #22 (permalink)
Forum Administrator
 
krrios's Avatar
 
Join Date: Aug 2002
Posts: 2,850
Default

Well, yes, you can create an object instance and have it reside in the Internal map, where it is inaccessible. Alternatively, you can certainly write your own custom file serialization methods.
krrios is offline   Reply With Quote
Old 08-22-2003, 01:25 PM   #23 (permalink)
 
SoulStone's Avatar
 
Join Date: Feb 2003
Age: 36
Posts: 68
Send a message via ICQ to SoulStone Send a message via MSN to SoulStone
Default

Quote:
Originally Posted by krrios
The standard way to serialize custom classes is through similar Serialize/Deserialize methods.

[code:1]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 );
}
}[/code:1]
What should I do to serialize/deserialize a class that uses MyClass in an ArrayList, like this:
[code:1]ArrayList mylist = new ArrayList();
mylist.Add( new MyClass( par1, par2 ) );[/code:1]
How could I serialize/deserialize mylist?

SoulStone.
SoulStone is offline   Reply With Quote
Old 09-02-2003, 03:57 AM   #24 (permalink)
 
Join Date: Nov 2002
Posts: 636
Default

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&lt;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&lt;length; k++)
{
MyClass mc=new MyClass(r);
myList.Add(mc);
}
[/code:1]
Ceday is offline   Reply With Quote
Old 09-25-2003, 12:07 PM   #25 (permalink)
 
Join Date: Oct 2002
Age: 22
Posts: 4,689
Default

Can someone make a serialization and deserialization method for commands, or regions for example, so we do not require putting an item or mobile in the internal map?
XxSP1DERxX is offline   Reply With Quote
Reply

Bookmarks


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off



Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0 RC5