Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

[RGSS] About Marshal and Saving Methods in RMXP

Oh... I wrote this whole thing in a help topic on RGSS support, but i´m getting the feeling that no one will read it.... So i´ll post it here. There we go!

As you would already know, RMXP saves and loads your game progress. But for most makers it´s a wonder on how RMXP makes such a thing. There´re many things hidden in the default Ruby library that most people don´t know and that is widely used in RGSS. Marshal can be included in this group. So, let´s try to understand more about Marshal library, the library used to save and load files.

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:
Code:
# Class that will hold some text...
class Text
 
  attr_accessor :data
  def initialize
    @data = "Hi"
  end
 
end
 
# Class that will be the real object we´ll use
class Handler
 
  def initialize
    @text = Text.new
  end
 
  def say_something
    return @text.data
  end
 
  def record_this_text(txt)
    @text.data = txt
  end
 
end

So, we need new instances of them to start explaining anything.
Code:
myObject = Handler.new
print myObject.say_something     => "Hi"
 
# Changing some data
myObject.record_this_text("Hello World!")

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
string = Marshal.dump(myObject)

Now our object is serialized inside string. To recover it we call Marshal.load:
Code:
recoveredObject = Marshal.load(string)
print recoveredObject.say_something     => "Hello World!"

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"
mode = "wb"  # in this case the file will be in the write mode only
file = File.open(filename, mode)

* 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. 
Marshal.dump(myObject, file)
 
# It´s REALLY important to close the IO object, otherwise
# the object won´t be saved correctly. Make this after dumping
# all the needed objects.
file.close

Now, to recover our object, first open the file:
Code:
filename = "Handler.rxdata"
mode = "rb"  # in this case the file will be in the read mode only
file = File.open(filename, mode)

Next, call Marshal.load:
Code:
recoveredObject = Marshal.load(file)
recoveredObject.say_something     => "Hello World!"

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")
    Marshal.dump($game_system, file)
    Marshal.dump($game_switches, file)
    Marshal.dump($game_variables, file)
    Marshal.dump($game_self_switches, file)
    Marshal.dump($game_screen, file)
    Marshal.dump($game_actors, file)
    Marshal.dump($game_party, file)
    Marshal.dump($game_troop, file)
    Marshal.dump($game_map, file)
    Marshal.dump($game_player, file)
    file.close

LOADING:
Code:
    file = File.open(filename, "rb")
    $game_system        = Marshal.load(file)
    $game_switches      = Marshal.load(file)
    $game_variables     = Marshal.load(file)
    $game_self_switches = Marshal.load(file)
    $game_screen        = Marshal.load(file)
    $game_actors        = Marshal.load(file)
    $game_party         = Marshal.load(file)
    $game_troop         = Marshal.load(file)
    $game_map           = Marshal.load(file)
    $game_player        = Marshal.load(file)
    file.close

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. For that, and 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.: I´ll update it later with the serialization method in details. Please wait ^^
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top