* This whole thing were written in a post in RGSS Support, but i sense no one will read it lol... So, i decided to post it here, supposing it will help new scripters.
Marshal is a library that converts all data from an object/objects into a byte stream, permitting the scripter to save this object into a file (outside the Ruby Interpreter´s memory) and recover it later on. Some objects cannot be dumped: if the objects to be dumped include bindings, procedure objects, instances of class IO, or singleton objects, a TypeError will be raised, so take care with what you dump. I have tried once to save an entire Bitmap for example, and the game crashed xD
Usage is fairly simple. This library has only two methods and they´re simple and very straightforward.
So... The two methods are explained, so let´s take some examples for you to understand about them:
Now, if your object can´t be saved by Marshal library bu default, you can create a serialization method for the specific object.
Also, for more informations about Marshal, check here. (Sorry i´m so tired, i will explain the serialization method in another time ^^)
And magic, our object is saved inside Handler.rxdata ^^
I REALLY hope you understand what i´m trying to explain, and i´m sorry if i was too obvious and pointless in any part.
P.S.: Give me some time and i´ll explain Serialization methods in depth.
Almost everybody knows that RMXP has the ability to save the progress made by the player in any game. But just a few people really knows how it does such that thing. In fact, there´re a lot of Ruby´s default library code in RGSS that people don´t make any kind of idea about its existence. Marshal can be included in this group. Now let´s try to understand more on this library that´s the great responsible for the saving and loading data possibility in RMXP.
Marshal is a library that converts all data from an object/objects into a byte stream, permitting the scripter to save this object into a file (outside the Ruby Interpreter´s memory) and recover it later on. Some objects cannot be dumped: if the objects to be dumped include bindings, procedure objects, instances of class IO, or singleton objects, a TypeError will be raised, so take care with what you dump. I have tried once to save an entire Bitmap for example, and the game crashed xD
Usage is fairly simple. This library has only two methods and they´re simple and very straightforward.
- Marshal.dump(object, [anIO, [limit]])
This method converts all the objects´ data into a byte stream. object is te object to be serialized.
anIO is not necessary, but if passed it must be an instance of the IO class (this is an special object that can be saved as an ordinary file, for you to know). In this case, Marshal.dump will dump the object´s stream into this IO object. Otherwise, it will return a string with the serialized object.
In Marshal.dump, more than one object can be dumped into an IO object, and in this case the user can make the process check to see the number of dumps made in this IO object. limit[/b] represents the maximum number of objects that can be inside the IO object. -1 is the default value, and if it is that value, no ckeck will be made. As anIO, this argument is not necessary.
- Marshal.load(object, [proc])
Marshal.load is the part responsible for recovering the dumped object´s data. object must be an instance of IO class, a String or any class that responds to the to_str method.
This method returns the recovered object. If an IO object is passed and if it has more than one object dumped, it will load the objects in the same order they were dumped (the first dumped object will be the first to be loaded), and will return only ONE object each time you ask for it to load objects from that IO class. This operation must be done in order, so take care.
proc is a Proc object that can be passed to be executed each time you load an object. Don´t really care with it since it´s a bit complicated for most scripters ^^ (if you want i can explain about Procs later).
So... The two methods are explained, so let´s take some examples for you to understand about them:
Suppose we have those two classes:
So, we need new instances of them to start explaining anything.
As you can see we changed the object´s data and wants to store it. Suppose we can´t do it with IO objects, the only way to do is with Strings:
Now our object is serialized inside string. To recover it we call Marshal.load:
As you can see it´s very easy. Now let´s get more in depth... We will save it into a file. First, create a new IO object for that:
* NOTE: File.open opens the file specified in filename and returns a IO object that contains the bytes of it. If the file doesn´t exists it creates a new file with the name passed. Note that filename must contain the complete path and filename, but in our case we just used the default Game folder (supposing we´re writing it in RMXP). So, the new file will appear in the same place where Game.exe is.
Pass it to Marshal.dump...
Now, to recover our object, first open the file:
Next, call Marshal.load:
The magic is done ^^
Now your saved and recovered myObject is in recoveredObject. And sure, you can dump more than one object into a file. Take RMXP for example:
SAVING:
LOADING:
Note that it´s just the condensated and simplified Scene_Save and Scene_Load most important code. I gave focus only to the Marshal methods. Note that the files are saved and loaded at the same order, that´s very important.
Code:
# Class that will hold some text...
[SIZE=2]class Text[/SIZE]
[SIZE=2]attr_accessor :data[/SIZE]
[SIZE=2]def initialize[/SIZE]
[SIZE=2] @data = "Hi"[/SIZE]
[SIZE=2]end[/SIZE]
[SIZE=2]end[/SIZE]
[SIZE=2]# Class that will be the real object we´ll use[/SIZE]
[SIZE=2]class Handler[/SIZE]
[SIZE=2]def initialize[/SIZE]
[SIZE=2] @text = Text.new[/SIZE]
[SIZE=2]end[/SIZE]
[SIZE=2]def say_something[/SIZE]
[SIZE=2] return @text.data[/SIZE]
[SIZE=2]end[/SIZE]
[SIZE=2]def record_this_text(txt)[/SIZE]
[SIZE=2] @text.data = txt[/SIZE]
[SIZE=2]end[/SIZE]
[SIZE=2]end[/SIZE]
So, we need new instances of them to start explaining anything.
Code:
myObject = Handler.new
[SIZE=2]print myObject.say_something => "Hi"[/SIZE]
[SIZE=2]# Changing some data[/SIZE]
[SIZE=2]myObject.record_this_text("Hello World!")[/SIZE]
As you can see we changed the object´s data and wants to store it. Suppose we can´t do it with IO objects, the only way to do is with Strings:
Code:
# Serializing the object and getting the result
[SIZE=2]string = Marshal.dump(myObject)[/SIZE]
Now our object is serialized inside string. To recover it we call Marshal.load:
Code:
recoveredObject = Marshal.load(string)
[SIZE=2]print recoveredObject.say_something => "Hello World!"[/SIZE]
As you can see it´s very easy. Now let´s get more in depth... We will save it into a file. First, create a new IO object for that:
Code:
filename = "Handler.rxdata"
[SIZE=2]mode = "wb" # in this case the file will be in the write mode only[/SIZE]
[SIZE=2]file = File.open(filename, mode)[/SIZE]
* NOTE: File.open opens the file specified in filename and returns a IO object that contains the bytes of it. If the file doesn´t exists it creates a new file with the name passed. Note that filename must contain the complete path and filename, but in our case we just used the default Game folder (supposing we´re writing it in RMXP). So, the new file will appear in the same place where Game.exe is.
Pass it to Marshal.dump...
Code:
# In this case Marshal.dump returns nothing.
[SIZE=2]Marshal.dump(myObject, file)[/SIZE]
[SIZE=2]# It´s REALLY important to close the IO object, otherwise[/SIZE]
[SIZE=2]# the object won´t be saved correctly. Make this after dumping[/SIZE]
[SIZE=2]# all the needed objects.[/SIZE]
[SIZE=2]file.close[/SIZE]
Now, to recover our object, first open the file:
Code:
filename = "Handler.rxdata"
[SIZE=2]mode = "rb" # in this case the file will be in the read mode only[/SIZE]
[SIZE=2]file = File.open(filename, mode)[/SIZE]
Next, call Marshal.load:
Code:
recoveredObject = Marshal.load(file)
[SIZE=2]recoveredObject.say_something => "Hello World!"[/SIZE]
The magic is done ^^
Now your saved and recovered myObject is in recoveredObject. And sure, you can dump more than one object into a file. Take RMXP for example:
SAVING:
Code:
file = File.open(filename, "wb")
[SIZE=2] Marshal.dump($game_system, file)[/SIZE]
[SIZE=2] Marshal.dump($game_switches, file)[/SIZE]
[SIZE=2] Marshal.dump($game_variables, file)[/SIZE]
[SIZE=2] Marshal.dump($game_self_switches, file)[/SIZE]
[SIZE=2] Marshal.dump($game_screen, file)[/SIZE]
[SIZE=2] Marshal.dump($game_actors, file)[/SIZE]
[SIZE=2] Marshal.dump($game_party, file)[/SIZE]
[SIZE=2] Marshal.dump($game_troop, file)[/SIZE]
[SIZE=2] Marshal.dump($game_map, file)[/SIZE]
[SIZE=2] Marshal.dump($game_player, file)[/SIZE]
[SIZE=2] file.close[/SIZE]
LOADING:
Code:
file = File.open(filename, "rb")
[SIZE=2] $game_system = Marshal.load(file)[/SIZE]
[SIZE=2] $game_switches = Marshal.load(file)[/SIZE]
[SIZE=2] $game_variables = Marshal.load(file)[/SIZE]
[SIZE=2] $game_self_switches = Marshal.load(file)[/SIZE]
[SIZE=2] $game_screen = Marshal.load(file)[/SIZE]
[SIZE=2] $game_actors = Marshal.load(file)[/SIZE]
[SIZE=2] $game_party = Marshal.load(file)[/SIZE]
[SIZE=2] $game_troop = Marshal.load(file)[/SIZE]
[SIZE=2] $game_map = Marshal.load(file)[/SIZE]
[SIZE=2] $game_player = Marshal.load(file)[/SIZE]
[SIZE=2] file.close[/SIZE]
Note that it´s just the condensated and simplified Scene_Save and Scene_Load most important code. I gave focus only to the Marshal methods. Note that the files are saved and loaded at the same order, that´s very important.
Now, if your object can´t be saved by Marshal library bu default, you can create a serialization method for the specific object.
Will be done wait ^^
And magic, our object is saved inside Handler.rxdata ^^
I REALLY hope you understand what i´m trying to explain, and i´m sorry if i was too obvious and pointless in any part.
P.S.: Give me some time and i´ll explain Serialization methods in depth.