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.

A saving error...

Occasionally, when I try to save, I get this message:


Code:
Script ‘Scene_Save’ line 82: TypeError occurred.

singleton can’t be dumped


It corrupts the save file, and I can't load after that.

If it means anything, I started the project on an illegal version of RMXP a long time ago, and I was getting a similar error message back then. But now, since I have the legal version of RMXP, I thought it would go away. It hasn't. If you're wondering, this is line 82:

Code:
    Marshal.dump($game_player, file)

I'd appreciate any help.
 
Let's see, I'll just post the scripts I have that overtly deal with saving.

First I have a "save corruption fix" thing that basically just tells you a save file is corrupted instead of making the game crash when you try to load:
Code:
#==========================================================================
# ** SG Broken Save File Fix
#==========================================================================
# sandgolem 
# Version 1
# 26.06.06
#==========================================================================

SG_BrokenSave_Text = 'Corrupted file!'
SG_BrokenSave_LoadPop = 'One of your save files is corrupted.'
SG_BrokenSave_SavePop = 'One of your previous save files is corrupted. Please save over it.'
SG_BrokenSave_Load = 'This save file is corrupted. Save over it with something else.'

#==========================================================================
#
# To check for updates or find more scripts, visit:
# http://www.gamebaker.com/rmxp/scripts/
#
# To use this script, copy it and insert it in a new section above "Main",
# but under the default scripts and the SDK (if using).
#
# Have problems? You can leave me a message at:
# http://www.gamebaker.com/users/sandgolem
#
#==========================================================================

begin
  SDK.log('SG Broken Save File Fix', 'sandgolem', 1, '26.06.06')
  if SDK.state('SG Broken Save File Fix') != true
    @sg_brokensave_disabled = true
  end
  rescue
end

if !@sg_brokensave_disabled
#--------------------------------------------------------------------------

class Window_SaveFile < Window_Base
  alias sandgolem_brokensavefix_winsavefile_init initialize
  def initialize(file_index, filename)
    begin
      sandgolem_brokensavefix_winsavefile_init(file_index,filename)
    rescue
      @name_width = 16
      self.contents.clear
      self.contents.font.color = normal_color
      self.contents.draw_text(0,self.height / 2 - 32,self.width,32,SG_BrokenSave_Text,1)
      if !$scene.sg_saves_broken
        if $scene.is_a?(Scene_Save)
          p SG_BrokenSave_SavePop
        else
          p SG_BrokenSave_LoadPop
        end
        $scene.sg_saves_broken = true
      end
    end
  end
end

class Scene_Save < Scene_File
  attr_accessor :sg_saves_broken
end

class Scene_Load < Scene_File 
  attr_accessor :sg_saves_broken
  
  alias sandgolem_brokensavefix_load_ondecision on_decision
  def on_decision(filename)
    begin
      sandgolem_brokensavefix_load_ondecision(filename)
    rescue
      p SG_BrokenSave_Load
      $scene = Scene_Title.new
    end
  end
end

#--------------------------------------------------------------------------
end

The next one is an edit of Window_SaveFile that basically just changes some aesthetic things when saving and loading...
Code:
#==============================================================================
# â–  Window_SaveFile
#------------------------------------------------------------------------------
#  セーブ画面およびロード画面で表示する、セーブファイルのウィンドウです。
#==============================================================================

class Window_SaveFile < Window_Base
  #--------------------------------------------------------------------------
  # ● 公開インスタンス変数
  #--------------------------------------------------------------------------
  attr_reader   :filename                 # ファイル名
  attr_reader   :selected                 # 選択状態
  #--------------------------------------------------------------------------
  # ● オブジェクト初期化
  #     file_index : セーブファイルのインデックス (0~3)
  #     filename   : ファイル名
  #--------------------------------------------------------------------------
  def initialize(file_index, filename)
    super(0, 64 + file_index % 4 * 104, 640, 104)
    self.contents = Bitmap.new(width - 32, height - 32)
    self.contents.font.name = $fontface
    self.contents.font.size = $fontsize
    @game_party_leader = ""
    @file_index = file_index
    @filename = "Save#{@file_index + 1}.rxdata"
    @time_stamp = Time.at(0)
    @file_exist = FileTest.exist?(@filename)
    if @file_exist
      file = File.open(@filename, "r")
      @time_stamp = file.mtime
      
      
    @characters = Marshal.load(file)
    @frame_count = Marshal.load(file)
      
    @game_system = Marshal.load(file)
    @game_switches = Marshal.load(file)
    @game_variables = Marshal.load(file)
    @total_sec = @frame_count / Graphics.frame_rate
    
    @game_self_switches = Marshal.load(file)
    @game_screen        = Marshal.load(file)
    @game_actors        = Marshal.load(file)
    @game_party         = Marshal.load(file)
    @game_party_leader = @game_party.actors[0].name 
    file.close
      
      
  
    end
    refresh
    @selected = false
  end
  #--------------------------------------------------------------------------
  # ● リフレッシュ
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    # ファイル番号を描画
    self.contents.font.color = normal_color
    
    if @game_party_leader == ""
        name = "File #{@file_index + 1}"
    else
       name = "File #{@file_index + 1} : " + @game_party_leader
   end
    
    self.contents.draw_text(4, 0, 600, 32, name)
    @name_width = contents.text_size(name).width
    # セーブファイルが存在する場合
    if @file_exist
      # キャラクターを描画
      for i in 0...@characters.size
        bitmap = RPG::Cache.character(@characters[i][0], @characters[i][1])
        cw = bitmap.rect.width / 4
        ch = bitmap.rect.height / 4
        src_rect = Rect.new(0, 0, cw, ch)
        x = 300 - @characters.size * 32 + i * 64 - cw / 2
        self.contents.blt(x, 68 - ch, bitmap, src_rect)
      end
      # プレイ時間を描画
      hour = @total_sec / 60 / 60
      min = @total_sec / 60 % 60
      sec = @total_sec % 60
      time_string = sprintf("%02d:%02d:%02d", hour, min, sec)
      self.contents.font.color = normal_color
      self.contents.draw_text(4, 8, 600, 32, time_string, 2)
      # タイムスタンプを描画
      self.contents.font.color = normal_color
      time_string = @time_stamp.strftime("%Y/%m/%d %H:%M")
      self.contents.draw_text(4, 40, 600, 32, time_string, 2)
    end
  end
  #--------------------------------------------------------------------------
  # ● 選択状態の設定
  #     selected : 新しい選択状態 (true=選択 false=非選択)
  #--------------------------------------------------------------------------
  def selected=(selected)
    @selected = selected
    update_cursor_rect
  end
  #--------------------------------------------------------------------------
  # ● カーソルの矩形更新
  #--------------------------------------------------------------------------
  def update_cursor_rect
    if @selected
      self.cursor_rect.set(0, 0, @name_width + 8, 32)
    else
      self.cursor_rect.empty
    end
  end
end

If that helps at all, those are the only changes I can think of that deal with saving or loading.

Edit: I found one more script that could very well be part of the problem, there's even a part that says it prevents save errors. It's a map wrapping script, and I noticed the save errors usually happen on my wrapping map (though not always). Anyway, here it is:
Code:
#==============================================================================
# â–  Wrap_Map V2
#------------------------------------------------------------------------------
#  By Dirtie.
#   Allows chosen map(s) to "wrap-around", ie. go continuously.
#   Just add "_wrap" to the end of the map name for the map you want to be wrapped.
#   Many thanks to Rataime for all the event code, Dubealex for helping me out,
#   Deke for the map checker script, and to everyone else that contributed.
#==============================================================================

#--------------------------------------------------------------------------
# â–¼ CLASS Game_Temp (edit)
#      Script to check for "_wrap" in the map name.
#      This is taken and modified from Deke's Day/Night and Time System script.
#      If you would like to use something other than "_wrap" to check for,
#      change _wrap to whatever you want on lines 30 and 34
#--------------------------------------------------------------------------
class Game_Temp

 attr_reader    :map_infos
 attr_reader    :outside_array

 alias wrap_original_game_temp_initialize initialize

 def initialize
   wrap_original_game_temp_initialize
   @map_infos = load_data("Data/MapInfos.rxdata")
   @outside_array=Array.new
   for key in @map_infos.keys
     @outside_array[key]=@map_infos[key].name.include?("_wrap")
   end
   for key in @map_infos.keys
     @map_infos[key] = @map_infos[key].name
     @map_infos[key].delete!("_wrap")
   end
 end

end

#--------------------------------------------------------------------------
# â–¼ CLASS Game_Map (edit)
#      First, sets up the variable "wrap" for use in the event script later.
#      Then checks to see if "_wrap" is in the map name;
#      If not, uses default scrolling options for respective edge of map.
#      If so, tells viewport to keep scrolling in the respective direction when actor is near edge of map.
#--------------------------------------------------------------------------
class Game_Map

 attr_accessor :wrap

 alias wrap_original_game_map_scroll_left scroll_left
 alias wrap_original_game_map_scroll_right scroll_right
 alias wrap_original_game_map_scroll_up scroll_up
 alias wrap_original_game_map_scroll_down scroll_down

# Left
 def scroll_left(distance)
   unless $game_temp.outside_array[$game_map.map_id]
     wrap_original_game_map_scroll_left(distance)
   else
     @display_x = [@display_x - distance].max
   end
 end

# Right
 def scroll_right(distance)
   unless $game_temp.outside_array[$game_map.map_id]
     wrap_original_game_map_scroll_right(distance)
   else
     @display_x = [@display_x + distance].min
   end
 end

# Top
 def scroll_up(distance)
   unless $game_temp.outside_array[$game_map.map_id]
     wrap_original_game_map_scroll_up(distance)
   else
     @display_y = [@display_y - distance].max
   end
 end

# Bottom
 def scroll_down(distance)
   unless $game_temp.outside_array[$game_map.map_id]
     wrap_original_game_map_scroll_down(distance)
   else
     @display_y = [@display_y + distance].min
  end
 end

end

#--------------------------------------------------------------------------
# â–¼ CLASS Game_Player (edit)
#      Makes sure viewport stays centered on player, particularly when teleporting near edges.
#--------------------------------------------------------------------------
class Game_Player

 alias wrap_original_game_player_center center

 def center(x, y)
   unless $game_temp.outside_array[$game_map.map_id]
     wrap_original_game_player_center(x, y)
   else
     max_x = ($game_map.width + 20) * 128
     max_y = ($game_map.height + 15) * 128
     $game_map.display_x = [-20 * 128, [x * 128 - CENTER_X, max_x].min].max
     $game_map.display_y = [-15 * 128, [y * 128 - CENTER_Y, max_y].min].max
   end
 end

end

#--------------------------------------------------------------------------
# â–¼ CLASS Check_Coordinates
#      Checks for coordinates and keyboard input, then teleports if conditions are met.
#--------------------------------------------------------------------------
class Check_Coordinates

#------------------------------------------------------------------------
# ● Handles left edge
#------------------------------------------------------------------------
 def refresh_left
   unless $game_temp.outside_array[$game_map.map_id]
   else
     if $game_player.real_x == 0
       if Input.press?(Input::LEFT)
         def $game_player.passable?(x, y, d)
           return true
         end
         @left_trigger = true
       end
     end
   end
 end
 
#------------------------------------------------------------------------
# ● Handles right edge
#------------------------------------------------------------------------
 def refresh_right
   unless $game_temp.outside_array[$game_map.map_id]
   else
     @map_width_max = ($game_map.width - 1) * 128
     if $game_player.real_x == @map_width_max
       if Input.press?(Input::RIGHT)
         def $game_player.passable?(x, y, d)
           return true
         end
         @right_trigger = true
       end
     end
   end
 end

#------------------------------------------------------------------------
# ● Handles top edge
#------------------------------------------------------------------------
 def refresh_top
   unless $game_temp.outside_array[$game_map.map_id]
   else
     if $game_player.real_y == 0
       if Input.press?(Input::UP)
         def $game_player.passable?(x, y, d)
           return true
         end
         @top_trigger = true
       end
     end
   end
 end

#------------------------------------------------------------------------
# ● Handles bottom edge
#------------------------------------------------------------------------
 def refresh_bottom
   unless $game_temp.outside_array[$game_map.map_id]
   else
     @map_height_max = ($game_map.height - 1) * 128
     if $game_player.real_y == @map_height_max
       if Input.press?(Input::DOWN)
         def $game_player.passable?(x, y, d)
           return true
         end
         @bottom_trigger = true
       end
     end
   end
 end

#------------------------------------------------------------------------
# ● Left teleport
#------------------------------------------------------------------------
 def left_trigger
   if @left_trigger == true
     if $game_player.real_x == -128
       $game_player.moveto(($game_map.width - 1), $game_player.y)
       def $game_player.passable?(x, y, d)
         new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
         new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
         unless $game_map.valid?(new_x, new_y)
           return false
         end
         if $DEBUG and Input.press?(Input::CTRL)
           return true
         end
         super
       end
       @left_trigger = false
     end
   end
 end

#------------------------------------------------------------------------
# ● Right teleport
#------------------------------------------------------------------------
 def right_trigger
   if @right_trigger == true
     if $game_player.real_x == ($game_map.width * 128)
       $game_player.moveto(0, $game_player.y)
       def $game_player.passable?(x, y, d)
         new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
         new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
         unless $game_map.valid?(new_x, new_y)
           return false
         end
         if $DEBUG and Input.press?(Input::CTRL)
           return true
         end
         super
       end
       @right_trigger = false
     end
   end
 end

#------------------------------------------------------------------------
# ● Top teleport
#------------------------------------------------------------------------
 def top_trigger
   if @top_trigger == true
     if $game_player.real_y == -128
       $game_player.moveto($game_player.x, ($game_map.height - 1))
       def $game_player.passable?(x, y, d)
         new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
         new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
         unless $game_map.valid?(new_x, new_y)
           return false
         end
         if $DEBUG and Input.press?(Input::CTRL)
           return true
         end
         super
       end
       @top_trigger = false
     end
   end
 end

#------------------------------------------------------------------------
# ● Bottom teleport
#------------------------------------------------------------------------
 def bottom_trigger
   if @bottom_trigger == true
     if $game_player.real_y == ($game_map.height * 128)
       $game_player.moveto($game_player.x, 0)
       def $game_player.passable?(x, y, d)
         new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
         new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
         unless $game_map.valid?(new_x, new_y)
           return false
         end
         if $DEBUG and Input.press?(Input::CTRL)
           return true
         end
         super
       end
       @bottom_trigger = false
     end
   end
 end

end

#--------------------------------------------------------------------------
# â–¼ CLASS Sprite_Duplicate
#      A copy of the Sprite_Character class, with some adjustments made.
#      Used to create the duplicate event sprites.
#--------------------------------------------------------------------------
class Sprite_Duplicate < RPG::Sprite

 attr_accessor :character # @character is the original event
 
 def initialize(viewport, character = nil, x = 0, y = 0)
   @x = x
   @y = y
   super(viewport)
   @character = character
   @z=@character.screen_z
   update
 end

 def update
   super
   if @tile_id != @character.tile_id or
     @character_name != @character.character_name or
     @character_hue != @character.character_hue
       @tile_id = @character.tile_id
       @character_name = @character.character_name
       @character_hue = @character.character_hue
       if @tile_id >= 384
         self.bitmap = RPG::Cache.tile($game_map.tileset_name, @tile_id, @character.character_hue)
         self.src_rect.set(0, 0, 32, 32)
         self.ox = 16
         self.oy = 32
       else
         self.bitmap = RPG::Cache.character(@character.character_name, @character.character_hue)
         @cw = bitmap.width / 4
         @ch = bitmap.height / 4
         self.ox = @cw / 2
         self.oy = @ch
       end
   end
   self.visible = (not @character.transparent)
   if @tile_id == 0
     sx = @character.pattern * @cw
     sy = (@character.direction - 2) / 2 * @ch
     self.src_rect.set(sx, sy, @cw, @ch)
   end
   # The coordinates of the duplicate event sprite. They are relative to the original event,
   # so the duplicates will move and act as the original does; except the z coordinate,
   # as when the original sprite would be of range, the duplicate would not appear.
   self.x = @character.screen_x + @x
   self.y = @character.screen_y + @y
   self.z = @z
   self.opacity = @character.opacity
   self.blend_type = @character.blend_type
   self.bush_depth = @character.bush_depth
   if @character.animation_id != 0
     animation = $data_animations[@character.animation_id]
     animation(animation, true)
     @character.animation_id = 0
   end
 end

end

#--------------------------------------------------------------------------
# â–¼ CLASS Sprite_Character (edit)
#      Used to create the duplicate sprites.
#--------------------------------------------------------------------------
class Sprite_Character < RPG::Sprite

 alias wrap_original_sprite_character_initialize initialize
 alias wrap_original_sprite_character_update update

 def initialize(viewport, character = nil)
   unless $game_temp.outside_array[$game_map.map_id]
     wrap_original_sprite_character_initialize(viewport, character)
   else
     @character = character
     super(viewport)
     if $game_map.wrap == nil
       $game_map.wrap = []
     end
     # 8 duplicates are created, stored in the $game_map.wrap array
     if character.is_a?(Game_Event)
       $game_map.wrap.push(Sprite_Duplicate.new(viewport, character, (-$game_map.width * 32), 0))
       $game_map.wrap.push(Sprite_Duplicate.new(viewport, character, 0, (-$game_map.height * 32)))
       $game_map.wrap.push(Sprite_Duplicate.new(viewport, character, ($game_map.width * 32), 0))
       $game_map.wrap.push(Sprite_Duplicate.new(viewport, character, 0, ($game_map.height * 32)))
       $game_map.wrap.push(Sprite_Duplicate.new(viewport, character, (-$game_map.width * 32), (-$game_map.height * 32)))
       $game_map.wrap.push(Sprite_Duplicate.new(viewport, character, ($game_map.width * 32), ($game_map.height * 32)))
       $game_map.wrap.push(Sprite_Duplicate.new(viewport, character, (-$game_map.width * 32), ($game_map.height * 32)))
       $game_map.wrap.push(Sprite_Duplicate.new(viewport, character, ($game_map.width * 32), (-$game_map.height * 32)))
     end
     wrap_original_sprite_character_initialize(viewport, @character)
   end
 end

#------------------------------------------------------------------------
# ● Updates each sprite in the $game_map.wrap array
#------------------------------------------------------------------------
 def update
   unless $game_temp.outside_array[$game_map.map_id]
     wrap_original_sprite_character_update
   else
     wrap_original_sprite_character_update
     if $game_map.wrap != [] and character.is_a?(Game_Player)
       for duplicate in $game_map.wrap
         if duplicate != nil
           duplicate.update
         end
       end
     end
   end
 end

end

#--------------------------------------------------------------------------
# â–¼ CLASS Spriteset_Map (edit)
#      Prevents "disposed sprite" errors
#--------------------------------------------------------------------------

class Spriteset_Map

 alias wrap_original_spriteset_map_initialize initialize

 def initialize
   $game_map.wrap=nil
   wrap_original_spriteset_map_initialize
 end
 
end

#--------------------------------------------------------------------------
# â–¼ CLASS Scene_Save (edit)
#      Prevent save errors
#--------------------------------------------------------------------------
class Scene_Save < Scene_File

 alias wrap_original_scene_save_write_save_data write_save_data

 def write_save_data(file)
   $game_map.wrap = nil
   wrap_original_scene_save_write_save_data(file)
 end
 
end

#--------------------------------------------------------------------------
# â–¼ CLASS Scene Map (edit)
#      Initiates a loop for the methods of the Check_Coordinates class
#--------------------------------------------------------------------------
class Scene_Map

 $coordinate_check = Check_Coordinates.new
 
 alias wrap_original_scene_map_update update
 
 def update
   unless $game_temp.outside_array[$game_map.map_id]
     wrap_original_scene_map_update
   else
     $coordinate_check.refresh_left
     $coordinate_check.refresh_right
     $coordinate_check.refresh_top
     $coordinate_check.refresh_bottom
     $coordinate_check.left_trigger
     $coordinate_check.right_trigger
     $coordinate_check.top_trigger
     $coordinate_check.bottom_trigger
     wrap_original_scene_map_update
   end
 end
end
 

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