rey meustrus
Sponsor
Advanced Error Handling
Version: 1.2
Introduction
Ever run into a stupid error? Maybe when beta-testing, or even in a final product? Lost your save file? That's what this is for. Advanced Error Checking enables the game to skip small errors per-frame, for when the scripter failed to check for the errors, or when something really weird happens that nobody accounted for. It also writes all errors to a log file, which makes it much easier for testers to explain their errors, and for scripters to fix them (it also writes the entire backtrace of the error).
The error skipping only occurs when not running a test play from within RMXP (controlled by the internal variable $DEBUG). During test plays, it won't skip any errors; this is useful for scripters trying to catch their errors since the editor only points to that point in the scripts if the game closes to that error.
This script was inspired by the functionality provided by Zeriab's code snippet, on which this is based. It's really a bit of a small script, based mostly around skipping small errors (those that don't occur every frame) and avoiding nasty unintentional recursion (method Exception.to_s calls the method write_to_log, which calls full_message, which calls message_with_backtrace, which calls an aliased to_s...complicated, eh?).
Screenshots
(this script can't be well described with screenshots)
Script
[rgss]class Exception
 # prevents infinite loops by aliasing the original message
 alias to_string :to_s
 #--------------------------------------------------------------------------
 # * Only called from internal error checking; writes log and adds backtrace
 #--------------------------------------------------------------------------
 def to_s
  write_to_log # Note that the log calls :full_message, which calls to_string
  return message_with_backtrace
 end
 #--------------------------------------------------------------------------
 # * Returns the error message with accompanying backtrace
 #--------------------------------------------------------------------------
 def message_with_backtrace
  return to_string + backtrace_string
 end
 #--------------------------------------------------------------------------
 # * Generate the backtrace string from a range of its values
 #--------------------------------------------------------------------------
 def backtrace_string(range = nil)
  return "" if backtrace == nil or backtrace.length <= 0
  range = 0...backtrace.length unless range.is_a?(Range)
  output = "\n\nBacktrace:\n"
  for i in range
   output += backtrace_item(i, true) + "\n"
  end
  return output
 end
 #--------------------------------------------------------------------------
 # * Generate a string from an individual item in the backtrace
 #--------------------------------------------------------------------------
 def backtrace_item(i, show_method = false)
  return "" if backtrace == nil
  method = backtrace.gsub(/Section(\d*)
\d*)/) {}
  output = "'%s' line %d" % [$RGSS_SCRIPTS[$1.to_i][1], $2]
  output += method.sub(':', ' ') if show_method
  return output
 end
 #--------------------------------------------------------------------------
 # * Returns what raising an error displays
 #--------------------------------------------------------------------------
 def full_message
  # Finds script and line number
  error = "Script " + backtrace_item(0) + ": #{self.class} occured.\n\n"
  return error + self.message_with_backtrace
 end
 #--------------------------------------------------------------------------
 # * Write the error to the log file
 #--------------------------------------------------------------------------
 def write_to_log
  return if @written # Only write log once
  file = File.open('ErrorLog.log', File::CREAT|File::APPEND|File::WRONLY)
file.print Time.now
file.print "\n--------------------------------------------------------\n"
  file.print full_message
  file.print "\n========================================================\n"
  file.close
  @written = true
 end
 #--------------------------------------------------------------------------
 # * Is this error fatal? (redefine for other exceptions)
 #--------------------------------------------------------------------------
 def fatal?
  return true
 end
end
Â
def StandardError.fatal? ; return false ; end
Â
class NameError < StandardError
 alias to_string :to_s
 def to_s ;super ; end
end
Â
class SystemExit < Exception
 def to_s ; return message_with_backtrace ; end
end
Â
class Object
 #--------------------------------------------------------------------------
 # * Advanced error checking for methods - provide method as a symbol
 #--------------------------------------------------------------------------
 def error_wrapper(symbol)
  # Create the record of whether there's been an error last time checked
  if @_error == nil
   @_error = {}
  end
  # If in debug mode, or there was an error last time we ran this method
  if $DEBUG or @_error[symbol]
   # Run the method and, after getting no errors, reset error check
   send symbol
   @_error[symbol] = false
  else # If there was no error last time we ran this method
   begin
    send symbol
   rescue
    # Catch errors and provide feedback; set checker for each-frame errors
    print $!.full_message if $DEBUG or $!.fatal?
    $!.write_to_log
    exit(1) if $!.fatal?
    @_error[symbol] = true
   end
  end
 end
end
[/rgss]
Instructions
First, install the script above. Then, to activate the script, you need to modify your Scene classes.
For XP, with the SDK installed with part 3 (SDK::Scene_Base), find where it says:
[rgss]   loop do            # Scene Loop
   main_loop          # Main Loop      <========This line, replace with error_wrapper
main_loop)
   break if main_break?     # Break If Breakloop Test
  end              # End Scene Loop
[/rgss]
Without SDK installed, you need to manually go through each Scene class you want it installed in, and change this:
[rgss] Â Â # Main loop
  loop do
   # Update game screen
   Graphics.update
   # Update input information
   Input.update
   # Frame update
   update        #<======== Change this to error_wrapper
update)
   # Abort loop if screen is changed
   if $scene != self
    break
   end
  end
[/rgss]
For RPG Maker VX, change this in Scene_Base:
[rgss] Â Â loop do
   Graphics.update       # Update game screen
   Input.update         # Update input information
   update            # Update frame   <======== Change this to error_wrapper
update)
   break if $scene != self   # When screen is switched, interrupt loop
  end
Â
[/rgss]
Compatibility
This should work with anything and everything, although it may be disabled by some other non-SDK RMXP scripts, or interfere with anything that messes with the Exception class.
Credits and Thanks
The inspiration and foundation for this script was provided by Zeriab in the Scripter's Corner thread. I'm assuming he's OK with this going out, since I'm not trying to repackage his script, nor am I trying to become a big celebrity for this. Just another useful tool provided by the various scripters on RMXP.org working together.
Version: 1.2
Introduction
Ever run into a stupid error? Maybe when beta-testing, or even in a final product? Lost your save file? That's what this is for. Advanced Error Checking enables the game to skip small errors per-frame, for when the scripter failed to check for the errors, or when something really weird happens that nobody accounted for. It also writes all errors to a log file, which makes it much easier for testers to explain their errors, and for scripters to fix them (it also writes the entire backtrace of the error).
The error skipping only occurs when not running a test play from within RMXP (controlled by the internal variable $DEBUG). During test plays, it won't skip any errors; this is useful for scripters trying to catch their errors since the editor only points to that point in the scripts if the game closes to that error.
This script was inspired by the functionality provided by Zeriab's code snippet, on which this is based. It's really a bit of a small script, based mostly around skipping small errors (those that don't occur every frame) and avoiding nasty unintentional recursion (method Exception.to_s calls the method write_to_log, which calls full_message, which calls message_with_backtrace, which calls an aliased to_s...complicated, eh?).
Screenshots
(this script can't be well described with screenshots)
Script
[rgss]class Exception
 # prevents infinite loops by aliasing the original message
 alias to_string :to_s
 #--------------------------------------------------------------------------
 # * Only called from internal error checking; writes log and adds backtrace
 #--------------------------------------------------------------------------
 def to_s
  write_to_log # Note that the log calls :full_message, which calls to_string
  return message_with_backtrace
 end
 #--------------------------------------------------------------------------
 # * Returns the error message with accompanying backtrace
 #--------------------------------------------------------------------------
 def message_with_backtrace
  return to_string + backtrace_string
 end
 #--------------------------------------------------------------------------
 # * Generate the backtrace string from a range of its values
 #--------------------------------------------------------------------------
 def backtrace_string(range = nil)
  return "" if backtrace == nil or backtrace.length <= 0
  range = 0...backtrace.length unless range.is_a?(Range)
  output = "\n\nBacktrace:\n"
  for i in range
   output += backtrace_item(i, true) + "\n"
  end
  return output
 end
 #--------------------------------------------------------------------------
 # * Generate a string from an individual item in the backtrace
 #--------------------------------------------------------------------------
 def backtrace_item(i, show_method = false)
  return "" if backtrace == nil
  method = backtrace.gsub(/Section(\d*)
  output = "'%s' line %d" % [$RGSS_SCRIPTS[$1.to_i][1], $2]
  output += method.sub(':', ' ') if show_method
  return output
 end
 #--------------------------------------------------------------------------
 # * Returns what raising an error displays
 #--------------------------------------------------------------------------
 def full_message
  # Finds script and line number
  error = "Script " + backtrace_item(0) + ": #{self.class} occured.\n\n"
  return error + self.message_with_backtrace
 end
 #--------------------------------------------------------------------------
 # * Write the error to the log file
 #--------------------------------------------------------------------------
 def write_to_log
  return if @written # Only write log once
  file = File.open('ErrorLog.log', File::CREAT|File::APPEND|File::WRONLY)
file.print Time.now
file.print "\n--------------------------------------------------------\n"
  file.print full_message
  file.print "\n========================================================\n"
  file.close
  @written = true
 end
 #--------------------------------------------------------------------------
 # * Is this error fatal? (redefine for other exceptions)
 #--------------------------------------------------------------------------
 def fatal?
  return true
 end
end
Â
def StandardError.fatal? ; return false ; end
Â
class NameError < StandardError
 alias to_string :to_s
 def to_s ;super ; end
end
Â
class SystemExit < Exception
 def to_s ; return message_with_backtrace ; end
end
Â
class Object
 #--------------------------------------------------------------------------
 # * Advanced error checking for methods - provide method as a symbol
 #--------------------------------------------------------------------------
 def error_wrapper(symbol)
  # Create the record of whether there's been an error last time checked
  if @_error == nil
   @_error = {}
  end
  # If in debug mode, or there was an error last time we ran this method
  if $DEBUG or @_error[symbol]
   # Run the method and, after getting no errors, reset error check
   send symbol
   @_error[symbol] = false
  else # If there was no error last time we ran this method
   begin
    send symbol
   rescue
    # Catch errors and provide feedback; set checker for each-frame errors
    print $!.full_message if $DEBUG or $!.fatal?
    $!.write_to_log
    exit(1) if $!.fatal?
    @_error[symbol] = true
   end
  end
 end
end
[/rgss]
Instructions
First, install the script above. Then, to activate the script, you need to modify your Scene classes.
For XP, with the SDK installed with part 3 (SDK::Scene_Base), find where it says:
[rgss]   loop do            # Scene Loop
   main_loop          # Main Loop      <========This line, replace with error_wrapper
   break if main_break?     # Break If Breakloop Test
  end              # End Scene Loop
[/rgss]
Without SDK installed, you need to manually go through each Scene class you want it installed in, and change this:
[rgss] Â Â # Main loop
  loop do
   # Update game screen
   Graphics.update
   # Update input information
   Input.update
   # Frame update
   update        #<======== Change this to error_wrapper
   # Abort loop if screen is changed
   if $scene != self
    break
   end
  end
[/rgss]
For RPG Maker VX, change this in Scene_Base:
[rgss] Â Â loop do
   Graphics.update       # Update game screen
   Input.update         # Update input information
   update            # Update frame   <======== Change this to error_wrapper
   break if $scene != self   # When screen is switched, interrupt loop
  end
Â
[/rgss]
Compatibility
This should work with anything and everything, although it may be disabled by some other non-SDK RMXP scripts, or interfere with anything that messes with the Exception class.
Credits and Thanks
The inspiration and foundation for this script was provided by Zeriab in the Scripter's Corner thread. I'm assuming he's OK with this going out, since I'm not trying to repackage his script, nor am I trying to become a big celebrity for this. Just another useful tool provided by the various scripters on RMXP.org working together.