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.

Universal Data Backup

Universal Data Back-Up
Version: 3.0
By: Kain Nobel

Introduction

Ever go to open your RPG Maker XP/VX project, just to find *gasp* an Unexpected File Format error!? This system does regular back-ups of all the files in the specified Data folder, and re-writes them to a backup directory. Not only that, but this script is universal meaning it'll, in theory, work in any standard Ruby library just as well as it does with RGSS/RGSS2.

Features

  • An automated project data back-up utility.
  • You're able to tell the system how many versions max to keep.
  • Automatically deletes older back-ups.
  • Saves all data in specified data directory.
  • Writes all data to specified backup directory.
  • Doesn't just read default RM Maker files.
  • Writes file as it origionally was, with same data extension.
  • Backups are sorted chronologically based on the time saved.

Script

Code:
#===============================================================================

# ** System : Data Back-Up

#===============================================================================

 

#-------------------------------------------------------------------------------

# * SDK Log

#-------------------------------------------------------------------------------

if Object.const_defined?(:SDK)

  SDK.log('System.DataBackUp', 'Kain Nobel ©', 3.0, '04.16.2009')

end

 

#=============================================================================== 

# ** DataBackUp

#===============================================================================

 

module DataBackUp

  #-----------------------------------------------------------------------------

  # * Enable or Disable this system by setting true/false.

  #-----------------------------------------------------------------------------

  Enabled = ($DEBUG == true or $TEST == true)

  #-----------------------------------------------------------------------------

  # * Directory where all origional data to be backed up is.

  #-----------------------------------------------------------------------------

  RB_Dir  = "Data"

  #-----------------------------------------------------------------------------

  # * Directory where all backup folders/files will be created.

  #-----------------------------------------------------------------------------

  WB_Dir  = "Data/Versions"

  #-----------------------------------------------------------------------------

  # * Maximum number of backups allowed.

  #-----------------------------------------------------------------------------

  Maximum = 1

  #-----------------------------------------------------------------------------

  # * Time Format for the sub directory.

  #-----------------------------------------------------------------------------

  TimeF   = "%m-%d-%Y @ %I-%M%p"

  #-----------------------------------------------------------------------------

  # * DataBackUp.create

  #-----------------------------------------------------------------------------

  def self.create

    if Enabled

      self.data_purge

      self.data_load

      self.data_save

    end

  end

  #-----------------------------------------------------------------------------

  # * DataBackUp.data_purge

  #-----------------------------------------------------------------------------

  def self.data_purge

    unless FileTest.directory?(WB_Dir)

      Dir.mkdir(WB_Dir)

    end

    dir = Dir.entries(WB_Dir)

    dir.delete('.')

    dir.delete('..')

    return if dir.size < Maximum || Maximum < 1

    for j in 0...(dir.size - (Maximum - 1))

      entries = Dir.entries("#{WB_Dir}/#{dir[j]}")

      entries.delete('.')

      entries.delete('..')

      entries.each {|f| File.delete("#{WB_Dir}/#{dir[j]}/#{f}")}

      Dir.delete("#{WB_Dir}/#{dir[j]}")

    end

  end

  #-----------------------------------------------------------------------------

  # * DataBackUp.data_load

  #-----------------------------------------------------------------------------

  def self.data_load

    @data = Hash.new

    dir = Dir.new(RB_Dir).entries

    dir.delete(".")

    dir.delete("..")

    dir.each {|f|

    if FileTest.file?("#{RB_Dir}/#{f}")

      file = File.open("#{RB_Dir}/#{f}", "rb")

      @data[f] = Marshal.load(file)

      file.close

    end}

  end

  #-----------------------------------------------------------------------------

  # * DataBackUp.data_save

  #-----------------------------------------------------------------------------

  def self.data_save

    if Maximum < 1

      @data = nil

      return

    end

    time = Time.new

    dir = time.strftime("#{WB_Dir}/#{TimeF}")

    return if FileTest.directory?(dir)

    Dir.mkdir(dir)

    @data.each_key {|f|

    file = File.open("#{dir}/#{f}", "wb")

    Marshal.dump(@data[f], file)

    file.close}

    @data = nil

  end

end

DataBackUp.create

Instructions

Place this script anywhere so long as it is above main. It is highly suggested that, if you have script(s) that you suspect could corrupt your data you definately place this one above that/those script(s).

I also suggest that you set this script to save more than just 1 backup at a time, incase anything goes wrong in the data load/dump process. Lastly, I'd only use this to save reasonable files such as data files (not all your graphics 'n stuff, that would be memory-intensive as hell), and be sure that the files in the directory are all readable/deletable.

FAQ

Dargor's is only intended for RPG Maker XP/VX
Mine is intended for RPG Maker XP/VX and Ruby standard platforms.
Dargor's only handles the files that come default to an RM project.
Mine handles all files in the specified 'data' folder.
Dargor's manually tags the file extensions to the backed up files.
Mine lets the files handle their own extensions.
Dargor's uses save_data and load_data, which are RM methods.
Mine uses Marshal.dump and Marshal.load which are Ruby methods.
Dargor's would probably work in an encrypted project.
Mine will crash an encrypted RM project if enabled.
Basically, TimeF is the time format that the project uses to name backup sub directories. I suggest leaving this alone because it enforces the proper sorting of directory archives. When a backup is created, it will (according to my default settings) save to...

"Data/BackUps/yy-mm-dd @ hh-mm/"

...so in other words, it will save the proper chronological format...

year => month => day => hour => minute
NO! Please, for your own sake, archive your most important versions of anything to a directory unrelated to what you're going to set in the script, because it only keeps the Maximum ammount of recent versions and deletes older ones. So, for instance if you get so far into your project and you have everything working great, I'd save my entire project somewhere else and let the DataBackUp system version only my most recent stuff.
For one, why should you need this in a finished and encrypted project? You don't! More importantly, this script uses Marshal.dump and Marshal.load, which doesn't handle the encrypted RGSSAD. If you would like it to, you can easily exchange those for save_data and load_data methods of RGSS(2) instead but... honestly, you shouldn't need to use this in an encrypted game anyways. XD

Compatibility

This script is compatible with most any Ruby-esque platform, including but not limited to Ruby, RGSS and RGSS2. This also means that it is compatible with any version of the SDK or MACL Libraries. This script, however, shouldn't be enabled or present in an Encrypted RM Project.

Credits and Thanks

Good ol' Dargor wrote a system much like this, so I'd like to credit and thank him for the inspiration.

Terms and Conditions

If you used this to help develop your project, please credit me! Please do not redistribute without letting me know. I am not responsible if you forget to remove/disable this from an encrypted RM Game and problems result.
 
Semi-OT

FileUtils in Ruby has a good method called cp_r, it copies all the directories and subdirectories contents (don't forget to use Dir.getwd first). You can copy and paste the fileutils.rb contents on the Script Editor and create any methods you like to simply the process even more. According to the scripter's comments it copies files recursively. You can easily (pre-)define a location for the backup folder like this...

FileUtils.cp_r(source_dir, dest_dir)

Back On Topic

It's good to see this script of yours include a data_purge method, but I don't like, you may delete something you might still need... Especially if the last backup throws an error message... (Or lights go off or anything else happens...)

I guess data_purge should stand alone... and not included in DataBackUp.create method...
 
Well, when I wrote it I intended it so the user can set how many archives of their data they want to save each time their project is loaded. Lets say they only want to save 3 versions, the 3 newest versions will be saved and anything older than those 3 will be deleted automatically.

However, you do make good points, especially about unexpected tragedies (such as power outages) and something going wrong when the script loads/saves the data (no file permission, etc). I'd recommend always having Maximum set to 2 or more, that way if your main data files and your last backup were ruined, you'd still have the one before that. Also, I'd recommend that you save your best version of anything to another directory unrelated to the script since it only keeps the latest versions of whatever you're doing.

One thing that comes to mind though; old versions are always being deleted, but is this really costing the user physical memory? According to experts, when you 'delete' a file you're not really 'deleting' a file, your computer is just hiding it somewhere else in memory. With this being the case, should I re-write the system so that it opens old archives and overwrites each existing file with the new data and renames the folder to the current date/time?

If anybody has anything further to suggest I'm open for it, I think there is a few things I could do better with this little script.
 

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