Resource icon

Code Serialization and Deserialization: From Scratch

So I decided since I started with something non-essential, I'd come back to you with some pretty fundamental knowledge of loading and saving.

I know there are many tutorials like it, but I don't think I've seen anything about the process of hooking world load and world save events, or the an explanation of the world load process, or even initializing new streams. All of these things are fundamental to how the world is saved and loaded.

Let's start simple: first we need the path which we'll save to. We'll want it to be static so there's only one version for every instance of the object. We'll also want it read-only, so that outside code can not manipulate this path (They still could, nothing is completely secure given time and resources).

Code:
private static readonly string SavePath = "Saves\\Foo";
private static readonly string SaveFile = Path.Combine(SavePath, "bar.bin");

The next thing we'll need to do is listen for the Word Load Event. For this, you'll need to understand a little bit about the progression of server start up. The event must be hooked in the Configure() method, and the reason behind this that Initialization() happens after the initial World Load Event (Configure > Load > Initialize). We'll also want this Configure method to be static, otherwise an instance of this method will not exist until the parent object is created, and you will be unable to access it during configuration.

I should also note that both configure and initialize must be public or they can not be called.

Code:
        public static void Configure()
        {
            EventSink.WorldLoad += new WorldLoadEventHandler(Event_WorldLoad);
        }

Now that you're listening for this event, you need to create the method or function you've attached via the WorldLoadEventHandler constructor. In this method you'll need to do a few things. First, you'll need to check if the file you're looking for exists. You'll also need to open a new file stream that you will read from, using the file path above. It's also a good idea to do this within the try functionality due the the variable states a document can exist in.

Code:
        private static void Event_WorldLoad()
        {
            if (!File.Exists(SaveFile))
                return;

            try
            {
                using (FileStream stream = new FileStream(SaveFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    BinaryFileReader reader = new BinaryFileReader(new BinaryReader(stream));
                    Deserialize(reader);
                    reader.Close();
                }
            }

            catch (ArgumentException e)
            {
                Console.WriteLine("Error: Event_WorldLoad Failed in Foo...");
                Console.WriteLine(e.Message);
            }
        }

You can then build a Deserialize() method similar to the way items and mobiles serialize.

Code:
        public static void Deserialize(BinaryFileReader reader)
        {
            int version = reader.ReadInt();
		}

Now you know how to read data, let's save it.

This time you can listen for the world save handler in your class' Initialize() because it does not need to happen before the world loads. You'll also want this to be static, for the same reasons.

Code:
        public static void Initialize()
        {
            EventSink.WorldSave += new WorldSaveEventHandler(Event_WorldSave);
        }

Then, like the loading process we will need to create the function called within the SaveEvent constructor. In this method/function we'll first want to check if the folder it's looking for exists, and create it if it doesn't. Then we'll need to instantiate a new StreamWriter to create our binary files. Also note, unlike the World Load Event, the Save Event will pass WorldSaveEventArgs via parameter to this function, and you must accommodate for this, whether or not you intend to use any information from the SaveEventArgs.

Code:
        private static void Event_WorldSave(WorldSaveEventArgs args)
        {
            try
            {
                if (!Directory.Exists(SavePath))
                    Directory.CreateDirectory(SavePath);

                BinaryFileWriter writer = new BinaryFileWriter(SaveFile, true);

                Serialize(writer);

                writer.Close(); writer.Dispose();
            }

            catch(ArgumentException e)
            {
                Console.WriteLine("Error: Event_WorldSave Failed in Foo...");
                Console.WriteLine(e.Message);
            }
        }

Then, create your object Serialize() method per usual.

Code:
        public static void Serialize(BinaryFileWriter writer)
        {
            writer.Write((int)0); //Version
		}

There you have it!
Unfortunately I can't provide any documentation, as this is entirely from my head.
Author
Enroq
Views
32
First release
Last update
Rating
0.00 star(s) 0 ratings

More resources from Enroq