Vai al contenuto

Rilevato Ad-Blocker. Per favore disabilita il tuo adblocker quando navighi su makerando.com - Non c'è nessun annuncio invasivo.

  • Chatbox

    You don't have permission to chat.
    Load More
Ally

Bugfix Referenze Globali Oggetti Grafici

Recommended Posts

Nome Script: Referenze Globali Oggetti Grafici
Versione: 1.1
Autore/i: Mithran

Informazioni:
Topic originale: Graphical Object Global Reference (inglese)

Il Game.exe continua a crashare in maniera casuale e talvolta controllata?
"Game.exe ha riscontrato un problema e verrà terminato"

Questo è uno degli errori più frustranti di RPG Maker VX con cui fare i conti, visto che sembra andare e venire a caso, solo per determinate persone o a certe condizioni, e la causa del problema ti è ignota.

Se il tuo progetto riscontra frequenti crash del Game.exe, questa lettura potrà esserti utile. Oddio, anche se non ti crasha può essere utile leggerla. Questo script si occupa di uno specifico problema che causa questi crash.


La causa di crash del Game.exe può essere dovuta a un sacco di cose - essa non dipende da errori un Ruby, ma da eccezioni non gestite in una delle classi 'nascoste'.

Dopo pesanti sessioni di testing, l'autore è riuscito finalmente a ricreare le circostanze che portavano ad alcune di queste eccezioni causanti crash.

1. Un "GO" - Graphical Object, Oggetto Grafico (Sprite, Window, Plane, o Tilemap) viene creato
2. Il GO viene assegnato a un Viewport
3. Il Viewport viene disposto, ma non lo sprite
4. Il GO viene interpellato dal GC (Garbage Collector)*

* - Nuova scoperta: disporre uno sprite che ha un Viewport disposto, crasherà occasionalmente. (v 1.1)
Nota che questo particolare crash occorre se lo schermo è stato disegnato (da uno dei metodi di Graphics) mentre il Viewport era disposto e si provava a disporre lo sprite.

Per il modo in cui il GC è implementato, non vedrai subito l'effetto. Ci possono essere diversi cambi di scene prima che il crash arrivi. A peggiorare le cose, seguire lo stesso corso di azioni che avevano portato al crash, darà risultati del tutto diversi, facendoli sembrare del tutto casuali. In più, c'è un'altra circostanza che l'autore non è riuscito ancora a delineare, sospetta abbia a che fare con l'ordine in cui il GC gestisca i GO, o che il numero di volte che lo schermo è stato ridisegnato influisca in tutto ciò.

In sostanza: puoi avere un gioco instabile e neppure saperlo.

Quindi questo script verrà in aiuto. Assolverà i seguenti compiti:

1. Creare una referenza globale per ogni GO.
In questo modo il GC saprà come comportarsi e si eviteranno crash.

2. Rimuovere le referenze ai GO una volta disposti.
Ancora una volta per il corretto funzionamento del GC. Visto che il GO è disposto, la condizione 3 non si riscontrerà.

3. Riportare potenziali problemi all'utente.
In questo modo saranno identificabili e sistemabili.

4. Prevenire quindi i crash del Game.exe relativi a questo.
È incluso un fix 'pigro' che pulisce i GO al cambio scena.*

* v 1.1 Il fix 'pigro' ha subito modifiche e interviene soltanto se è disabilitato il debug critical disposal.

Cronologia:

v 1.1
Scoperta una nuova condizione di crash. Aggiornato lo script per correggerla e notificarla.

v 1.01-1.05
Piccoli fix, migliorato il sistema di notifiche (log), aggiunta considerazione per i Plane

v 1.0
Release iniziale



Features:
- identifica e permette di risolvere una delle più rilevanti cause di crash del Game.exe;
- crea una referenza globale per ogni oggetto grafico creato finché non viene disposto, per prevenire che errori causino il crash

Istruzioni:
Incolla lo script in una nuova voce creata sotto Materials. Se usi script che creano grafica all'avvio (es. Woratana Simple Mouse System), questo script dovrà stare sotto ad essi.

Script:


# Graphical Object Global Reference
# v 1.1
# A debugger script.
# Created by Mithran
# hosted at rpgmakervx.net; forums.rpgmakerweb.com

# Created to address the issue of specific Game.exe crashes during play

%q(
The cause of a given Game.exe crash could be any number of things - anything that
doesn't create throw an error in Ruby, but causes an unhandled exception in one
of the 'hidden' classes.

After extensive testing, I was finally able to recreate the circumstances leading
up to one such exception that, if left unhandled, could lead to Game.exe crash.  

1. A "GO" - Graphical Object (Sprite, Window, Plane, or Tilemap) is created
2. The Graphical Object is assigned a Viewport
3. The Viewport is disposed, but the sprite is not
4. The Graphical Object is claimed by GC (garbage disposal)*

* - Newly Discovered: attempting to dispose a sprite that has a disposed viewport
    will occasionally also crash. (v 1.1)
    Note that this particuar crash only seems to occur if screen draws have taken
    place (any of the Graphics methods) between the time the viewport is disposed
    and the sprite disposal is attempted.

Due to the way GC is implemented, you are unlikely to see an immediate effect
when the situation comes up.  It could be several scene changes down the line
before the crash finally happens.  To make matters worse, following the exact
same course of action will yield completely different results, making it seem
as though the crashes are random.  In addition, there is yet another circumstance
which I have still been unable to pinpoint, but I suspect has something to do
with the order in which assets associated with the Graphical Object are claimed
by the GC, or the amount of screen rewdraws that have taken place,
that allows the GO to be cliamed without causing an exception and
thus making it even harder to find.

In essence: you could be suffering from an unstable game and not even know it.

So that is where this little script comes in.  This does the following:

1. Creates a global variable backreference to every Graphical Object created.
  This prevents them from being marked by the GC so long as the reference exists,
  circumventing the final condition to cause this version of the crash.

2. Removes reference to the Graphical Object once it has been disposed.
  This reallows the object to be marked by GC for disposal (once all other
  references are removed).  Since the GO is disposed, condition 3 is no longer met
  and the object is deemed 'safe'.

3. Report on potential issues to the user.
  This allows the user (given limited scripting knowledge) to identify potential
  errors and fix them outright.

4. Prevents further Game.exe crashes caused by this specific issue.
  Includes a 'lazy' fix that cleans up offending Graphical Objects when the scene
  changes.*

* v 1.1 'Lazy' fix has been superceeded to prevent crashes caused by disposal of
    these errant sprites.  Lazy fix only works if debug criticial disposal has
    been disabled.

Version History:

v 1.1
  Discovered a new condition for a Game.exe crash.  Updated script to trap and log
  this error also.

v 1.01-1.05
  Minor bugfixes, improved logging, added consideration for Plane objects viewport method error

v 1.0
  Initial Release

)
# Creates a global refrence list to all graphical objects, preventing them from
# ever being garbage collected.  Objects from this list are removed when the object
# runs its dispose method, thereby allowing them to be GC'd.  

# Has a built in layer to notify the player if the scene changes with live
# graphical objects in play.  As a rule, this should almost never happen.  Certain
# scripts have sprites that are used across every scene and never disposed,
# thus intentionally having an additional global reference (such as mouse script)
# As such, they should never generate a critical error.  However, they can be manually
# exempted from being detected by this script by using the instance method
# 'gobj_exempt' on the sprite.  In the case of Woratana's Simple Mouse/Jets Mouse
# simply place my script as low as possible on the scripts list, but above Main,
# to avoid conflicts.

GOBJ_NOTIFY_LEAK = false # when true, displays a list of undisposed graphical objects
# every time the scene changes.  This includes all graphical objects

GOBJ_NOTIFY_CRITICAL = false # when true, displays information regarding critical
# graphical object disposal oversights on scene switch.  These are the errors
# that could otherwise turn into a Game.exe crash.

# The above two options print a message directly to the screen.

GOBJ_DEBUG_FILE = true # makes a file (gobj.txt) in the game directory containing
# information about new critcal objects whenever a scene switches
# the list includes:
# the time the error was recorded
# the object's class and ID
# the scene it was created during (NilClass = in a script before any scene was created)
# and the 'caller', or the list of methods run prior to this object's creation
# the first line on caller will generally be the location of where the
# offending object was initially CREATED
# HOWEVER, the error this script addresses is that this object is never DISPOSED
# of properly.  Knowing where the object will only allow a scripter to go back
# and properly dispose of the object at the correct time.

GOBJ_LOG_NON_CRITICAL = true
# if set to true creates log entries for non-critical objects that are not disposed
# between scenes.  Only works if GOBJ_DEBUG_FILE is also set to true.
# if you have a game.exe crash that seems to pop up randomly after a while
# try using this and see if there are any unfreed objects at all

GOBJ_LAZY = false
# turn this to true and graphical objects with disposed viewports will be disposed
# when the scene changes.  It is recommended this setting not be used and instead
# the code be cleaned up directly.
# v 1.1 This function has been superceeded by below.  
# Sprites must be kept in memory to prevent a crash if their viewport has already
# been disposed.
# Note this only seems to occur if screen redraws have occured between the time
# of viewport disposal and sprite disposal

GOBJ_DEBUG_CRITICAL_DISPOSAL = false
# disables disposal of GO that have had their viewports already disposed
# this is only considered unsafe if screen redraws have taken place between the
# time that the viewport and sprite are disposed.
# Some of the base scripts dispose viewport immediately before the sprites, which
# has never been known to cause errors, therefore, this option has been added to
# circumvent dealing with these type of objects.  Turn this on if you continue
# to get Game.exe crashes that are not logged.


# --- End Setup
  $gobj = []


[Sprite, Plane, Window, Tilemap].each { |cl|
class << cl
  alias new_gobj new unless $@
  def new(*args)
    obj = new_gobj(*args)
    ary = [obj, $scene.class]
    ary.push(caller) if GOBJ_DEBUG_FILE # add caller list if debug file is enabled
    # if object is disposed already during initialization, dont add it
    $gobj.push(ary) unless obj.disposed?
    obj
  end

end

cl.class_eval {

  alias dispose_gobj dispose unless $@
  def dispose
    if GOBJ_DEBUG_CRITICAL_DISPOSAL && viewport && viewport.disposed?
      o = $gobj.find { |a| a[0] == self }
      print "#{o[0]} created in #{o[1]} is attempting to dispose with a disposed viewport!" if GOBJ_NOTIFY_CRITICAL
      if GOBJ_DEBUG_FILE && !o[3]
        gobj_log_to_file(o, true)
        o[3] = true
      end
      return
    end
    gobj_exempt   # remove from global reference
    dispose_gobj # original dispose
  end

  def gobj_exempt
    $gobj.delete_if { |a| a[0] == self }
  end

} # class eval

} # each class

class Scene_Base
  alias main_gobj main unless $@
  def main
    if !@gobj && $TEST && $gobj.size > 0
      p 'Live Graphical Object List:', $gobj.collect { |o| o[0..1] } if GOBJ_NOTIFY_LEAK
      $gobj.clone.each { |o|
      next o[0].gobj_exempt if o[0].disposed?
      critical = o[0].viewport && o[0].viewport.disposed?
      print "#{o[0]} created in #{o[1]} is a potential for Game.exe crash!" if GOBJ_NOTIFY_CRITICAL && critical
      if GOBJ_DEBUG_FILE && !o[3] && (critical or GOBJ_LOG_NON_CRITICAL)
        gobj_log_to_file(o, critical)
        o[3] = true # do not log again this instance
      end
      if GOBJ_LAZY && critical
        o[0].dispose
      end
      } # close $gobj.each
      @gobj = true # once per run of this specfic scene object
    end # debug branch
    main_gobj  #original method
  end


end

module Kernel

  def gobj_log_to_file(o, critical)
    File.open("gobj.txt", "a") { |f|
    f.print "\n-----\n"
    f.print("Time: #{Time.now}\n")
    f.print("#{critical ? '' : 'Non-'}Critical Object #{o[0]}\n")
    f.print("In Scene #{o[1]}\n")
    f.print("Caller:: \n")
    o[2].each { |e| e.gsub!(/Section(\d+)\\d+)/i) { |m|
    "Script #{$1} -- #{ScriptNames[$1.to_i]}, Line: #{$2}" }
    } # close o[2].each
    outp = o[2].join("\n")
    f.print(outp)
    } # close file
  end

end

class Viewport
  alias dispose_gobj dispose unless $@
  def dispose
    @disposed = true
    dispose_gobj
  end

  def disposed?
    @disposed
  end

end

class Plane
  # Plane#viewport methods do not work correctly
  # Plane#viewport takes an argument and SETS the viewport
  # while Plane#viewport= is not defined at all
  # fixed to work like sprite, window and Tilemap

  alias viewport= viewport unless $@
  alias viewport_set viewport unless $@
  def viewport=(vp)
    @viewport = vp
    viewport_set(vp)
  end

  def viewport
    @viewport
  end

  alias initialize_vpfix initialize
  def initialize(vp = nil)
    @viewport = vp
    initialize_vpfix(vp)
  end

end

ScriptNames = {}

load_data("Data/Scripts.rvdata").each_with_index {|s, i| ScriptNames[i] = s[1] }

http://pastebin.com/raw.php?i=rW9qkbxT

Incompatibilità:
D: Il Game.exe crasha costantemente e questo script non aiuta!
R: Come spiegato, questo script risolve solo determinati motivi circoscritti del crash. Non tutti i motivi di crash vengono risolti. Può essere utile lasciare un post con dettagli dell'errore, come dice Mithran nel topic originale, ma magari sarebbe da farglieli notare proprio lì.

D: Uso una versione crackata e...
R: Nessun supporto per versioni non ufficiali.

D: Ho trovato un modo di forzare un crash al Game.exe in un gioco che sembra stabile.
R: Posta i dettagli, che interessano!

Se riscontri errori, per favore provvedi informazioni complete di questi assieme a una breve spiegazione di come riprodurli (nel topic originale, magari).

Note dell'autore:
Con un link al post originale (inglese) e con i dovuti crediti, lo script originale senza modifiche può essere ripubblicato su altri forum. Può essere utilizzato in ogni progetto, a patto che rimangano i crediti nello script tali e quali (i crediti nell'insieme nel progetto non sono richiesti).
Mithran, autore dello script.

Condividi questo messaggio


Link di questo messaggio
Condividi su altri siti

Crea un account o accedi per lasciare un commento

You need to be a member in order to leave a comment

Crea un account

Iscriviti per un nuovo account nella nostra comunità. È facile!

Registra un nuovo account

Accedi

Sei già registrato? Accedi qui.

Accedi Ora

  • Contenuti simili

    • Da KenzaMe92
      Nome Script: KZM - Cura Totale su Level Up
      Versione: 1.0
      Autore:
      Descrizione:
      Questo script permette di recuperare vita e mana e curare stati alterati salendo di livello.
       
      Istruzioni:
      Installare sotto "▼ Materiali" e sopra "▼ Processo Iniziale".
       
      Screenshot:
      Non Servono
       
      Script:
       
       
       
      Bug e Conflitti Noti:
      Nessuno
       
      Note dell'autore:
      Condividetelo, usatelo nei vostri progetti free o commerciali, l'importante è creditare l'autore.
    • Da KenzaMe92
      Nome Script: KZM - Cura su Level Up
      Versione: 1.0
      Autore:
      Descrizione:
      Questo script permette di recuperare vita e mana salendo di livello.
       
      Istruzioni:
      Installare sotto "▼ Materiali" e sopra "▼ Processo Iniziale"
       
      Screenshot:
      Non servono
       
      Script:
       
       
       
      Bug o Conflitti Noti:
      Nessuno
       
      [/b]Note dell'autore:[/b]
      Condividetelo, usatelo nei vostri progetti free o commerciali,l'importante è creditare l'autore.
    • Da Ally
      Nome Script: Text Cache
      Versione: 1.0
      Autore/i: Mithran
      Link post originale: Link
       
      Informazioni:
      Il VXAce ha portato nuove opzioni di personallizzazione delle scritte e con essi na marea di bug che rovinano la bellezza delle window. Questo script risolve tutti i bug portando le vostre scritte al loro vero splendore... Quindi ogni progetto dovrebbe averlo.
       
      Istruzioni:
      Copiatelo sotto Materials e sopra Main.
       
      Script:
       
       
      # Text Cache# by Mithran# posted at forums.rpgmakerweb.com# Instructions%Q(This script is a workaround for the Bitmap#draw_text issues in RPGMaker VX Ace.By default, there are several errors with Bitmap#draw_text in Ace.1. Text shrinking algorithm is overzealous. Text drawn to a rect given by its own text_size is reduced in size. This is both counterintuitive, and not the way it worked in previous versions (VX). 2. Text drawn to any rect wider than approx 640 pixels wraps around to the beginning of the line, overwriting previous text. This also causes center and right alignments to fail. This is both unnecessary and not how it worked in VX. 3. Text drawn character by character with non true-type fonts has awkward spacing. In addition, the text_size of a string of characters is not the same as the sum of the text_size of each character. This existed even in VX. 4. The first character of a Bitmap#draw_text command for certain letters on certain fonts is not drawn correctly. Since message window draws character by character, this can become a major issue. (example: Verdana 20 pt font) These errors can be demonstrated using my text draw debugger:http://pastebin.com/p55ukZP2 What this script does:1. Adds 2 pixels to any draw_text width, so text can be intuitively drawn to its own text_size rect. Offsets x coordinate where appropriate. If SIMPLE_FIX is set to true, only this fix will be enabled. 2. Adds a text cache. Instead of drawing text directly when called, a unique bitmap is created for any potential text draw with buffers, drawn with extra space around it. The character is then copied whenever a text draw is attempted. Text Caching can be turned off by setting SIMPLE_FIX to true. Text Caching also has the following features: - Much faster processing than the original Bitmap#draw_text. Trades a small amount of memory to accomodate faster processing speed. The first time any letter is drawn takes approximately 3-4 times as long, subsquently, any time this same letter and font is drawn it is upwards of twice as fast. The longer the string drawn, the bigger the difference. - Accounts for a 3-length string when checking the size. This makes single characters drawn look more natural for the offending fonts. Does not work with: - Reduced size text. If text is squeezed due to not being given enough room to draw, text caching is bypassed in favor of the original method. This is due to the text squeezing algorithm reducing each character by a variable amount that can not be determined with text_size. Manually stretching or aligning this "squeezed" text looks completely awful, so for now, this will have to stay like this. The exception to this is if the text has "just enough" room to draw, it will be given the two extra pixels rather than squeezing it. - If text extends beyond MAX_DRAW_WIDTH, text caching will be forced. This disables the "squeeze" effect. Using the default method means the text would draw over itself anyway, so this is the lesser of two evils. Changelog:v 1.01 Fixed crash error when using F12 to reset. (Thanks Archiea_Nessiah)v 1.0Official release.)# class Bitmap TEXT_TOP_BUFFER = 2 TEXT_SIDE_BUFFER = 8 # buffer in pixels to draw text away from # the edge of the bitmap, to prevent certain characters from being cut off SIMPLE_FIX = false # just adds the two pixels to prevent unnecessary squeeze MAX_TEXT_DRAW_WIDTH = 640 # tests have shown the draw fails at around 640px # if nil, no max width NO_FIX = false # completely disables the fix, for testing comparison alias draw_text_vxa draw_text def draw_text(*args) return draw_text_vxa(*args) if NO_FIX if args[0].is_a?(Rect) rect = args[0] x, y, width, height = rect.x, rect.y, rect.width, rect.height text = args[1].to_s.clone || "" align = args[2] || 0 else x, y, width, height = *args[0..3] text = args[4].to_s.clone || "" align = args[5] || 0 end text_rect = self.text_size(text) text_width = text_rect.width text_height = text_rect.height squeeze = text_width > width if SIMPLE_FIX or (squeeze and (MAX_TEXT_DRAW_WIDTH and width <= MAX_TEXT_DRAW_WIDTH)) x -= align # shift one pixels to the left if centering # two if right right justified # to offset the extra width given return draw_text_vxa(x, y, width + 2, height, text, align) else # TextCache.canvas(font) # passing the font slows this down extremly, changed it to later fontkey = self.font.to_a case align when 1; x += (width - text_width) / 2 when 2; x += width - text_width end y += (height - text_height) / 2 # horizontal center buf = -TEXT_SIDE_BUFFER text.each_char { |char| letter = TextCache.letters(fontkey, char) draw_text_vxa(x + buf, y, letter.rect.width + 2, letter.height, char) if SIMPLE_FIX # swap with original method for debugging and simple fix self.blt(x + buf, y, letter, letter.rect) unless SIMPLE_FIX buf += letter.rect.width - TEXT_SIDE_BUFFER * 2 } end endendmodule TextCache BUFFER_DRAW = 300 # for drawing characters, to make sure there is enough room def self.canvas(font = nil) @canvas = Bitmap.new(32, 32) if @canvas.nil? || @canvas.disposed? #@canvas.font = font if font and font != @canvas.font @canvas end def self.letters(font, char) @cache ||= {} key = font + [char] if include?(key) return @cache[key] elsif char.empty? return empty_bitmap else return new_letter(font, char) end end def self.empty_bitmap # not used, added for completness in case the cache is accessed directly @cache[:empty] = Bitmap.new(32, 32) unless include?(:empty) @cache[:empty] end def self.new_letter(fontary, char) font = create_font(fontary) # get the font canvas.font = font rect = canvas.text_size(char * 3) # get size of character between two other characters (for better kerning) b = Bitmap.new((rect.width / 3) + Bitmap::TEXT_SIDE_BUFFER * 2, rect.height) # create bitmap just big enough for one character b.font = font # get the font b.draw_text_vxa(rect.x - b.text_size(" ").width + Bitmap::TEXT_SIDE_BUFFER, rect.y - Bitmap::TEXT_TOP_BUFFER, BUFFER_DRAW, rect.height + Bitmap::TEXT_TOP_BUFFER * 2, " #{char} ", 0) # draw blank spaces before and after character, fix for cutting off the # first pixel using draw_text key = fontary + [char] @cache[key] = b end def self.create_font(fontary) font = Font.new(*fontary[0..1]) font.bold = fontary[2] font.italic = fontary[3] font.outline = fontary[4] font.shadow = fontary[5] font.color.set(*fontary[6..9]) font.out_color.set(*fontary[10..13]) font end def self.include?(key) @cache[key] && !@cache[key].disposed? end def self.clear @cache ||= {} @cache.clear GC.start end endclass Font # font's instance variables are not reflective, so this has to be defined explicitly def to_a [name, size, bold, italic, outline, shadow, color.red, color.green, color.blue, color.alpha, out_color.red, out_color.green, out_color.blue, out_color.alpha] end end Incompatibilità:N/D
    • Da Ally
      Nome Script: Picture Bug Fix
      Versione: Fix Bug
      Autore/i: Raizen884, Johnbolton, Gab!
       
      Informazioni:
      Quando una picture viene cancellata, gli script di rmvxace, mantengono un leggero ritardo di eliminazione di queste.
      La cosa non è percepibile con poche immagini, ma se ne usate ad esempio una decina, la cosa si noterà con freeze e lag.
      Per questo è stato creato questo piccolisismo script che fixerà questo piccolo (ma a quanto pare fastidioso), bug ^^
       
      Pinno il topic per lasciarlo in evidenza
       
      Istruzioni:
      Inserite lo script sotto Material.
       
      Script:
       
       
      #=======================================================# Picture Bug Fix# Author : Raizen884# Creditss : JohnBolton, Gab!# The script will correct a fatal bug caused by image deleting,# the more images deleted caused a constant freeze and lag# to the game.#=======================================================# It is better for this script to go over every new script added# to the scripts, and below all the original RMVXA scripts#=======================================================class Sprite_Picture < Sprite def update super if @picture.name != "" update_bitmap update_origin update_position update_zoom update_other else self.bitmap.dispose if self.bitmap != nil end endend
    • Da Ally
      Nome Script: Fix Animazioni
      Versione: 1.0
      Autore/i: FenixFyreX

      Informazioni:
      Se prima le animazioni su mappa venivano create in un punto preciso della mappa attraverso @animation_ox e @animation_oy, con questo script si aggiornano le variabili per poter muovere le animazioni.

      Istruzioni:
      Lo script deve stare sopra Main, ma SOTTO TUTTI gli altri Script che avete nel progetto.

      Script:


      class Sprite_Base   alias update_animation_oxy update_animation unless $@   def update_animation(*args,&block)     if @animation.position == 3       if viewport == nil         @animation_ox = 544 / 2         @animation_oy = 416 / 2       else         @animation_ox = viewport.rect.width / 2         @animation_oy = viewport.rect.height / 2       end     else       @animation_ox = x - ox + width / 2       @animation_oy = y - oy + height / 2       if @animation.position == 0         @animation_oy -= height / 2       elsif @animation.position == 2         @animation_oy += height / 2       end     end     update_animation_oxy(*args,&block)   end end
×