I had this idea, but I finally decided to actually implement it. Normally, game data is stored in the files in a particular order. If the order is changed or new data is added, the savegame can't load, or the game will crash eventually. But if I use a loop and check for the loaded objects' class in each iteration and assign them to the respected global variable, data will be loaded properly no matter how badly the order is changed. After the loop, if any globals are still 'nil', I create a new instance and assign it. Basically, the read_save_data method will be something like this:
def read_save_data(file)
characters = frame_count = $game_system = $game_switches = $game_variables = nil
$game_self_switches = $game_screen = $game_actors = $game_party = nil
$game_troop = $game_map = $game_player = nil
data = [characters, frame_count, $game_system, $game_switches,
$game_variables, $game_self_switches, $game_screen, $game_actors,
$game_party, $game_troop, $game_map, $game_player]
# Checking each loaded object's class and assigning accordingly
while !data.any? {|obj| obj == nil}
stuff = Marshal.load(file)
if stuff.is_a?(Array)
characters = stuff
elsif stuff.is_a?(Numeric)
frame_count = stuff
elsif stuff.is_a?(Game_System)
$game_system = stuff
end
#
#and so on..
#
Graphics.frame_count = frame_count
end
#Creating new instances of extra objects
$ams = AMS.new if $ams == nil
$item_bag = Item_Bag.new if $item_bag = nil
#
#and so on..
#
end
The only catch is that data of same classes can't be recognised (like arrays and numbers). Even that can be corrected by checking the arrays, but numbers...
So... discuss :)
Why not use begin-rescue-end like I do in DREAM for the Save script? The code is easier to read and faster in processing.
Of course, but I want to make a script that people can use without having to dump their saves. Sometimes, nothing will go wrong while loading but only when the game actually begins (like itembag and ams).
You'll have to iterate through all possible instance variables of the classes with OBJ.instance_variables. Or you could create a new object and copy the existing values to the new objects.
Other than that I don't recommend doing that. It will turn out complicated and it will not cover all existing scripts.
QuoteYou'll have to iterate through all possible instance variables of the classes with OBJ.instance_variables. Or you could create a new object and copy the existing values to the new objects.
Good point... Well, I guess I won't be doing this right now.
When were are talking about saving here is something interesting I have made :3
It's a string buffer where you can marshal objects into as if it was a file. I am sure Blizz can see its uses.
class StringBuffer < IO
MODE_STRING = 1
MODE_FILE_MARSHAL = 2
MODE_FILE_BINMODE = 3
##
# Initialization of the String Buffer
# The mode can be MODE_STRING, MODE_FILE_MARSHAL or MODE_FILE_BINMODE
#
def initialize(data = nil, mode = MODE_FILE_MARSHAL, compressed = true)
if data.nil?
@data = ''
else
# Check which type the data is
case mode
when MODE_STRING
@data = data
when MODE_FILE_MARSHAL
begin
@data = load_data(data)
rescue
@data = ''
end
when MODE_FILE_BINMODE
if FileTest.exists?(data)
f = File.open(data, 'rb')
f.binmode
@data = f.read
f.close
end
end
# Decompress the data if it is compressed
if compressed
@data = Zlib::Inflate.inflate(@data)
end
end
end
##
# Save to file
# The mode can be MODE_FILE_MARSHAL or MODE_FILE_BINMODE
#
def save(filename, mode = MODE_FILE_MARSHAL, compress = true)
# Check whether the data should be compressed
if compress
data = Zlib::Deflate.deflate(@data)
else
data = @data
end
# Check whether to save in binary or marshal mode
case mode
when MODE_FILE_MARSHAL
save_data(data, filename)
when MODE_FILE_BINMODE
f = File.open(filename, 'w+')
f.binmode
f.print data
f.close
end
end
##
# Get data
#
def data
return @data
end
##
# Binary mode
#
def binmode
# Do nothing
end
##
# Write data
#
def write(data)
@data += data
end
##
# Get char
#
def getc
return @data.slice!(0)
end
##
# Read an amount of bytes
#
def read(amount)
return @data.slice!(0...amount)
end
end
On a side note I would most definitely recommend having the save file in a specific order. It simplifies matters greatly.
As for dumping objects in saves. For the majority of scripts just having the data in Game_System would suffice.
That's true. But Game_Actor is also often being used in scripts.
I especially like the compression. >:3 <3
EDIT: Isn't it "f.write data" instead of "f.print data"? O.o;
Game_Actor or Game_System. It's really the same deal. Sometimes you can also have compatibility with old saves by using defensive programming.
I am glad you like the StringBuffer :3
You can use both f.write and f.print. I believe they do the same thing, but I haven't researched it.
Wait no, they are different. The syntax is f.write(aString) while it is f.print(objects*)
It probably just converts each object to a string and uses the write operation on them in order the arguments are inputted.
Since I only use one argument f.write would probably be better although I don't know.
Anyway maybe you could consider building onto the string buffer and also allow it to save data encrypted :3
Or first compress and then encrypt it. That would be awesome ^^
Or: DREAM_encrypt -> compress -> other_encrypt -> compress again
You just gave me the idea I need for DREAM 5. ^_^
That indeed my motivation >:3
I you might want to compress first because it might be able to compress much better before than after the encryption. I don't know though, this would require some testing.
I was going to test it first anyway. I want to get a minimal filesize, lol.
In that case it could be interesting of you to know that I on average got a decrease of file size with about a factor 4. ;)
Nice, 25% save file size sounds good. I can't wait to try it out. Right after CP has reached beta status and probably before Blizz-ABS 2.0. >:3
Indeed :3
This was with a pretty much blank project though so the validity is questionable. ^^
When you said "Blank Project", you remembered me of Zerizzacon... <_<;
Quote
It's a string buffer where you can marshal objects into as if it was a file. I am sure Blizz can see its uses.
I don't see anything yet :'(
I'll paste the code in RMXP and look hard O_O
Thanks Zeriab :)
*powers up Bliz and Zeriab b/c I feel their awesomeness <3*
To help you I would suggest you try making a StringBuffer.new instead of a File.open(filename, 'wb') in Scene_Save.
Look at what happens. It would be and idea to make many prints ;)
Okay, except the print thing, I think this simply tries to compress the data. I need to look up the f.print command.